summaryrefslogtreecommitdiffstats
path: root/connectivity
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-15 05:54:39 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-15 05:54:39 +0000
commit267c6f2ac71f92999e969232431ba04678e7437e (patch)
tree358c9467650e1d0a1d7227a21dac2e3d08b622b2 /connectivity
parentInitial commit. (diff)
downloadlibreoffice-267c6f2ac71f92999e969232431ba04678e7437e.tar.xz
libreoffice-267c6f2ac71f92999e969232431ba04678e7437e.zip
Adding upstream version 4:24.2.0.upstream/4%24.2.0
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'connectivity')
-rw-r--r--connectivity/AllLangMoTarget_cnr.mk13
-rw-r--r--connectivity/Configuration_ado.mk20
-rw-r--r--connectivity/Configuration_calc.mk20
-rw-r--r--connectivity/Configuration_dbase.mk20
-rw-r--r--connectivity/Configuration_evoab.mk20
-rw-r--r--connectivity/Configuration_firebird.mk20
-rw-r--r--connectivity/Configuration_flat.mk20
-rw-r--r--connectivity/Configuration_hsqldb.mk20
-rw-r--r--connectivity/Configuration_jdbc.mk20
-rw-r--r--connectivity/Configuration_macab.mk20
-rw-r--r--connectivity/Configuration_mysql.mk20
-rw-r--r--connectivity/Configuration_mysql_jdbc.mk20
-rw-r--r--connectivity/Configuration_odbc.mk20
-rw-r--r--connectivity/Configuration_postgresql.mk20
-rw-r--r--connectivity/Configuration_writer.mk20
-rw-r--r--connectivity/CppunitTest_connectivity_ado.mk69
-rw-r--r--connectivity/CppunitTest_connectivity_commontools.mk42
-rw-r--r--connectivity/CppunitTest_connectivity_mysql_test.mk66
-rw-r--r--connectivity/CppunitTest_connectivity_sharedresources.mk44
-rw-r--r--connectivity/IwyuFilter_connectivity.yaml81
-rw-r--r--connectivity/Jar_ConnectivityTools.mk42
-rw-r--r--connectivity/Jar_sdbc_hsqldb.mk37
-rw-r--r--connectivity/JunitTest_complex.mk51
-rw-r--r--connectivity/Library_ado.mk85
-rw-r--r--connectivity/Library_calc.mk50
-rw-r--r--connectivity/Library_dbase.mk61
-rw-r--r--connectivity/Library_dbpool2.mk43
-rw-r--r--connectivity/Library_dbtools.mk127
-rw-r--r--connectivity/Library_evoab.mk59
-rw-r--r--connectivity/Library_file.mk71
-rw-r--r--connectivity/Library_firebird_sdbc.mk68
-rw-r--r--connectivity/Library_flat.mk55
-rw-r--r--connectivity/Library_hsqldb.mk61
-rw-r--r--connectivity/Library_jdbc.mk76
-rw-r--r--connectivity/Library_macab1.mk40
-rw-r--r--connectivity/Library_macabdrv1.mk58
-rw-r--r--connectivity/Library_mozbootstrap.mk35
-rw-r--r--connectivity/Library_mysql_jdbc.mk48
-rw-r--r--connectivity/Library_mysqlc.mk78
-rw-r--r--connectivity/Library_odbc.mk61
-rw-r--r--connectivity/Library_postgresql-sdbc-impl.mk105
-rw-r--r--connectivity/Library_postgresql-sdbc.mk34
-rw-r--r--connectivity/Library_sdbc2.mk38
-rw-r--r--connectivity/Library_writer.mk48
-rw-r--r--connectivity/Makefile7
-rw-r--r--connectivity/Module_connectivity.mk136
-rw-r--r--connectivity/Package_postgresql-sdbc.mk12
-rw-r--r--connectivity/README.md66
-rw-r--r--connectivity/Rdb_postgresql-sdbc.mk12
-rw-r--r--connectivity/com/sun/star/sdbcx/comp/hsqldb/NativeInputStreamHelper.java62
-rw-r--r--connectivity/com/sun/star/sdbcx/comp/hsqldb/NativeLibraries.java71
-rw-r--r--connectivity/com/sun/star/sdbcx/comp/hsqldb/NativeOutputStreamHelper.java60
-rw-r--r--connectivity/com/sun/star/sdbcx/comp/hsqldb/NativeStorageAccess.java62
-rw-r--r--connectivity/com/sun/star/sdbcx/comp/hsqldb/StorageAccess.java126
-rw-r--r--connectivity/com/sun/star/sdbcx/comp/hsqldb/StorageFileAccess.java90
-rw-r--r--connectivity/com/sun/star/sdbcx/comp/hsqldb/StorageNativeInputStream.java34
-rw-r--r--connectivity/com/sun/star/sdbcx/comp/hsqldb/StorageNativeOutputStream.java145
-rw-r--r--connectivity/inc/ParameterCont.hxx48
-rw-r--r--connectivity/inc/SQLStatementHelper.hxx43
-rw-r--r--connectivity/inc/TIndex.hxx45
-rw-r--r--connectivity/inc/TIndexColumns.hxx40
-rw-r--r--connectivity/inc/TKey.hxx43
-rw-r--r--connectivity/inc/TKeyColumns.hxx40
-rw-r--r--connectivity/inc/bitmaps.hlst14
-rw-r--r--connectivity/inc/pch/precompiled_ado.cxx12
-rw-r--r--connectivity/inc/pch/precompiled_ado.hxx114
-rw-r--r--connectivity/inc/pch/precompiled_calc.cxx12
-rw-r--r--connectivity/inc/pch/precompiled_calc.hxx76
-rw-r--r--connectivity/inc/pch/precompiled_dbase.cxx12
-rw-r--r--connectivity/inc/pch/precompiled_dbase.hxx231
-rw-r--r--connectivity/inc/pch/precompiled_dbpool2.cxx12
-rw-r--r--connectivity/inc/pch/precompiled_dbpool2.hxx93
-rw-r--r--connectivity/inc/pch/precompiled_dbtools.cxx12
-rw-r--r--connectivity/inc/pch/precompiled_dbtools.hxx214
-rw-r--r--connectivity/inc/pch/precompiled_file.cxx12
-rw-r--r--connectivity/inc/pch/precompiled_file.hxx225
-rw-r--r--connectivity/inc/pch/precompiled_firebird_sdbc.cxx12
-rw-r--r--connectivity/inc/pch/precompiled_firebird_sdbc.hxx75
-rw-r--r--connectivity/inc/pch/precompiled_flat.cxx12
-rw-r--r--connectivity/inc/pch/precompiled_flat.hxx207
-rw-r--r--connectivity/inc/pch/precompiled_mysql_jdbc.cxx12
-rw-r--r--connectivity/inc/pch/precompiled_mysql_jdbc.hxx62
-rw-r--r--connectivity/inc/pch/precompiled_odbc.cxx12
-rw-r--r--connectivity/inc/pch/precompiled_odbc.hxx90
-rw-r--r--connectivity/inc/pch/precompiled_postgresql-sdbc-impl.cxx12
-rw-r--r--connectivity/inc/pch/precompiled_postgresql-sdbc-impl.hxx61
-rw-r--r--connectivity/inc/sdbcx/VCatalog.hxx116
-rw-r--r--connectivity/inc/sdbcx/VGroup.hxx95
-rw-r--r--connectivity/inc/sdbcx/VIndex.hxx98
-rw-r--r--connectivity/inc/sdbcx/VIndexColumn.hxx58
-rw-r--r--connectivity/inc/sdbcx/VKey.hxx109
-rw-r--r--connectivity/inc/sdbcx/VKeyColumn.hxx59
-rw-r--r--connectivity/inc/sdbcx/VTypeDef.hxx34
-rw-r--r--connectivity/inc/sdbcx/VUser.hxx96
-rw-r--r--connectivity/inc/strings.hrc129
-rw-r--r--connectivity/inc/strings.hxx76
-rw-r--r--connectivity/org/hsqldb/lib/FileSystemRuntimeException.java38
-rw-r--r--connectivity/qa/complex/connectivity/DBaseDriverTest.java70
-rw-r--r--connectivity/qa/complex/connectivity/FlatFileAccess.java245
-rw-r--r--connectivity/qa/complex/connectivity/HsqlDriverTest.java145
-rw-r--r--connectivity/qa/complex/connectivity/JdbcLongVarCharTest.java125
-rw-r--r--connectivity/qa/complex/connectivity/SubTestCase.java41
-rw-r--r--connectivity/qa/complex/connectivity/TestCase.java27
-rw-r--r--connectivity/qa/complex/connectivity/dbase/DBaseDateFunctions.java296
-rw-r--r--connectivity/qa/complex/connectivity/dbase/DBaseNumericFunctions.java388
-rw-r--r--connectivity/qa/complex/connectivity/dbase/DBaseSqlTests.java80
-rw-r--r--connectivity/qa/complex/connectivity/dbase/DBaseStringFunctions.java310
-rw-r--r--connectivity/qa/complex/connectivity/hsqldb/TestCacheSize.java591
-rw-r--r--connectivity/qa/connectivity/ado/DriverTest.cxx141
-rw-r--r--connectivity/qa/connectivity/ado/TS001018407.mdbbin0 -> 2789376 bytes
-rw-r--r--connectivity/qa/connectivity/commontools/FValue_test.cxx366
-rw-r--r--connectivity/qa/connectivity/mysql/mysql.cxx502
-rw-r--r--connectivity/qa/connectivity/resource/sharedresources_test.cxx106
-rw-r--r--connectivity/qa/connectivity/tools/AbstractDatabase.java207
-rw-r--r--connectivity/qa/connectivity/tools/CRMDatabase.java277
-rw-r--r--connectivity/qa/connectivity/tools/CsvDatabase.java31
-rw-r--r--connectivity/qa/connectivity/tools/DataSource.java150
-rw-r--r--connectivity/qa/connectivity/tools/DatabaseAccess.java50
-rw-r--r--connectivity/qa/connectivity/tools/DbaseDatabase.java32
-rw-r--r--connectivity/qa/connectivity/tools/FlatFileDatabase.java74
-rw-r--r--connectivity/qa/connectivity/tools/HsqlColumnDescriptor.java75
-rw-r--r--connectivity/qa/connectivity/tools/HsqlDatabase.java202
-rw-r--r--connectivity/qa/connectivity/tools/HsqlTableDescriptor.java93
-rw-r--r--connectivity/qa/connectivity/tools/QueryDefinition.java49
-rw-r--r--connectivity/qa/connectivity/tools/RowSet.java288
-rw-r--r--connectivity/qa/connectivity/tools/sdb/Connection.java80
-rw-r--r--connectivity/qa/scenarios.sce21
-rw-r--r--connectivity/registry/README25
-rw-r--r--connectivity/registry/ado/org/openoffice/Office/DataAccess/Drivers.xcu369
-rw-r--r--connectivity/registry/calc/org/openoffice/Office/DataAccess/Drivers.xcu61
-rw-r--r--connectivity/registry/dbase/org/openoffice/Office/DataAccess/Drivers.xcu101
-rw-r--r--connectivity/registry/evoab2/org/openoffice/Office/DataAccess/Drivers.xcu88
-rw-r--r--connectivity/registry/firebird/org/openoffice/Office/DataAccess/Drivers.xcu135
-rw-r--r--connectivity/registry/flat/org/openoffice/Office/DataAccess/Drivers.xcu116
-rw-r--r--connectivity/registry/hsqldb/org/openoffice/Office/DataAccess/Drivers.xcu103
-rw-r--r--connectivity/registry/jdbc/org/openoffice/Office/DataAccess/Drivers.xcu297
-rw-r--r--connectivity/registry/macab/org/openoffice/Office/DataAccess/Drivers.xcu44
-rw-r--r--connectivity/registry/mysql_jdbc/org/openoffice/Office/DataAccess/Drivers.xcu180
-rw-r--r--connectivity/registry/mysqlc/org/openoffice/Office/DataAccess/Drivers.xcu138
-rw-r--r--connectivity/registry/odbc/org/openoffice/Office/DataAccess/Drivers.xcu261
-rw-r--r--connectivity/registry/postgresql/org/openoffice/Office/DataAccess/Drivers.xcu94
-rw-r--r--connectivity/registry/writer/org/openoffice/Office/DataAccess/Drivers.xcu51
-rw-r--r--connectivity/source/commontools/AutoRetrievingBase.cxx52
-rw-r--r--connectivity/source/commontools/BlobHelper.cxx63
-rw-r--r--connectivity/source/commontools/CommonTools.cxx235
-rw-r--r--connectivity/source/commontools/ConnectionWrapper.cxx238
-rw-r--r--connectivity/source/commontools/DateConversion.cxx517
-rw-r--r--connectivity/source/commontools/DriversConfig.cxx249
-rw-r--r--connectivity/source/commontools/FDatabaseMetaDataResultSet.cxx839
-rw-r--r--connectivity/source/commontools/FDatabaseMetaDataResultSetMetaData.cxx357
-rw-r--r--connectivity/source/commontools/FValue.cxx2473
-rw-r--r--connectivity/source/commontools/ParameterSubstitution.cxx106
-rw-r--r--connectivity/source/commontools/RowFunctionParser.cxx442
-rw-r--r--connectivity/source/commontools/TColumnsHelper.cxx208
-rw-r--r--connectivity/source/commontools/TConnection.cxx85
-rw-r--r--connectivity/source/commontools/TDatabaseMetaDataBase.cxx329
-rw-r--r--connectivity/source/commontools/TIndex.cxx100
-rw-r--r--connectivity/source/commontools/TIndexColumns.cxx114
-rw-r--r--connectivity/source/commontools/TIndexes.cxx247
-rw-r--r--connectivity/source/commontools/TKey.cxx107
-rw-r--r--connectivity/source/commontools/TKeyColumns.cxx132
-rw-r--r--connectivity/source/commontools/TKeys.cxx307
-rw-r--r--connectivity/source/commontools/TPrivilegesResultSet.cxx140
-rw-r--r--connectivity/source/commontools/TSkipDeletedSet.cxx255
-rw-r--r--connectivity/source/commontools/TSortIndex.cxx152
-rw-r--r--connectivity/source/commontools/TTableHelper.cxx610
-rw-r--r--connectivity/source/commontools/conncleanup.cxx230
-rw-r--r--connectivity/source/commontools/dbcharset.cxx191
-rw-r--r--connectivity/source/commontools/dbconversion.cxx392
-rw-r--r--connectivity/source/commontools/dbexception.cxx485
-rw-r--r--connectivity/source/commontools/dbmetadata.cxx443
-rw-r--r--connectivity/source/commontools/dbtools.cxx2074
-rw-r--r--connectivity/source/commontools/dbtools2.cxx1018
-rw-r--r--connectivity/source/commontools/filtermanager.cxx254
-rw-r--r--connectivity/source/commontools/formattedcolumnvalue.cxx291
-rw-r--r--connectivity/source/commontools/parameters.cxx1212
-rw-r--r--connectivity/source/commontools/paramwrapper.cxx345
-rw-r--r--connectivity/source/commontools/predicateinput.cxx411
-rw-r--r--connectivity/source/commontools/propertyids.cxx104
-rw-r--r--connectivity/source/commontools/sqlerror.cxx295
-rw-r--r--connectivity/source/commontools/statementcomposer.cxx301
-rw-r--r--connectivity/source/commontools/warningscontainer.cxx110
-rw-r--r--connectivity/source/cpool/ZConnectionPool.cxx301
-rw-r--r--connectivity/source/cpool/ZConnectionPool.hxx147
-rw-r--r--connectivity/source/cpool/ZConnectionWrapper.cxx241
-rw-r--r--connectivity/source/cpool/ZConnectionWrapper.hxx77
-rw-r--r--connectivity/source/cpool/ZDriverWrapper.cxx114
-rw-r--r--connectivity/source/cpool/ZDriverWrapper.hxx73
-rw-r--r--connectivity/source/cpool/ZPoolCollection.cxx468
-rw-r--r--connectivity/source/cpool/ZPoolCollection.hxx133
-rw-r--r--connectivity/source/cpool/ZPooledConnection.cxx72
-rw-r--r--connectivity/source/cpool/ZPooledConnection.hxx58
-rw-r--r--connectivity/source/cpool/dbpool2.component26
-rw-r--r--connectivity/source/dbtools/dbtools.component30
-rw-r--r--connectivity/source/drivers/ado/ACallableStatement.cxx253
-rw-r--r--connectivity/source/drivers/ado/ACatalog.cxx115
-rw-r--r--connectivity/source/drivers/ado/AColumn.cxx234
-rw-r--r--connectivity/source/drivers/ado/AColumns.cxx125
-rw-r--r--connectivity/source/drivers/ado/AConnection.cxx568
-rw-r--r--connectivity/source/drivers/ado/ADatabaseMetaData.cxx1034
-rw-r--r--connectivity/source/drivers/ado/ADatabaseMetaDataImpl.cxx543
-rw-r--r--connectivity/source/drivers/ado/ADatabaseMetaDataResultSet.cxx1242
-rw-r--r--connectivity/source/drivers/ado/ADatabaseMetaDataResultSetMetaData.cxx210
-rw-r--r--connectivity/source/drivers/ado/ADriver.cxx250
-rw-r--r--connectivity/source/drivers/ado/AGroup.cxx127
-rw-r--r--connectivity/source/drivers/ado/AGroups.cxx76
-rw-r--r--connectivity/source/drivers/ado/AIndex.cxx107
-rw-r--r--connectivity/source/drivers/ado/AIndexes.cxx82
-rw-r--r--connectivity/source/drivers/ado/AKey.cxx120
-rw-r--r--connectivity/source/drivers/ado/AKeys.cxx97
-rw-r--r--connectivity/source/drivers/ado/APreparedStatement.cxx455
-rw-r--r--connectivity/source/drivers/ado/AResultSet.cxx1158
-rw-r--r--connectivity/source/drivers/ado/AResultSetMetaData.cxx247
-rw-r--r--connectivity/source/drivers/ado/AStatement.cxx867
-rw-r--r--connectivity/source/drivers/ado/ATable.cxx216
-rw-r--r--connectivity/source/drivers/ado/ATables.cxx103
-rw-r--r--connectivity/source/drivers/ado/AUser.cxx175
-rw-r--r--connectivity/source/drivers/ado/AUsers.cxx77
-rw-r--r--connectivity/source/drivers/ado/AView.cxx78
-rw-r--r--connectivity/source/drivers/ado/AViews.cxx97
-rw-r--r--connectivity/source/drivers/ado/Aolevariant.cxx687
-rw-r--r--connectivity/source/drivers/ado/Awrapado.cxx2009
-rw-r--r--connectivity/source/drivers/ado/ado.component27
-rw-r--r--connectivity/source/drivers/ado/adoimp.cxx325
-rw-r--r--connectivity/source/drivers/calc/CCatalog.cxx62
-rw-r--r--connectivity/source/drivers/calc/CConnection.cxx264
-rw-r--r--connectivity/source/drivers/calc/CDatabaseMetaData.cxx217
-rw-r--r--connectivity/source/drivers/calc/CDriver.cxx95
-rw-r--r--connectivity/source/drivers/calc/CTable.cxx638
-rw-r--r--connectivity/source/drivers/calc/CTables.cxx48
-rw-r--r--connectivity/source/drivers/calc/calc.component27
-rw-r--r--connectivity/source/drivers/component/CColumns.cxx44
-rw-r--r--connectivity/source/drivers/component/CDatabaseMetaData.cxx235
-rw-r--r--connectivity/source/drivers/component/CPreparedStatement.cxx34
-rw-r--r--connectivity/source/drivers/component/CResultSet.cxx172
-rw-r--r--connectivity/source/drivers/component/CStatement.cxx35
-rw-r--r--connectivity/source/drivers/component/CTable.cxx189
-rw-r--r--connectivity/source/drivers/dbase/DCatalog.cxx57
-rw-r--r--connectivity/source/drivers/dbase/DColumns.cxx77
-rw-r--r--connectivity/source/drivers/dbase/DConnection.cxx112
-rw-r--r--connectivity/source/drivers/dbase/DDatabaseMetaData.cxx381
-rw-r--r--connectivity/source/drivers/dbase/DDriver.cxx118
-rw-r--r--connectivity/source/drivers/dbase/DIndex.cxx591
-rw-r--r--connectivity/source/drivers/dbase/DIndexColumns.cxx82
-rw-r--r--connectivity/source/drivers/dbase/DIndexIter.cxx282
-rw-r--r--connectivity/source/drivers/dbase/DIndexes.cxx111
-rw-r--r--connectivity/source/drivers/dbase/DPreparedStatement.cxx35
-rw-r--r--connectivity/source/drivers/dbase/DResultSet.cxx211
-rw-r--r--connectivity/source/drivers/dbase/DStatement.cxx35
-rw-r--r--connectivity/source/drivers/dbase/DTable.cxx2747
-rw-r--r--connectivity/source/drivers/dbase/DTables.cxx127
-rw-r--r--connectivity/source/drivers/dbase/dbase.component27
-rw-r--r--connectivity/source/drivers/dbase/dindexnode.cxx1047
-rw-r--r--connectivity/source/drivers/evoab2/EApi.cxx135
-rw-r--r--connectivity/source/drivers/evoab2/EApi.h160
-rw-r--r--connectivity/source/drivers/evoab2/NCatalog.cxx86
-rw-r--r--connectivity/source/drivers/evoab2/NCatalog.hxx43
-rw-r--r--connectivity/source/drivers/evoab2/NColumns.cxx87
-rw-r--r--connectivity/source/drivers/evoab2/NColumns.hxx44
-rw-r--r--connectivity/source/drivers/evoab2/NConnection.cxx242
-rw-r--r--connectivity/source/drivers/evoab2/NConnection.hxx105
-rw-r--r--connectivity/source/drivers/evoab2/NDatabaseMetaData.cxx1157
-rw-r--r--connectivity/source/drivers/evoab2/NDatabaseMetaData.hxx218
-rw-r--r--connectivity/source/drivers/evoab2/NDriver.cxx157
-rw-r--r--connectivity/source/drivers/evoab2/NDriver.hxx74
-rw-r--r--connectivity/source/drivers/evoab2/NPreparedStatement.cxx319
-rw-r--r--connectivity/source/drivers/evoab2/NPreparedStatement.hxx108
-rw-r--r--connectivity/source/drivers/evoab2/NResultSet.cxx1036
-rw-r--r--connectivity/source/drivers/evoab2/NResultSet.hxx182
-rw-r--r--connectivity/source/drivers/evoab2/NResultSetMetaData.cxx175
-rw-r--r--connectivity/source/drivers/evoab2/NResultSetMetaData.hxx77
-rw-r--r--connectivity/source/drivers/evoab2/NStatement.cxx682
-rw-r--r--connectivity/source/drivers/evoab2/NStatement.hxx273
-rw-r--r--connectivity/source/drivers/evoab2/NTable.cxx76
-rw-r--r--connectivity/source/drivers/evoab2/NTable.hxx53
-rw-r--r--connectivity/source/drivers/evoab2/NTables.cxx79
-rw-r--r--connectivity/source/drivers/evoab2/NTables.hxx44
-rw-r--r--connectivity/source/drivers/evoab2/evoab.component26
-rw-r--r--connectivity/source/drivers/file/FCatalog.cxx103
-rw-r--r--connectivity/source/drivers/file/FColumns.cxx80
-rw-r--r--connectivity/source/drivers/file/FConnection.cxx428
-rw-r--r--connectivity/source/drivers/file/FDatabaseMetaData.cxx1050
-rw-r--r--connectivity/source/drivers/file/FDateFunctions.cxx278
-rw-r--r--connectivity/source/drivers/file/FDriver.cxx206
-rw-r--r--connectivity/source/drivers/file/FNoException.cxx102
-rw-r--r--connectivity/source/drivers/file/FNumericFunctions.cxx242
-rw-r--r--connectivity/source/drivers/file/FPreparedStatement.cxx555
-rw-r--r--connectivity/source/drivers/file/FResultSet.cxx1579
-rw-r--r--connectivity/source/drivers/file/FResultSetMetaData.cxx189
-rw-r--r--connectivity/source/drivers/file/FStatement.cxx712
-rw-r--r--connectivity/source/drivers/file/FStringFunctions.cxx226
-rw-r--r--connectivity/source/drivers/file/FTable.cxx171
-rw-r--r--connectivity/source/drivers/file/FTables.cxx54
-rw-r--r--connectivity/source/drivers/file/fanalyzer.cxx207
-rw-r--r--connectivity/source/drivers/file/fcode.cxx373
-rw-r--r--connectivity/source/drivers/file/fcomp.cxx886
-rw-r--r--connectivity/source/drivers/file/quotedstring.cxx146
-rw-r--r--connectivity/source/drivers/firebird/Blob.cxx391
-rw-r--r--connectivity/source/drivers/firebird/Blob.hxx100
-rw-r--r--connectivity/source/drivers/firebird/Catalog.cxx105
-rw-r--r--connectivity/source/drivers/firebird/Catalog.hxx40
-rw-r--r--connectivity/source/drivers/firebird/Clob.cxx141
-rw-r--r--connectivity/source/drivers/firebird/Clob.hxx64
-rw-r--r--connectivity/source/drivers/firebird/Column.cxx51
-rw-r--r--connectivity/source/drivers/firebird/Column.hxx32
-rw-r--r--connectivity/source/drivers/firebird/Columns.cxx41
-rw-r--r--connectivity/source/drivers/firebird/Columns.hxx30
-rw-r--r--connectivity/source/drivers/firebird/Connection.cxx979
-rw-r--r--connectivity/source/drivers/firebird/Connection.hxx247
-rw-r--r--connectivity/source/drivers/firebird/DatabaseMetaData.cxx1803
-rw-r--r--connectivity/source/drivers/firebird/DatabaseMetaData.hxx205
-rw-r--r--connectivity/source/drivers/firebird/Driver.cxx228
-rw-r--r--connectivity/source/drivers/firebird/Driver.hxx90
-rw-r--r--connectivity/source/drivers/firebird/Indexes.cxx33
-rw-r--r--connectivity/source/drivers/firebird/Indexes.hxx39
-rw-r--r--connectivity/source/drivers/firebird/Keys.cxx54
-rw-r--r--connectivity/source/drivers/firebird/Keys.hxx36
-rw-r--r--connectivity/source/drivers/firebird/PreparedStatement.cxx1058
-rw-r--r--connectivity/source/drivers/firebird/PreparedStatement.hxx152
-rw-r--r--connectivity/source/drivers/firebird/ResultSet.cxx926
-rw-r--r--connectivity/source/drivers/firebird/ResultSet.hxx216
-rw-r--r--connectivity/source/drivers/firebird/ResultSetMetaData.cxx301
-rw-r--r--connectivity/source/drivers/firebird/ResultSetMetaData.hxx80
-rw-r--r--connectivity/source/drivers/firebird/Statement.cxx176
-rw-r--r--connectivity/source/drivers/firebird/Statement.hxx84
-rw-r--r--connectivity/source/drivers/firebird/StatementCommonBase.cxx486
-rw-r--r--connectivity/source/drivers/firebird/StatementCommonBase.hxx134
-rw-r--r--connectivity/source/drivers/firebird/SubComponent.hxx111
-rw-r--r--connectivity/source/drivers/firebird/Table.cxx232
-rw-r--r--connectivity/source/drivers/firebird/Table.hxx81
-rw-r--r--connectivity/source/drivers/firebird/Tables.cxx226
-rw-r--r--connectivity/source/drivers/firebird/Tables.hxx61
-rw-r--r--connectivity/source/drivers/firebird/User.cxx53
-rw-r--r--connectivity/source/drivers/firebird/User.hxx46
-rw-r--r--connectivity/source/drivers/firebird/Users.cxx78
-rw-r--r--connectivity/source/drivers/firebird/Users.hxx53
-rw-r--r--connectivity/source/drivers/firebird/Util.cxx424
-rw-r--r--connectivity/source/drivers/firebird/Util.hxx126
-rw-r--r--connectivity/source/drivers/firebird/View.cxx85
-rw-r--r--connectivity/source/drivers/firebird/View.hxx60
-rw-r--r--connectivity/source/drivers/firebird/Views.cxx112
-rw-r--r--connectivity/source/drivers/firebird/Views.hxx42
-rw-r--r--connectivity/source/drivers/firebird/firebird_sdbc.component19
-rw-r--r--connectivity/source/drivers/flat/ECatalog.cxx58
-rw-r--r--connectivity/source/drivers/flat/EColumns.cxx44
-rw-r--r--connectivity/source/drivers/flat/EConnection.cxx176
-rw-r--r--connectivity/source/drivers/flat/EDatabaseMetaData.cxx242
-rw-r--r--connectivity/source/drivers/flat/EDriver.cxx135
-rw-r--r--connectivity/source/drivers/flat/EPreparedStatement.cxx35
-rw-r--r--connectivity/source/drivers/flat/EResultSet.cxx169
-rw-r--r--connectivity/source/drivers/flat/EStatement.cxx34
-rw-r--r--connectivity/source/drivers/flat/ETable.cxx947
-rw-r--r--connectivity/source/drivers/flat/ETables.cxx44
-rw-r--r--connectivity/source/drivers/flat/flat.component27
-rw-r--r--connectivity/source/drivers/hsqldb/HCatalog.cxx148
-rw-r--r--connectivity/source/drivers/hsqldb/HColumns.cxx76
-rw-r--r--connectivity/source/drivers/hsqldb/HConnection.cxx336
-rw-r--r--connectivity/source/drivers/hsqldb/HDriver.cxx892
-rw-r--r--connectivity/source/drivers/hsqldb/HStorageAccess.cxx516
-rw-r--r--connectivity/source/drivers/hsqldb/HStorageMap.cxx361
-rw-r--r--connectivity/source/drivers/hsqldb/HTable.cxx373
-rw-r--r--connectivity/source/drivers/hsqldb/HTables.cxx176
-rw-r--r--connectivity/source/drivers/hsqldb/HTerminateListener.cxx45
-rw-r--r--connectivity/source/drivers/hsqldb/HTerminateListener.hxx46
-rw-r--r--connectivity/source/drivers/hsqldb/HTools.cxx53
-rw-r--r--connectivity/source/drivers/hsqldb/HUser.cxx329
-rw-r--r--connectivity/source/drivers/hsqldb/HUsers.cxx99
-rw-r--r--connectivity/source/drivers/hsqldb/HView.cxx216
-rw-r--r--connectivity/source/drivers/hsqldb/HViews.cxx148
-rw-r--r--connectivity/source/drivers/hsqldb/StorageFileAccess.cxx167
-rw-r--r--connectivity/source/drivers/hsqldb/StorageNativeInputStream.cxx292
-rw-r--r--connectivity/source/drivers/hsqldb/StorageNativeOutputStream.cxx195
-rw-r--r--connectivity/source/drivers/hsqldb/accesslog.cxx78
-rw-r--r--connectivity/source/drivers/hsqldb/accesslog.hxx135
-rw-r--r--connectivity/source/drivers/hsqldb/hsqldb.component27
-rw-r--r--connectivity/source/drivers/jdbc/Array.cxx132
-rw-r--r--connectivity/source/drivers/jdbc/Blob.cxx144
-rw-r--r--connectivity/source/drivers/jdbc/Boolean.cxx38
-rw-r--r--connectivity/source/drivers/jdbc/CallableStatement.cxx354
-rw-r--r--connectivity/source/drivers/jdbc/Class.cxx70
-rw-r--r--connectivity/source/drivers/jdbc/Clob.cxx132
-rw-r--r--connectivity/source/drivers/jdbc/ConnectionLog.cxx110
-rw-r--r--connectivity/source/drivers/jdbc/ContextClassLoader.cxx111
-rw-r--r--connectivity/source/drivers/jdbc/DatabaseMetaData.cxx1463
-rw-r--r--connectivity/source/drivers/jdbc/Date.cxx38
-rw-r--r--connectivity/source/drivers/jdbc/DriverPropertyInfo.cxx40
-rw-r--r--connectivity/source/drivers/jdbc/Exception.cxx37
-rw-r--r--connectivity/source/drivers/jdbc/InputStream.cxx113
-rw-r--r--connectivity/source/drivers/jdbc/JBigDecimal.cxx79
-rw-r--r--connectivity/source/drivers/jdbc/JConnection.cxx800
-rw-r--r--connectivity/source/drivers/jdbc/JDriver.cxx231
-rw-r--r--connectivity/source/drivers/jdbc/JStatement.cxx864
-rw-r--r--connectivity/source/drivers/jdbc/Object.cxx481
-rw-r--r--connectivity/source/drivers/jdbc/PreparedStatement.cxx697
-rw-r--r--connectivity/source/drivers/jdbc/Reader.cxx178
-rw-r--r--connectivity/source/drivers/jdbc/Ref.cxx48
-rw-r--r--connectivity/source/drivers/jdbc/ResultSet.cxx1013
-rw-r--r--connectivity/source/drivers/jdbc/ResultSetMetaData.cxx200
-rw-r--r--connectivity/source/drivers/jdbc/SQLException.cxx87
-rw-r--r--connectivity/source/drivers/jdbc/SQLWarning.cxx37
-rw-r--r--connectivity/source/drivers/jdbc/String.cxx47
-rw-r--r--connectivity/source/drivers/jdbc/Throwable.cxx59
-rw-r--r--connectivity/source/drivers/jdbc/Timestamp.cxx189
-rw-r--r--connectivity/source/drivers/jdbc/jdbc.component37
-rw-r--r--connectivity/source/drivers/jdbc/tools.cxx261
-rw-r--r--connectivity/source/drivers/macab/MacabAddressBook.cxx249
-rw-r--r--connectivity/source/drivers/macab/MacabAddressBook.hxx60
-rw-r--r--connectivity/source/drivers/macab/MacabCatalog.cxx112
-rw-r--r--connectivity/source/drivers/macab/MacabCatalog.hxx51
-rw-r--r--connectivity/source/drivers/macab/MacabColumns.cxx94
-rw-r--r--connectivity/source/drivers/macab/MacabColumns.hxx42
-rw-r--r--connectivity/source/drivers/macab/MacabConnection.cxx316
-rw-r--r--connectivity/source/drivers/macab/MacabConnection.hxx110
-rw-r--r--connectivity/source/drivers/macab/MacabDatabaseMetaData.cxx1073
-rw-r--r--connectivity/source/drivers/macab/MacabDatabaseMetaData.hxx195
-rw-r--r--connectivity/source/drivers/macab/MacabDriver.cxx310
-rw-r--r--connectivity/source/drivers/macab/MacabDriver.hxx161
-rw-r--r--connectivity/source/drivers/macab/MacabGroup.cxx93
-rw-r--r--connectivity/source/drivers/macab/MacabGroup.hxx38
-rw-r--r--connectivity/source/drivers/macab/MacabHeader.cxx330
-rw-r--r--connectivity/source/drivers/macab/MacabHeader.hxx61
-rw-r--r--connectivity/source/drivers/macab/MacabPreparedStatement.cxx343
-rw-r--r--connectivity/source/drivers/macab/MacabPreparedStatement.hxx111
-rw-r--r--connectivity/source/drivers/macab/MacabRecord.cxx336
-rw-r--r--connectivity/source/drivers/macab/MacabRecord.hxx71
-rw-r--r--connectivity/source/drivers/macab/MacabRecords.cxx1160
-rw-r--r--connectivity/source/drivers/macab/MacabRecords.hxx125
-rw-r--r--connectivity/source/drivers/macab/MacabResultSet.cxx1094
-rw-r--r--connectivity/source/drivers/macab/MacabResultSet.hxx213
-rw-r--r--connectivity/source/drivers/macab/MacabResultSetMetaData.cxx216
-rw-r--r--connectivity/source/drivers/macab/MacabResultSetMetaData.hxx80
-rw-r--r--connectivity/source/drivers/macab/MacabStatement.cxx631
-rw-r--r--connectivity/source/drivers/macab/MacabStatement.hxx169
-rw-r--r--connectivity/source/drivers/macab/MacabTable.cxx86
-rw-r--r--connectivity/source/drivers/macab/MacabTable.hxx54
-rw-r--r--connectivity/source/drivers/macab/MacabTables.cxx80
-rw-r--r--connectivity/source/drivers/macab/MacabTables.hxx49
-rw-r--r--connectivity/source/drivers/macab/macab1.component26
-rw-r--r--connectivity/source/drivers/macab/macabcondition.cxx244
-rw-r--r--connectivity/source/drivers/macab/macabcondition.hxx165
-rw-r--r--connectivity/source/drivers/macab/macaborder.cxx75
-rw-r--r--connectivity/source/drivers/macab/macaborder.hxx64
-rw-r--r--connectivity/source/drivers/macab/macabutilities.hxx142
-rw-r--r--connectivity/source/drivers/mozab/bootstrap/MMozillaBootstrap.cxx136
-rw-r--r--connectivity/source/drivers/mozab/bootstrap/MMozillaBootstrap.hxx78
-rw-r--r--connectivity/source/drivers/mozab/bootstrap/MNSFolders.cxx159
-rw-r--r--connectivity/source/drivers/mozab/bootstrap/MNSFolders.hxx28
-rw-r--r--connectivity/source/drivers/mozab/bootstrap/MNSINIParser.cxx94
-rw-r--r--connectivity/source/drivers/mozab/bootstrap/MNSINIParser.hxx54
-rw-r--r--connectivity/source/drivers/mozab/bootstrap/MNSProfileDiscover.cxx212
-rw-r--r--connectivity/source/drivers/mozab/bootstrap/MNSProfileDiscover.hxx80
-rw-r--r--connectivity/source/drivers/mozab/bootstrap/README3
-rw-r--r--connectivity/source/drivers/mozab/bootstrap/mozbootstrap.component26
-rw-r--r--connectivity/source/drivers/mysql_jdbc/YCatalog.cxx132
-rw-r--r--connectivity/source/drivers/mysql_jdbc/YColumns.cxx72
-rw-r--r--connectivity/source/drivers/mysql_jdbc/YDriver.cxx416
-rw-r--r--connectivity/source/drivers/mysql_jdbc/YTable.cxx313
-rw-r--r--connectivity/source/drivers/mysql_jdbc/YTables.cxx208
-rw-r--r--connectivity/source/drivers/mysql_jdbc/YUser.cxx326
-rw-r--r--connectivity/source/drivers/mysql_jdbc/YUsers.cxx92
-rw-r--r--connectivity/source/drivers/mysql_jdbc/YViews.cxx138
-rw-r--r--connectivity/source/drivers/mysql_jdbc/mysql_jdbc.component27
-rw-r--r--connectivity/source/drivers/mysqlc/mysqlc.component15
-rw-r--r--connectivity/source/drivers/mysqlc/mysqlc_catalog.cxx93
-rw-r--r--connectivity/source/drivers/mysqlc/mysqlc_catalog.hxx38
-rw-r--r--connectivity/source/drivers/mysqlc/mysqlc_column.cxx45
-rw-r--r--connectivity/source/drivers/mysqlc/mysqlc_column.hxx32
-rw-r--r--connectivity/source/drivers/mysqlc/mysqlc_columns.cxx28
-rw-r--r--connectivity/source/drivers/mysqlc/mysqlc_columns.hxx29
-rw-r--r--connectivity/source/drivers/mysqlc/mysqlc_connection.cxx521
-rw-r--r--connectivity/source/drivers/mysqlc/mysqlc_connection.hxx190
-rw-r--r--connectivity/source/drivers/mysqlc/mysqlc_databasemetadata.cxx1057
-rw-r--r--connectivity/source/drivers/mysqlc/mysqlc_databasemetadata.hxx233
-rw-r--r--connectivity/source/drivers/mysqlc/mysqlc_driver.cxx148
-rw-r--r--connectivity/source/drivers/mysqlc/mysqlc_driver.hxx88
-rw-r--r--connectivity/source/drivers/mysqlc/mysqlc_general.cxx357
-rw-r--r--connectivity/source/drivers/mysqlc/mysqlc_general.hxx116
-rw-r--r--connectivity/source/drivers/mysqlc/mysqlc_indexes.cxx25
-rw-r--r--connectivity/source/drivers/mysqlc/mysqlc_indexes.hxx34
-rw-r--r--connectivity/source/drivers/mysqlc/mysqlc_keys.cxx19
-rw-r--r--connectivity/source/drivers/mysqlc/mysqlc_keys.hxx25
-rw-r--r--connectivity/source/drivers/mysqlc/mysqlc_prepared_resultset.cxx1127
-rw-r--r--connectivity/source/drivers/mysqlc/mysqlc_prepared_resultset.hxx251
-rw-r--r--connectivity/source/drivers/mysqlc/mysqlc_preparedstatement.cxx580
-rw-r--r--connectivity/source/drivers/mysqlc/mysqlc_preparedstatement.hxx155
-rw-r--r--connectivity/source/drivers/mysqlc/mysqlc_propertyids.hxx44
-rw-r--r--connectivity/source/drivers/mysqlc/mysqlc_resultset.cxx1111
-rw-r--r--connectivity/source/drivers/mysqlc/mysqlc_resultset.hxx273
-rw-r--r--connectivity/source/drivers/mysqlc/mysqlc_resultsetmetadata.cxx212
-rw-r--r--connectivity/source/drivers/mysqlc/mysqlc_resultsetmetadata.hxx99
-rw-r--r--connectivity/source/drivers/mysqlc/mysqlc_services.cxx110
-rw-r--r--connectivity/source/drivers/mysqlc/mysqlc_statement.cxx390
-rw-r--r--connectivity/source/drivers/mysqlc/mysqlc_statement.hxx173
-rw-r--r--connectivity/source/drivers/mysqlc/mysqlc_subcomponent.hxx138
-rw-r--r--connectivity/source/drivers/mysqlc/mysqlc_table.cxx167
-rw-r--r--connectivity/source/drivers/mysqlc/mysqlc_table.hxx69
-rw-r--r--connectivity/source/drivers/mysqlc/mysqlc_tables.cxx157
-rw-r--r--connectivity/source/drivers/mysqlc/mysqlc_tables.hxx57
-rw-r--r--connectivity/source/drivers/mysqlc/mysqlc_types.cxx700
-rw-r--r--connectivity/source/drivers/mysqlc/mysqlc_types.hxx45
-rw-r--r--connectivity/source/drivers/mysqlc/mysqlc_user.cxx211
-rw-r--r--connectivity/source/drivers/mysqlc/mysqlc_user.hxx71
-rw-r--r--connectivity/source/drivers/mysqlc/mysqlc_users.cxx95
-rw-r--r--connectivity/source/drivers/mysqlc/mysqlc_users.hxx43
-rw-r--r--connectivity/source/drivers/mysqlc/mysqlc_view.cxx98
-rw-r--r--connectivity/source/drivers/mysqlc/mysqlc_view.hxx72
-rw-r--r--connectivity/source/drivers/mysqlc/mysqlc_views.cxx113
-rw-r--r--connectivity/source/drivers/mysqlc/mysqlc_views.hxx50
-rw-r--r--connectivity/source/drivers/odbc/OConnection.cxx547
-rw-r--r--connectivity/source/drivers/odbc/ODatabaseMetaData.cxx1717
-rw-r--r--connectivity/source/drivers/odbc/ODatabaseMetaDataResultSet.cxx1330
-rw-r--r--connectivity/source/drivers/odbc/ODriver.cxx193
-rw-r--r--connectivity/source/drivers/odbc/OFunctions.cxx245
-rw-r--r--connectivity/source/drivers/odbc/OPreparedStatement.cxx924
-rw-r--r--connectivity/source/drivers/odbc/ORealDriver.cxx291
-rw-r--r--connectivity/source/drivers/odbc/OResultSet.cxx1847
-rw-r--r--connectivity/source/drivers/odbc/OResultSetMetaData.cxx291
-rw-r--r--connectivity/source/drivers/odbc/OStatement.cxx1140
-rw-r--r--connectivity/source/drivers/odbc/OTools.cxx797
-rw-r--r--connectivity/source/drivers/odbc/odbc.component26
-rw-r--r--connectivity/source/drivers/postgresql/postgresql-sdbc-impl.component17
-rw-r--r--connectivity/source/drivers/postgresql/postgresql-sdbc.component17
-rw-r--r--connectivity/source/drivers/postgresql/pq_array.cxx122
-rw-r--r--connectivity/source/drivers/postgresql/pq_array.hxx98
-rw-r--r--connectivity/source/drivers/postgresql/pq_baseresultset.cxx613
-rw-r--r--connectivity/source/drivers/postgresql/pq_baseresultset.hxx203
-rw-r--r--connectivity/source/drivers/postgresql/pq_connection.cxx572
-rw-r--r--connectivity/source/drivers/postgresql/pq_connection.hxx194
-rw-r--r--connectivity/source/drivers/postgresql/pq_databasemetadata.cxx2511
-rw-r--r--connectivity/source/drivers/postgresql/pq_databasemetadata.hxx237
-rw-r--r--connectivity/source/drivers/postgresql/pq_driver.cxx142
-rw-r--r--connectivity/source/drivers/postgresql/pq_driver.hxx116
-rw-r--r--connectivity/source/drivers/postgresql/pq_fakedupdateableresultset.cxx215
-rw-r--r--connectivity/source/drivers/postgresql/pq_fakedupdateableresultset.hxx106
-rw-r--r--connectivity/source/drivers/postgresql/pq_preparedstatement.cxx738
-rw-r--r--connectivity/source/drivers/postgresql/pq_preparedstatement.hxx221
-rw-r--r--connectivity/source/drivers/postgresql/pq_resultset.cxx309
-rw-r--r--connectivity/source/drivers/postgresql/pq_resultset.hxx94
-rw-r--r--connectivity/source/drivers/postgresql/pq_resultsetmetadata.cxx441
-rw-r--r--connectivity/source/drivers/postgresql/pq_resultsetmetadata.hxx127
-rw-r--r--connectivity/source/drivers/postgresql/pq_sequenceresultset.cxx125
-rw-r--r--connectivity/source/drivers/postgresql/pq_sequenceresultset.hxx92
-rw-r--r--connectivity/source/drivers/postgresql/pq_sequenceresultsetmetadata.cxx191
-rw-r--r--connectivity/source/drivers/postgresql/pq_sequenceresultsetmetadata.hxx89
-rw-r--r--connectivity/source/drivers/postgresql/pq_statement.cxx887
-rw-r--r--connectivity/source/drivers/postgresql/pq_statement.hxx198
-rw-r--r--connectivity/source/drivers/postgresql/pq_statics.cxx627
-rw-r--r--connectivity/source/drivers/postgresql/pq_statics.hxx240
-rw-r--r--connectivity/source/drivers/postgresql/pq_tools.cxx1247
-rw-r--r--connectivity/source/drivers/postgresql/pq_tools.hxx176
-rw-r--r--connectivity/source/drivers/postgresql/pq_updateableresultset.cxx550
-rw-r--r--connectivity/source/drivers/postgresql/pq_updateableresultset.hxx170
-rw-r--r--connectivity/source/drivers/postgresql/pq_xbase.cxx216
-rw-r--r--connectivity/source/drivers/postgresql/pq_xbase.hxx131
-rw-r--r--connectivity/source/drivers/postgresql/pq_xcolumn.cxx95
-rw-r--r--connectivity/source/drivers/postgresql/pq_xcolumn.hxx82
-rw-r--r--connectivity/source/drivers/postgresql/pq_xcolumns.cxx560
-rw-r--r--connectivity/source/drivers/postgresql/pq_xcolumns.hxx122
-rw-r--r--connectivity/source/drivers/postgresql/pq_xcontainer.cxx411
-rw-r--r--connectivity/source/drivers/postgresql/pq_xcontainer.hxx188
-rw-r--r--connectivity/source/drivers/postgresql/pq_xindex.cxx187
-rw-r--r--connectivity/source/drivers/postgresql/pq_xindex.hxx123
-rw-r--r--connectivity/source/drivers/postgresql/pq_xindexcolumn.cxx96
-rw-r--r--connectivity/source/drivers/postgresql/pq_xindexcolumn.hxx83
-rw-r--r--connectivity/source/drivers/postgresql/pq_xindexcolumns.cxx268
-rw-r--r--connectivity/source/drivers/postgresql/pq_xindexcolumns.hxx110
-rw-r--r--connectivity/source/drivers/postgresql/pq_xindexes.cxx303
-rw-r--r--connectivity/source/drivers/postgresql/pq_xindexes.hxx102
-rw-r--r--connectivity/source/drivers/postgresql/pq_xkey.cxx183
-rw-r--r--connectivity/source/drivers/postgresql/pq_xkey.hxx119
-rw-r--r--connectivity/source/drivers/postgresql/pq_xkeycolumn.cxx95
-rw-r--r--connectivity/source/drivers/postgresql/pq_xkeycolumn.hxx82
-rw-r--r--connectivity/source/drivers/postgresql/pq_xkeycolumns.cxx239
-rw-r--r--connectivity/source/drivers/postgresql/pq_xkeycolumns.hxx101
-rw-r--r--connectivity/source/drivers/postgresql/pq_xkeys.cxx295
-rw-r--r--connectivity/source/drivers/postgresql/pq_xkeys.hxx101
-rw-r--r--connectivity/source/drivers/postgresql/pq_xtable.cxx393
-rw-r--r--connectivity/source/drivers/postgresql/pq_xtable.hxx161
-rw-r--r--connectivity/source/drivers/postgresql/pq_xtables.cxx369
-rw-r--r--connectivity/source/drivers/postgresql/pq_xtables.hxx91
-rw-r--r--connectivity/source/drivers/postgresql/pq_xuser.cxx172
-rw-r--r--connectivity/source/drivers/postgresql/pq_xuser.hxx93
-rw-r--r--connectivity/source/drivers/postgresql/pq_xusers.cxx202
-rw-r--r--connectivity/source/drivers/postgresql/pq_xusers.hxx82
-rw-r--r--connectivity/source/drivers/postgresql/pq_xview.cxx217
-rw-r--r--connectivity/source/drivers/postgresql/pq_xview.hxx92
-rw-r--r--connectivity/source/drivers/postgresql/pq_xviews.cxx219
-rw-r--r--connectivity/source/drivers/postgresql/pq_xviews.hxx88
-rw-r--r--connectivity/source/drivers/writer/WCatalog.cxx60
-rw-r--r--connectivity/source/drivers/writer/WConnection.cxx245
-rw-r--r--connectivity/source/drivers/writer/WDatabaseMetaData.cxx112
-rw-r--r--connectivity/source/drivers/writer/WDriver.cxx87
-rw-r--r--connectivity/source/drivers/writer/WTable.cxx234
-rw-r--r--connectivity/source/drivers/writer/WTables.cxx45
-rw-r--r--connectivity/source/drivers/writer/writer.component17
-rw-r--r--connectivity/source/inc/AutoRetrievingBase.hxx50
-rw-r--r--connectivity/source/inc/FDatabaseMetaDataResultSet.hxx270
-rw-r--r--connectivity/source/inc/FDatabaseMetaDataResultSetMetaData.hxx96
-rw-r--r--connectivity/source/inc/OColumn.hxx119
-rw-r--r--connectivity/source/inc/OTypeInfo.hxx50
-rw-r--r--connectivity/source/inc/ParameterSubstitution.hxx63
-rw-r--r--connectivity/source/inc/RowFunctionParser.hxx109
-rw-r--r--connectivity/source/inc/TConnection.hxx81
-rw-r--r--connectivity/source/inc/TDatabaseMetaDataBase.hxx133
-rw-r--r--connectivity/source/inc/TKeyValue.hxx59
-rw-r--r--connectivity/source/inc/TPrivilegesResultSet.hxx46
-rw-r--r--connectivity/source/inc/TResultSetHelper.hxx51
-rw-r--r--connectivity/source/inc/TSkipDeletedSet.hxx80
-rw-r--r--connectivity/source/inc/TSortIndex.hxx110
-rw-r--r--connectivity/source/inc/ado/ACallableStatement.hxx76
-rw-r--r--connectivity/source/inc/ado/ACatalog.hxx49
-rw-r--r--connectivity/source/inc/ado/AColumn.hxx52
-rw-r--r--connectivity/source/inc/ado/AColumns.hxx56
-rw-r--r--connectivity/source/inc/ado/AConnection.hxx134
-rw-r--r--connectivity/source/inc/ado/ADatabaseMetaData.hxx221
-rw-r--r--connectivity/source/inc/ado/ADatabaseMetaDataResultSet.hxx225
-rw-r--r--connectivity/source/inc/ado/ADatabaseMetaDataResultSetMetaData.hxx102
-rw-r--r--connectivity/source/inc/ado/ADriver.hxx80
-rw-r--r--connectivity/source/inc/ado/AGroup.hxx58
-rw-r--r--connectivity/source/inc/ado/AGroups.hxx51
-rw-r--r--connectivity/source/inc/ado/AIndex.hxx46
-rw-r--r--connectivity/source/inc/ado/AIndexes.hxx53
-rw-r--r--connectivity/source/inc/ado/AKey.hxx55
-rw-r--r--connectivity/source/inc/ado/AKeys.hxx53
-rw-r--r--connectivity/source/inc/ado/APreparedStatement.hxx113
-rw-r--r--connectivity/source/inc/ado/AResultSet.hxx234
-rw-r--r--connectivity/source/inc/ado/AResultSetMetaData.hxx79
-rw-r--r--connectivity/source/inc/ado/AStatement.hxx217
-rw-r--r--connectivity/source/inc/ado/ATable.hxx69
-rw-r--r--connectivity/source/inc/ado/ATables.hxx52
-rw-r--r--connectivity/source/inc/ado/AUser.hxx83
-rw-r--r--connectivity/source/inc/ado/AUsers.hxx53
-rw-r--r--connectivity/source/inc/ado/AView.hxx47
-rw-r--r--connectivity/source/inc/ado/AViews.hxx51
-rw-r--r--connectivity/source/inc/ado/Aolevariant.hxx123
-rw-r--r--connectivity/source/inc/ado/Aolewrap.hxx174
-rw-r--r--connectivity/source/inc/ado/Awrapado.hxx372
-rw-r--r--connectivity/source/inc/ado/Awrapadox.hxx139
-rw-r--r--connectivity/source/inc/ado/WrapCatalog.hxx50
-rw-r--r--connectivity/source/inc/ado/WrapColumn.hxx62
-rw-r--r--connectivity/source/inc/ado/WrapIndex.hxx52
-rw-r--r--connectivity/source/inc/ado/WrapKey.hxx54
-rw-r--r--connectivity/source/inc/ado/WrapTable.hxx57
-rw-r--r--connectivity/source/inc/ado/WrapTypeDefs.hxx41
-rw-r--r--connectivity/source/inc/ado/adoimp.hxx103
-rw-r--r--connectivity/source/inc/calc/CCatalog.hxx38
-rw-r--r--connectivity/source/inc/calc/CConnection.hxx149
-rw-r--r--connectivity/source/inc/calc/CDatabaseMetaData.hxx42
-rw-r--r--connectivity/source/inc/calc/CDriver.hxx51
-rw-r--r--connectivity/source/inc/calc/CTable.hxx72
-rw-r--r--connectivity/source/inc/calc/CTables.hxx40
-rw-r--r--connectivity/source/inc/component/CColumns.hxx42
-rw-r--r--connectivity/source/inc/component/CDatabaseMetaData.hxx47
-rw-r--r--connectivity/source/inc/component/CPreparedStatement.hxx39
-rw-r--r--connectivity/source/inc/component/CResultSet.hxx79
-rw-r--r--connectivity/source/inc/component/CStatement.hxx39
-rw-r--r--connectivity/source/inc/component/CTable.hxx66
-rw-r--r--connectivity/source/inc/dbase/DCatalog.hxx38
-rw-r--r--connectivity/source/inc/dbase/DColumns.hxx43
-rw-r--r--connectivity/source/inc/dbase/DConnection.hxx46
-rw-r--r--connectivity/source/inc/dbase/DDatabaseMetaData.hxx57
-rw-r--r--connectivity/source/inc/dbase/DDriver.hxx46
-rw-r--r--connectivity/source/inc/dbase/DIndex.hxx135
-rw-r--r--connectivity/source/inc/dbase/DIndexColumns.hxx49
-rw-r--r--connectivity/source/inc/dbase/DIndexIter.hxx67
-rw-r--r--connectivity/source/inc/dbase/DIndexes.hxx50
-rw-r--r--connectivity/source/inc/dbase/DPreparedStatement.hxx38
-rw-r--r--connectivity/source/inc/dbase/DResultSet.hxx78
-rw-r--r--connectivity/source/inc/dbase/DStatement.hxx38
-rw-r--r--connectivity/source/inc/dbase/DTable.hxx191
-rw-r--r--connectivity/source/inc/dbase/DTables.hxx46
-rw-r--r--connectivity/source/inc/dbase/dindexnode.hxx307
-rw-r--r--connectivity/source/inc/file/FCatalog.hxx60
-rw-r--r--connectivity/source/inc/file/FColumns.hxx47
-rw-r--r--connectivity/source/inc/file/FConnection.hxx131
-rw-r--r--connectivity/source/inc/file/FDatabaseMetaData.hxx186
-rw-r--r--connectivity/source/inc/file/FDateFunctions.hxx228
-rw-r--r--connectivity/source/inc/file/FDriver.hxx72
-rw-r--r--connectivity/source/inc/file/FNumericFunctions.hxx362
-rw-r--r--connectivity/source/inc/file/FPreparedStatement.hxx121
-rw-r--r--connectivity/source/inc/file/FResultSet.hxx301
-rw-r--r--connectivity/source/inc/file/FResultSetMetaData.hxx77
-rw-r--r--connectivity/source/inc/file/FStatement.hxx196
-rw-r--r--connectivity/source/inc/file/FStringFunctions.hxx269
-rw-r--r--connectivity/source/inc/file/FTable.hxx99
-rw-r--r--connectivity/source/inc/file/FTables.hxx44
-rw-r--r--connectivity/source/inc/file/fanalyzer.hxx70
-rw-r--r--connectivity/source/inc/file/fcode.hxx331
-rw-r--r--connectivity/source/inc/file/fcomp.hxx111
-rw-r--r--connectivity/source/inc/file/filedllapi.hxx32
-rw-r--r--connectivity/source/inc/file/quotedstring.hxx46
-rw-r--r--connectivity/source/inc/flat/ECatalog.hxx38
-rw-r--r--connectivity/source/inc/flat/EColumns.hxx41
-rw-r--r--connectivity/source/inc/flat/EConnection.hxx62
-rw-r--r--connectivity/source/inc/flat/EDatabaseMetaData.hxx44
-rw-r--r--connectivity/source/inc/flat/EDriver.hxx45
-rw-r--r--connectivity/source/inc/flat/EPreparedStatement.hxx38
-rw-r--r--connectivity/source/inc/flat/EResultSet.hxx70
-rw-r--r--connectivity/source/inc/flat/EStatement.hxx38
-rw-r--r--connectivity/source/inc/flat/ETable.hxx100
-rw-r--r--connectivity/source/inc/flat/ETables.hxx40
-rw-r--r--connectivity/source/inc/hsqldb/HCatalog.hxx60
-rw-r--r--connectivity/source/inc/hsqldb/HColumns.hxx56
-rw-r--r--connectivity/source/inc/hsqldb/HConnection.hxx142
-rw-r--r--connectivity/source/inc/hsqldb/HDriver.hxx123
-rw-r--r--connectivity/source/inc/hsqldb/HStorageAccess.hxx43
-rw-r--r--connectivity/source/inc/hsqldb/HStorageMap.hxx97
-rw-r--r--connectivity/source/inc/hsqldb/HTable.hxx112
-rw-r--r--connectivity/source/inc/hsqldb/HTables.hxx53
-rw-r--r--connectivity/source/inc/hsqldb/HTools.hxx49
-rw-r--r--connectivity/source/inc/hsqldb/HUser.hxx73
-rw-r--r--connectivity/source/inc/hsqldb/HUsers.hxx52
-rw-r--r--connectivity/source/inc/hsqldb/HView.hxx88
-rw-r--r--connectivity/source/inc/hsqldb/HViews.hxx51
-rw-r--r--connectivity/source/inc/java/ContextClassLoader.hxx79
-rw-r--r--connectivity/source/inc/java/GlobalRef.hxx102
-rw-r--r--connectivity/source/inc/java/LocalRef.hxx95
-rw-r--r--connectivity/source/inc/java/io/InputStream.hxx51
-rw-r--r--connectivity/source/inc/java/io/Reader.hxx52
-rw-r--r--connectivity/source/inc/java/lang/Boolean.hxx43
-rw-r--r--connectivity/source/inc/java/lang/Class.hxx49
-rw-r--r--connectivity/source/inc/java/lang/Exception.hxx42
-rw-r--r--connectivity/source/inc/java/lang/Object.hxx147
-rw-r--r--connectivity/source/inc/java/lang/String.hxx43
-rw-r--r--connectivity/source/inc/java/lang/Throwable.hxx49
-rw-r--r--connectivity/source/inc/java/math/BigDecimal.hxx41
-rw-r--r--connectivity/source/inc/java/sql/Array.hxx54
-rw-r--r--connectivity/source/inc/java/sql/Blob.hxx54
-rw-r--r--connectivity/source/inc/java/sql/CallableStatement.hxx82
-rw-r--r--connectivity/source/inc/java/sql/Clob.hxx54
-rw-r--r--connectivity/source/inc/java/sql/Connection.hxx135
-rw-r--r--connectivity/source/inc/java/sql/ConnectionLog.hxx127
-rw-r--r--connectivity/source/inc/java/sql/DatabaseMetaData.hxx216
-rw-r--r--connectivity/source/inc/java/sql/Driver.hxx59
-rw-r--r--connectivity/source/inc/java/sql/DriverPropertyInfo.hxx42
-rw-r--r--connectivity/source/inc/java/sql/JStatement.hxx234
-rw-r--r--connectivity/source/inc/java/sql/PreparedStatement.hxx103
-rw-r--r--connectivity/source/inc/java/sql/Ref.hxx49
-rw-r--r--connectivity/source/inc/java/sql/ResultSet.hxx210
-rw-r--r--connectivity/source/inc/java/sql/ResultSetMetaData.hxx70
-rw-r--r--connectivity/source/inc/java/sql/SQLException.hxx56
-rw-r--r--connectivity/source/inc/java/sql/SQLWarning.hxx49
-rw-r--r--connectivity/source/inc/java/sql/Timestamp.hxx88
-rw-r--r--connectivity/source/inc/java/tools.hxx66
-rw-r--r--connectivity/source/inc/java/util/Date.hxx45
-rw-r--r--connectivity/source/inc/java/util/Property.hxx38
-rw-r--r--connectivity/source/inc/mysql/YCatalog.hxx60
-rw-r--r--connectivity/source/inc/mysql/YColumns.hxx56
-rw-r--r--connectivity/source/inc/mysql/YDriver.hxx106
-rw-r--r--connectivity/source/inc/mysql/YTable.hxx112
-rw-r--r--connectivity/source/inc/mysql/YTables.hxx63
-rw-r--r--connectivity/source/inc/mysql/YUser.hxx73
-rw-r--r--connectivity/source/inc/mysql/YUsers.hxx52
-rw-r--r--connectivity/source/inc/mysql/YViews.hxx52
-rw-r--r--connectivity/source/inc/odbc/OBoundParam.hxx128
-rw-r--r--connectivity/source/inc/odbc/OConnection.hxx126
-rw-r--r--connectivity/source/inc/odbc/ODatabaseMetaData.hxx203
-rw-r--r--connectivity/source/inc/odbc/ODatabaseMetaDataResultSet.hxx259
-rw-r--r--connectivity/source/inc/odbc/ODriver.hxx77
-rw-r--r--connectivity/source/inc/odbc/OFunctions.hxx600
-rw-r--r--connectivity/source/inc/odbc/OPreparedStatement.hxx149
-rw-r--r--connectivity/source/inc/odbc/OResultSet.hxx354
-rw-r--r--connectivity/source/inc/odbc/OResultSetMetaData.hxx116
-rw-r--r--connectivity/source/inc/odbc/OStatement.hxx244
-rw-r--r--connectivity/source/inc/odbc/OTools.hxx245
-rw-r--r--connectivity/source/inc/odbc/odbcbasedllapi.hxx32
-rw-r--r--connectivity/source/inc/propertyids.hxx109
-rw-r--r--connectivity/source/inc/resource/sharedresources.hxx149
-rw-r--r--connectivity/source/inc/writer/WCatalog.hxx37
-rw-r--r--connectivity/source/inc/writer/WConnection.hxx154
-rw-r--r--connectivity/source/inc/writer/WDatabaseMetaData.hxx43
-rw-r--r--connectivity/source/inc/writer/WDriver.hxx52
-rw-r--r--connectivity/source/inc/writer/WTable.hxx62
-rw-r--r--connectivity/source/inc/writer/WTables.hxx43
-rw-r--r--connectivity/source/manager/mdrivermanager.cxx656
-rw-r--r--connectivity/source/manager/mdrivermanager.hxx121
-rw-r--r--connectivity/source/manager/sdbc2.component26
-rw-r--r--connectivity/source/parse/PColumn.cxx271
-rw-r--r--connectivity/source/parse/internalnode.cxx64
-rw-r--r--connectivity/source/parse/sqlbison.y4857
-rw-r--r--connectivity/source/parse/sqlflex.l809
-rw-r--r--connectivity/source/parse/sqliterator.cxx2122
-rw-r--r--connectivity/source/parse/sqlnode.cxx2775
-rw-r--r--connectivity/source/resource/sharedresources.cxx184
-rw-r--r--connectivity/source/sdbcx/VCatalog.cxx211
-rw-r--r--connectivity/source/sdbcx/VCollection.cxx582
-rw-r--r--connectivity/source/sdbcx/VColumn.cxx216
-rw-r--r--connectivity/source/sdbcx/VDescriptor.cxx105
-rw-r--r--connectivity/source/sdbcx/VGroup.cxx166
-rw-r--r--connectivity/source/sdbcx/VIndex.cxx200
-rw-r--r--connectivity/source/sdbcx/VIndexColumn.cxx102
-rw-r--r--connectivity/source/sdbcx/VKey.cxx203
-rw-r--r--connectivity/source/sdbcx/VKeyColumn.cxx107
-rw-r--r--connectivity/source/sdbcx/VTable.cxx305
-rw-r--r--connectivity/source/sdbcx/VUser.cxx175
-rw-r--r--connectivity/source/sdbcx/VView.cxx133
-rw-r--r--connectivity/workben/iniParser/main.cxx160
-rw-r--r--connectivity/workben/iniParser/makefile.mk52
-rw-r--r--connectivity/workben/little/main.cxx101
-rw-r--r--connectivity/workben/little/makefile.mk50
-rw-r--r--connectivity/workben/skeleton/SResultSet.hxx235
-rw-r--r--connectivity/workben/skeleton/how_to_write_a_driver.txt69
802 files changed, 170869 insertions, 0 deletions
diff --git a/connectivity/AllLangMoTarget_cnr.mk b/connectivity/AllLangMoTarget_cnr.mk
new file mode 100644
index 0000000000..a960ce0b9b
--- /dev/null
+++ b/connectivity/AllLangMoTarget_cnr.mk
@@ -0,0 +1,13 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+$(eval $(call gb_AllLangMoTarget_AllLangMoTarget,cnr))
+
+$(eval $(call gb_AllLangMoTarget_set_polocation,cnr,connectivity))
+
+# vim: set noet sw=4 ts=4:
diff --git a/connectivity/Configuration_ado.mk b/connectivity/Configuration_ado.mk
new file mode 100644
index 0000000000..44673c42f2
--- /dev/null
+++ b/connectivity/Configuration_ado.mk
@@ -0,0 +1,20 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+$(eval $(call gb_Configuration_Configuration,driver_ado))
+
+$(eval $(call gb_Configuration_add_spool_modules,driver_ado,connectivity/registry/ado,\
+ org/openoffice/Office/DataAccess/Drivers-ado.xcu \
+))
+
+$(eval $(call gb_Configuration_add_localized_datas,driver_ado,connectivity/registry/ado,\
+ org/openoffice/Office/DataAccess/Drivers.xcu \
+))
+
+# vim: set noet sw=4 ts=4:
diff --git a/connectivity/Configuration_calc.mk b/connectivity/Configuration_calc.mk
new file mode 100644
index 0000000000..fe26cc9799
--- /dev/null
+++ b/connectivity/Configuration_calc.mk
@@ -0,0 +1,20 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+$(eval $(call gb_Configuration_Configuration,driver_calc))
+
+$(eval $(call gb_Configuration_add_spool_modules,driver_calc,connectivity/registry/calc,\
+ org/openoffice/Office/DataAccess/Drivers-calc.xcu \
+))
+
+$(eval $(call gb_Configuration_add_localized_datas,driver_calc,connectivity/registry/calc,\
+ org/openoffice/Office/DataAccess/Drivers.xcu \
+))
+
+# vim: set noet sw=4 ts=4:
diff --git a/connectivity/Configuration_dbase.mk b/connectivity/Configuration_dbase.mk
new file mode 100644
index 0000000000..e6af965c97
--- /dev/null
+++ b/connectivity/Configuration_dbase.mk
@@ -0,0 +1,20 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+$(eval $(call gb_Configuration_Configuration,driver_dbase))
+
+$(eval $(call gb_Configuration_add_spool_modules,driver_dbase,connectivity/registry/dbase,\
+ org/openoffice/Office/DataAccess/Drivers-dbase.xcu \
+))
+
+$(eval $(call gb_Configuration_add_localized_datas,driver_dbase,connectivity/registry/dbase,\
+ org/openoffice/Office/DataAccess/Drivers.xcu \
+))
+
+# vim: set noet sw=4 ts=4:
diff --git a/connectivity/Configuration_evoab.mk b/connectivity/Configuration_evoab.mk
new file mode 100644
index 0000000000..55de8dbd2d
--- /dev/null
+++ b/connectivity/Configuration_evoab.mk
@@ -0,0 +1,20 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+$(eval $(call gb_Configuration_Configuration,driver_evoab))
+
+$(eval $(call gb_Configuration_add_spool_modules,driver_evoab,connectivity/registry/evoab2,\
+ org/openoffice/Office/DataAccess/Drivers-evoab2.xcu \
+))
+
+$(eval $(call gb_Configuration_add_localized_datas,driver_evoab,connectivity/registry/evoab2,\
+ org/openoffice/Office/DataAccess/Drivers.xcu \
+))
+
+# vim: set noet sw=4 ts=4:
diff --git a/connectivity/Configuration_firebird.mk b/connectivity/Configuration_firebird.mk
new file mode 100644
index 0000000000..47873c7df7
--- /dev/null
+++ b/connectivity/Configuration_firebird.mk
@@ -0,0 +1,20 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+$(eval $(call gb_Configuration_Configuration,driver_firebird_sdbc))
+
+$(eval $(call gb_Configuration_add_spool_modules,driver_firebird_sdbc,connectivity/registry/firebird,\
+ org/openoffice/Office/DataAccess/Drivers-firebird.xcu \
+))
+
+$(eval $(call gb_Configuration_add_localized_datas,driver_firebird_sdbc,connectivity/registry/firebird,\
+ org/openoffice/Office/DataAccess/Drivers.xcu \
+))
+
+# vim: set noet sw=4 ts=4:
diff --git a/connectivity/Configuration_flat.mk b/connectivity/Configuration_flat.mk
new file mode 100644
index 0000000000..8fe5c3af04
--- /dev/null
+++ b/connectivity/Configuration_flat.mk
@@ -0,0 +1,20 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+$(eval $(call gb_Configuration_Configuration,driver_flat))
+
+$(eval $(call gb_Configuration_add_spool_modules,driver_flat,connectivity/registry/flat,\
+ org/openoffice/Office/DataAccess/Drivers-flat.xcu \
+))
+
+$(eval $(call gb_Configuration_add_localized_datas,driver_flat,connectivity/registry/flat,\
+ org/openoffice/Office/DataAccess/Drivers.xcu \
+))
+
+# vim: set noet sw=4 ts=4:
diff --git a/connectivity/Configuration_hsqldb.mk b/connectivity/Configuration_hsqldb.mk
new file mode 100644
index 0000000000..a9528cf497
--- /dev/null
+++ b/connectivity/Configuration_hsqldb.mk
@@ -0,0 +1,20 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+$(eval $(call gb_Configuration_Configuration,driver_hsqldb))
+
+$(eval $(call gb_Configuration_add_spool_modules,driver_hsqldb,connectivity/registry/hsqldb,\
+ org/openoffice/Office/DataAccess/Drivers-hsqldb.xcu \
+))
+
+$(eval $(call gb_Configuration_add_localized_datas,driver_hsqldb,connectivity/registry/hsqldb,\
+ org/openoffice/Office/DataAccess/Drivers.xcu \
+))
+
+# vim: set noet sw=4 ts=4:
diff --git a/connectivity/Configuration_jdbc.mk b/connectivity/Configuration_jdbc.mk
new file mode 100644
index 0000000000..d1320f47c1
--- /dev/null
+++ b/connectivity/Configuration_jdbc.mk
@@ -0,0 +1,20 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+$(eval $(call gb_Configuration_Configuration,driver_jdbc))
+
+$(eval $(call gb_Configuration_add_spool_modules,driver_jdbc,connectivity/registry/jdbc,\
+ org/openoffice/Office/DataAccess/Drivers-jdbc.xcu \
+))
+
+$(eval $(call gb_Configuration_add_localized_datas,driver_jdbc,connectivity/registry/jdbc,\
+ org/openoffice/Office/DataAccess/Drivers.xcu \
+))
+
+# vim: set noet sw=4 ts=4:
diff --git a/connectivity/Configuration_macab.mk b/connectivity/Configuration_macab.mk
new file mode 100644
index 0000000000..2403a2dc3f
--- /dev/null
+++ b/connectivity/Configuration_macab.mk
@@ -0,0 +1,20 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+$(eval $(call gb_Configuration_Configuration,driver_macab))
+
+$(eval $(call gb_Configuration_add_spool_modules,driver_macab,connectivity/registry/macab,\
+ org/openoffice/Office/DataAccess/Drivers-macab.xcu \
+))
+
+$(eval $(call gb_Configuration_add_localized_datas,driver_macab,connectivity/registry/macab,\
+ org/openoffice/Office/DataAccess/Drivers.xcu \
+))
+
+# vim: set noet sw=4 ts=4:
diff --git a/connectivity/Configuration_mysql.mk b/connectivity/Configuration_mysql.mk
new file mode 100644
index 0000000000..5ef54c70a8
--- /dev/null
+++ b/connectivity/Configuration_mysql.mk
@@ -0,0 +1,20 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+$(eval $(call gb_Configuration_Configuration,driver_mysqlc))
+
+$(eval $(call gb_Configuration_add_spool_modules,driver_mysqlc,connectivity/registry/mysqlc,\
+ org/openoffice/Office/DataAccess/Drivers-mysqlc.xcu \
+))
+
+$(eval $(call gb_Configuration_add_localized_datas,driver_mysqlc,connectivity/registry/mysqlc,\
+ org/openoffice/Office/DataAccess/Drivers.xcu \
+))
+
+# vim: set noet sw=4 ts=4:
diff --git a/connectivity/Configuration_mysql_jdbc.mk b/connectivity/Configuration_mysql_jdbc.mk
new file mode 100644
index 0000000000..27a672aad9
--- /dev/null
+++ b/connectivity/Configuration_mysql_jdbc.mk
@@ -0,0 +1,20 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+$(eval $(call gb_Configuration_Configuration,driver_mysql_jdbc))
+
+$(eval $(call gb_Configuration_add_spool_modules,driver_mysql_jdbc,connectivity/registry/mysql_jdbc,\
+ org/openoffice/Office/DataAccess/Drivers-mysql_jdbc.xcu \
+))
+
+$(eval $(call gb_Configuration_add_localized_datas,driver_mysql_jdbc,connectivity/registry/mysql_jdbc,\
+ org/openoffice/Office/DataAccess/Drivers.xcu \
+))
+
+# vim: set noet sw=4 ts=4:
diff --git a/connectivity/Configuration_odbc.mk b/connectivity/Configuration_odbc.mk
new file mode 100644
index 0000000000..bb5df1f3b5
--- /dev/null
+++ b/connectivity/Configuration_odbc.mk
@@ -0,0 +1,20 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+$(eval $(call gb_Configuration_Configuration,driver_odbc))
+
+$(eval $(call gb_Configuration_add_spool_modules,driver_odbc,connectivity/registry/odbc,\
+ org/openoffice/Office/DataAccess/Drivers-odbc.xcu \
+))
+
+$(eval $(call gb_Configuration_add_localized_datas,driver_odbc,connectivity/registry/odbc,\
+ org/openoffice/Office/DataAccess/Drivers.xcu \
+))
+
+# vim: set noet sw=4 ts=4:
diff --git a/connectivity/Configuration_postgresql.mk b/connectivity/Configuration_postgresql.mk
new file mode 100644
index 0000000000..d2e804d846
--- /dev/null
+++ b/connectivity/Configuration_postgresql.mk
@@ -0,0 +1,20 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+$(eval $(call gb_Configuration_Configuration,driver_postgresql))
+
+$(eval $(call gb_Configuration_add_spool_modules,driver_postgresql,connectivity/registry/postgresql,\
+ org/openoffice/Office/DataAccess/Drivers-postgresql.xcu \
+))
+
+$(eval $(call gb_Configuration_add_localized_datas,driver_postgresql,connectivity/registry/postgresql,\
+ org/openoffice/Office/DataAccess/Drivers.xcu \
+))
+
+# vim: set noet sw=4 ts=4:
diff --git a/connectivity/Configuration_writer.mk b/connectivity/Configuration_writer.mk
new file mode 100644
index 0000000000..c14030b11c
--- /dev/null
+++ b/connectivity/Configuration_writer.mk
@@ -0,0 +1,20 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+$(eval $(call gb_Configuration_Configuration,driver_writer))
+
+$(eval $(call gb_Configuration_add_spool_modules,driver_writer,connectivity/registry/writer,\
+ org/openoffice/Office/DataAccess/Drivers-writer.xcu \
+))
+
+$(eval $(call gb_Configuration_add_localized_datas,driver_writer,connectivity/registry/writer,\
+ org/openoffice/Office/DataAccess/Drivers.xcu \
+))
+
+# vim: set noet sw=4 ts=4:
diff --git a/connectivity/CppunitTest_connectivity_ado.mk b/connectivity/CppunitTest_connectivity_ado.mk
new file mode 100644
index 0000000000..3dd9535619
--- /dev/null
+++ b/connectivity/CppunitTest_connectivity_ado.mk
@@ -0,0 +1,69 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+$(eval $(call gb_CppunitTest_CppunitTest,connectivity_ado))
+
+$(eval $(call gb_CppunitTest_set_include,connectivity_ado,\
+ -I$(SRCDIR)/connectivity/inc \
+ -I$(SRCDIR)/connectivity/source/inc \
+ -I$(SRCDIR)/connectivity/source/drivers/ado \
+ $$(INCLUDE) \
+))
+
+$(eval $(call gb_CppunitTest_use_external,connectivity_ado,boost_headers))
+
+$(eval $(call gb_CppunitTest_use_sdk_api,connectivity_ado))
+
+$(eval $(call gb_CppunitTest_use_ure,connectivity_ado))
+$(eval $(call gb_CppunitTest_use_vcl,connectivity_ado))
+
+$(eval $(call gb_CppunitTest_use_sdk_api,connectivity_ado))
+
+ifeq ($(COM),GCC)
+$(eval $(call gb_CppunitTest_add_cxxflags,connectivity_ado,\
+ -fpermissive \
+))
+endif
+
+$(eval $(call gb_CppunitTest_add_exception_objects,connectivity_ado, \
+ connectivity/qa/connectivity/ado/DriverTest \
+))
+
+$(eval $(call gb_CppunitTest_use_libraries,connectivity_ado, \
+ comphelper \
+ cppu \
+ cppuhelper \
+ dbtools \
+ i18nlangtag \
+ ado \
+ sal \
+ salhelper \
+ sb \
+ test \
+ unotest \
+ ucbhelper \
+ utl \
+))
+
+$(eval $(call gb_CppunitTest_use_components,connectivity_ado,\
+ configmgr/source/configmgr \
+ i18npool/util/i18npool \
+ connectivity/source/drivers/ado/ado \
+ ucb/source/core/ucb1 \
+ ucb/source/ucp/file/ucpfile1 \
+))
+
+$(eval $(call gb_CppunitTest_use_configuration,connectivity_ado))
+
+$(call gb_CppunitTest_get_target,connectivity_ado) : $(WORKDIR)/CppunitTest/TS001018407.mdb
+$(WORKDIR)/CppunitTest/TS001018407.mdb : $(SRCDIR)/connectivity/qa/connectivity/ado/TS001018407.mdb
+ mkdir -p $(dir $@)
+ $(call gb_Deliver_deliver,$<,$@)
+
+# vim: set noet sw=4 ts=4:
diff --git a/connectivity/CppunitTest_connectivity_commontools.mk b/connectivity/CppunitTest_connectivity_commontools.mk
new file mode 100644
index 0000000000..81dfe9e686
--- /dev/null
+++ b/connectivity/CppunitTest_connectivity_commontools.mk
@@ -0,0 +1,42 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+$(eval $(call gb_CppunitTest_CppunitTest,connectivity_commontools))
+
+$(eval $(call gb_CppunitTest_set_include,connectivity_commontools,\
+ -I$(SRCDIR)/connectivity/source/inc \
+ $$(INCLUDE) \
+))
+
+$(eval $(call gb_CppunitTest_use_external,connectivity_commontools,boost_headers))
+
+$(eval $(call gb_CppunitTest_use_ure,connectivity_commontools))
+$(eval $(call gb_CppunitTest_use_vcl,connectivity_commontools))
+
+$(eval $(call gb_CppunitTest_use_sdk_api,connectivity_commontools))
+
+$(eval $(call gb_CppunitTest_add_exception_objects,connectivity_commontools, \
+ connectivity/qa/connectivity/commontools/FValue_test \
+))
+
+$(eval $(call gb_CppunitTest_use_libraries,connectivity_commontools, \
+ cppu \
+ dbtools \
+ sal \
+ test \
+ unotest \
+))
+
+$(eval $(call gb_CppunitTest_use_components,connectivity_commontools,\
+ configmgr/source/configmgr \
+))
+
+$(eval $(call gb_CppunitTest_use_configuration,connectivity_commontools))
+
+# vim: set noet sw=4 ts=4:
diff --git a/connectivity/CppunitTest_connectivity_mysql_test.mk b/connectivity/CppunitTest_connectivity_mysql_test.mk
new file mode 100644
index 0000000000..8733315f46
--- /dev/null
+++ b/connectivity/CppunitTest_connectivity_mysql_test.mk
@@ -0,0 +1,66 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+$(eval $(call gb_CppunitTest_CppunitTest,connectivity_mysql_test))
+
+$(eval $(call gb_CppunitTest_use_external,connectivity_mysql_test,boost_headers))
+
+$(eval $(call gb_CppunitTest_add_exception_objects,connectivity_mysql_test, \
+ connectivity/qa/connectivity/mysql/mysql \
+))
+
+$(eval $(call gb_CppunitTest_use_libraries,connectivity_mysql_test, \
+ comphelper \
+ cppu \
+ dbaxml \
+ sal \
+ subsequenttest \
+ svt \
+ test \
+ unotest \
+ utl \
+ xo \
+))
+
+$(eval $(call gb_CppunitTest_use_api,connectivity_mysql_test,\
+ offapi \
+ oovbaapi \
+ udkapi \
+))
+
+$(eval $(call gb_CppunitTest_use_ure,connectivity_mysql_test))
+$(eval $(call gb_CppunitTest_use_vcl,connectivity_mysql_test))
+
+$(eval $(call gb_CppunitTest_use_components,connectivity_mysql_test,\
+ basic/util/sb \
+ comphelper/util/comphelp \
+ configmgr/source/configmgr \
+ connectivity/source/drivers/mysqlc/mysqlc \
+ connectivity/source/manager/sdbc2 \
+ filter/source/config/cache/filterconfig1 \
+ framework/util/fwk \
+ i18npool/util/i18npool \
+ linguistic/source/lng \
+ package/source/xstor/xstor \
+ package/util/package2 \
+ sax/source/expatwrap/expwrap \
+ sfx2/util/sfx \
+ svl/source/fsstor/fsstorage \
+ svl/util/svl \
+ toolkit/util/tk \
+ ucb/source/core/ucb1 \
+ ucb/source/ucp/file/ucpfile1 \
+ unotools/util/utl \
+ uui/util/uui \
+ xmloff/util/xo \
+))
+
+$(eval $(call gb_CppunitTest_use_configuration,connectivity_mysql_test))
+
+# vim: set noet sw=4 ts=4:
diff --git a/connectivity/CppunitTest_connectivity_sharedresources.mk b/connectivity/CppunitTest_connectivity_sharedresources.mk
new file mode 100644
index 0000000000..f9f8172c6f
--- /dev/null
+++ b/connectivity/CppunitTest_connectivity_sharedresources.mk
@@ -0,0 +1,44 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t; fill-column: 100 -*-
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+$(eval $(call gb_CppunitTest_CppunitTest,connectivity_sharedresources))
+
+$(eval $(call gb_CppunitTest_set_include,connectivity_sharedresources,\
+ -I$(SRCDIR)/connectivity/inc \
+ -I$(SRCDIR)/connectivity/source/inc \
+ $$(INCLUDE) \
+))
+
+$(eval $(call gb_CppunitTest_use_external,connectivity_sharedresources,boost_headers))
+
+$(eval $(call gb_CppunitTest_use_ure,connectivity_sharedresources))
+$(eval $(call gb_CppunitTest_use_vcl,connectivity_sharedresources))
+
+$(eval $(call gb_CppunitTest_use_sdk_api,connectivity_sharedresources))
+
+$(eval $(call gb_CppunitTest_add_exception_objects,connectivity_sharedresources, \
+ connectivity/qa/connectivity/resource/sharedresources_test \
+))
+
+$(eval $(call gb_CppunitTest_use_libraries,connectivity_sharedresources, \
+ dbtools \
+ sal \
+ test \
+ utl \
+ unotest \
+))
+
+$(eval $(call gb_CppunitTest_use_components,connectivity_sharedresources,\
+ configmgr/source/configmgr \
+ i18npool/util/i18npool \
+))
+
+$(eval $(call gb_CppunitTest_use_configuration,connectivity_sharedresources))
+
+# vim: set noet sw=4 ts=4:
diff --git a/connectivity/IwyuFilter_connectivity.yaml b/connectivity/IwyuFilter_connectivity.yaml
new file mode 100644
index 0000000000..976f124f14
--- /dev/null
+++ b/connectivity/IwyuFilter_connectivity.yaml
@@ -0,0 +1,81 @@
+---
+assumeFilename: connectivity/source/commontools/dbtools.cxx
+excludelist:
+ connectivity/source/commontools/ConnectionWrapper.cxx:
+ # Actually used
+ - com/sun/star/beans/PropertyValue.hpp
+ - com/sun/star/sdbc/XConnection.hpp
+ connectivity/source/commontools/RowFunctionParser.cxx:
+ # Boost header needed
+ - boost/spirit/include/classic_core.hpp
+ connectivity/source/commontools/conncleanup.cxx:
+ # Actually used
+ - com/sun/star/sdbc/XRowSet.hpp
+ - com/sun/star/sdbc/XConnection.hpp
+ connectivity/source/commontools/dbconversion.cxx:
+ # Needed for rtl::math::round
+ - rtl/math.hxx
+ connectivity/source/commontools/dbexception.cxx:
+ # Actually used
+ - com/sun/star/sdb/SQLErrorEvent.hpp
+ connectivity/source/commontools/dbtools2.cxx:
+ # Actually used
+ - com/sun/star/sdbc/XDataSource.hpp
+ connectivity/source/commontools/paramwrapper.cxx:
+ # Actually used
+ - com/sun/star/sdbc/XParameters.hpp
+ connectivity/source/commontools/warningscontainer.cxx:
+ # Actually used
+ - com/sun/star/sdb/SQLContext.hpp
+ - com/sun/star/sdbc/XWarningsSupplier.hpp
+ connectivity/source/commontools/predicateinput.cxx:
+ # Actually used
+ - com/sun/star/sdbc/XConnection.hpp
+ connectivity/source/commontools/statementcomposer.cxx:
+ # Actually used
+ - com/sun/star/sdbc/XConnection.hpp
+ connectivity/source/commontools/parameters.cxx:
+ # Actually used
+ - com/sun/star/form/XDatabaseParameterListener.hpp
+ - com/sun/star/sdbc/XParameters.hpp
+ - com/sun/star/task/XInteractionHandler.hpp
+ connectivity/source/commontools/DriversConfig.cxx:
+ # Needed for ENABLE_FUZZERS
+ - o3tl/string_view.hxx
+ connectivity/source/cpool/ZPoolCollection.cxx:
+ # Actually used
+ - com/sun/star/beans/PropertyValue.hpp
+ connectivity/source/parse/PColumn.cxx:
+ # Actually used
+ - com/sun/star/sdbc/XResultSetMetaData.hpp
+ connectivity/source/drivers/file/FCatalog.cxx:
+ # Actually used
+ - com/sun/star/sdbc/XRow.hpp
+ connectivity/source/drivers/file/FNumericFunctions.cxx:
+ # Needed for rtl::math::round
+ - rtl/math.hxx
+ connectivity/source/drivers/hsqldb/HStorageAccess.cxx:
+ # Needed for HSQLDB_DBG
+ - accesslog.hxx
+ connectivity/source/drivers/hsqldb/StorageNativeInputStream.cxx:
+ # Needed for HSQLDB_DBG
+ - accesslog.hxx
+ connectivity/source/drivers/hsqldb/StorageNativeOutputStream.cxx:
+ # Needed for HSQLDB_DBG
+ - accesslog.hxx
+ connectivity/source/drivers/jdbc/ConnectionLog.cxx:
+ # Actually used
+ - com/sun/star/util/Date.hpp
+ - com/sun/star/util/Time.hpp
+ - com/sun/star/util/DateTime.hpp
+ connectivity/source/drivers/mysql_jdbc/YDriver.cxx:
+ # Actually used
+ - com/sun/star/uno/XComponentContext.hpp
+ connectivity/source/drivers/odbc/OTools.cxx:
+ # OSL_BIGENDIAN is being checked
+ - osl/endian.h
+ connectivity/source/drivers/postgresql/pq_connection.cxx:
+ # Needed for using deleter_from_fn
+ - pq_tools.hxx
+ connectivity/source/drivers/writer/WDatabaseMetaData.cxx:
+ - com/sun/star/text/XTextDocument.hpp
diff --git a/connectivity/Jar_ConnectivityTools.mk b/connectivity/Jar_ConnectivityTools.mk
new file mode 100644
index 0000000000..250b2ff3ae
--- /dev/null
+++ b/connectivity/Jar_ConnectivityTools.mk
@@ -0,0 +1,42 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+$(eval $(call gb_Jar_Jar,ConnectivityTools))
+
+$(eval $(call gb_Jar_use_jars,ConnectivityTools,\
+ ridl \
+ juh \
+ java_uno \
+ OOoRunner \
+))
+
+$(eval $(call gb_Jar_use_system_jars,ConnectivityTools, \
+ $(OOO_JUNIT_JAR) \
+))
+
+$(eval $(call gb_Jar_set_packageroot,ConnectivityTools,connectivity))
+
+$(eval $(call gb_Jar_add_sourcefiles,ConnectivityTools,\
+ connectivity/qa/connectivity/tools/AbstractDatabase \
+ connectivity/qa/connectivity/tools/CRMDatabase \
+ connectivity/qa/connectivity/tools/CsvDatabase \
+ connectivity/qa/connectivity/tools/DatabaseAccess \
+ connectivity/qa/connectivity/tools/DataSource \
+ connectivity/qa/connectivity/tools/DbaseDatabase \
+ connectivity/qa/connectivity/tools/FlatFileDatabase \
+ connectivity/qa/connectivity/tools/HsqlColumnDescriptor \
+ connectivity/qa/connectivity/tools/HsqlDatabase \
+ connectivity/qa/connectivity/tools/HsqlTableDescriptor \
+ connectivity/qa/connectivity/tools/QueryDefinition \
+ connectivity/qa/connectivity/tools/RowSet \
+ connectivity/qa/connectivity/tools/sdb/Connection \
+))
+
+# vim: set noet sw=4 ts=4:
diff --git a/connectivity/Jar_sdbc_hsqldb.mk b/connectivity/Jar_sdbc_hsqldb.mk
new file mode 100644
index 0000000000..20cd1f8ae0
--- /dev/null
+++ b/connectivity/Jar_sdbc_hsqldb.mk
@@ -0,0 +1,37 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+$(eval $(call gb_Jar_Jar,sdbc_hsqldb))
+
+$(eval $(call gb_Jar_use_externals,sdbc_hsqldb,\
+ hsqldb \
+))
+
+$(eval $(call gb_Jar_add_manifest_classpath,sdbc_hsqldb,\
+ $(if $(filter MACOSX,$(OS)),../../Frameworks/,..) \
+))
+
+$(eval $(call gb_Jar_set_packageroot,sdbc_hsqldb,com))
+
+$(eval $(call gb_Jar_add_packagedir,sdbc_hsqldb,org))
+
+$(eval $(call gb_Jar_add_sourcefiles,sdbc_hsqldb,\
+ connectivity/org/hsqldb/lib/FileSystemRuntimeException \
+ connectivity/com/sun/star/sdbcx/comp/hsqldb/NativeInputStreamHelper \
+ connectivity/com/sun/star/sdbcx/comp/hsqldb/NativeLibraries \
+ connectivity/com/sun/star/sdbcx/comp/hsqldb/NativeOutputStreamHelper \
+ connectivity/com/sun/star/sdbcx/comp/hsqldb/NativeStorageAccess \
+ connectivity/com/sun/star/sdbcx/comp/hsqldb/StorageAccess \
+ connectivity/com/sun/star/sdbcx/comp/hsqldb/StorageFileAccess \
+ connectivity/com/sun/star/sdbcx/comp/hsqldb/StorageNativeInputStream \
+ connectivity/com/sun/star/sdbcx/comp/hsqldb/StorageNativeOutputStream \
+))
+
+# vim: set noet sw=4 ts=4:
diff --git a/connectivity/JunitTest_complex.mk b/connectivity/JunitTest_complex.mk
new file mode 100644
index 0000000000..9b257d4c17
--- /dev/null
+++ b/connectivity/JunitTest_complex.mk
@@ -0,0 +1,51 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+$(eval $(call gb_JunitTest_JunitTest,connectivity_complex))
+
+$(eval $(call gb_JunitTest_use_unoapi_jars,connectivity_complex))
+$(eval $(call gb_JunitTest_use_unoapi_test_class,connectivity_complex))
+
+$(eval $(call gb_JunitTest_set_defs,connectivity_complex,\
+ $$(DEFS) \
+ -Dorg.openoffice.test.arg.sce=$(SRCDIR)/connectivity/qa/scenarios.sce \
+))
+
+$(eval $(call gb_JunitTest_use_externals,connectivity_complex,\
+ hsqldb \
+))
+
+$(eval $(call gb_JunitTest_add_sourcefiles,connectivity_complex,\
+ connectivity/qa/complex/connectivity/DBaseDriverTest \
+ connectivity/qa/complex/connectivity/FlatFileAccess \
+ connectivity/qa/complex/connectivity/HsqlDriverTest \
+ connectivity/qa/complex/connectivity/JdbcLongVarCharTest \
+ connectivity/qa/complex/connectivity/SubTestCase \
+ connectivity/qa/complex/connectivity/TestCase \
+ connectivity/qa/complex/connectivity/dbase/DBaseDateFunctions \
+ connectivity/qa/complex/connectivity/dbase/DBaseNumericFunctions \
+ connectivity/qa/complex/connectivity/dbase/DBaseSqlTests \
+ connectivity/qa/complex/connectivity/dbase/DBaseStringFunctions \
+ connectivity/qa/complex/connectivity/hsqldb/TestCacheSize \
+ connectivity/qa/connectivity/tools/AbstractDatabase \
+ connectivity/qa/connectivity/tools/CRMDatabase \
+ connectivity/qa/connectivity/tools/CsvDatabase \
+ connectivity/qa/connectivity/tools/DataSource \
+ connectivity/qa/connectivity/tools/DatabaseAccess \
+ connectivity/qa/connectivity/tools/DbaseDatabase \
+ connectivity/qa/connectivity/tools/FlatFileDatabase \
+ connectivity/qa/connectivity/tools/HsqlColumnDescriptor \
+ connectivity/qa/connectivity/tools/HsqlDatabase \
+ connectivity/qa/connectivity/tools/HsqlTableDescriptor \
+ connectivity/qa/connectivity/tools/QueryDefinition \
+ connectivity/qa/connectivity/tools/RowSet \
+ connectivity/qa/connectivity/tools/sdb/Connection \
+))
+
+# vim: set noet sw=4 ts=4:
diff --git a/connectivity/Library_ado.mk b/connectivity/Library_ado.mk
new file mode 100644
index 0000000000..8cfd5485fe
--- /dev/null
+++ b/connectivity/Library_ado.mk
@@ -0,0 +1,85 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+$(eval $(call gb_Library_Library,ado))
+
+$(eval $(call gb_Library_set_componentfile,ado,connectivity/source/drivers/ado/ado,services))
+
+$(eval $(call gb_Library_set_include,ado,\
+ -I$(SRCDIR)/connectivity/inc \
+ -I$(SRCDIR)/connectivity/source/inc \
+ $$(INCLUDE) \
+ -I$(WORKDIR)/YaccTarget/connectivity/source/parse \
+))
+
+$(eval $(call gb_Library_use_external,ado,boost_headers))
+
+$(eval $(call gb_Library_set_precompiled_header,ado,connectivity/inc/pch/precompiled_ado))
+
+$(eval $(call gb_Library_use_sdk_api,ado))
+
+ifeq ($(COM),GCC)
+$(eval $(call gb_Library_add_cxxflags,ado,\
+ -fpermissive \
+))
+endif
+
+$(eval $(call gb_Library_use_system_win32_libs,ado,\
+ ole32 \
+ oleaut32 \
+ uuid \
+))
+
+$(eval $(call gb_Library_use_libraries,ado,\
+ cppu \
+ cppuhelper \
+ sal \
+ salhelper \
+ utl \
+ dbtools \
+ comphelper \
+))
+
+$(eval $(call gb_Library_add_exception_objects,ado,\
+ connectivity/source/drivers/ado/ADatabaseMetaDataImpl \
+ connectivity/source/drivers/ado/Aolevariant \
+ connectivity/source/drivers/ado/ADatabaseMetaData \
+ connectivity/source/drivers/ado/AColumn \
+ connectivity/source/drivers/ado/AColumns \
+ connectivity/source/drivers/ado/AIndex \
+ connectivity/source/drivers/ado/AIndexes \
+ connectivity/source/drivers/ado/AKey \
+ connectivity/source/drivers/ado/AKeys \
+ connectivity/source/drivers/ado/AUser \
+ connectivity/source/drivers/ado/AUsers \
+ connectivity/source/drivers/ado/AGroup \
+ connectivity/source/drivers/ado/AGroups \
+ connectivity/source/drivers/ado/ACatalog \
+ connectivity/source/drivers/ado/AView \
+ connectivity/source/drivers/ado/AViews \
+ connectivity/source/drivers/ado/ATable \
+ connectivity/source/drivers/ado/ATables \
+ connectivity/source/drivers/ado/ACallableStatement \
+ connectivity/source/drivers/ado/ADatabaseMetaDataResultSetMetaData \
+ connectivity/source/drivers/ado/ADatabaseMetaDataResultSet \
+ connectivity/source/drivers/ado/AResultSet \
+ connectivity/source/drivers/ado/AConnection \
+ connectivity/source/drivers/ado/AStatement \
+ connectivity/source/drivers/ado/APreparedStatement \
+ connectivity/source/drivers/ado/AResultSetMetaData \
+ connectivity/source/drivers/ado/ADriver \
+ connectivity/source/drivers/ado/Awrapado \
+ connectivity/source/drivers/ado/adoimp \
+))
+
+# Runtime dependency for unit-tests
+$(call gb_Library_get_target,ado) :| $(call gb_Library_get_target,affine_uno_uno)
+
+# vim: set noet sw=4 ts=4:
diff --git a/connectivity/Library_calc.mk b/connectivity/Library_calc.mk
new file mode 100644
index 0000000000..925b6ec8fa
--- /dev/null
+++ b/connectivity/Library_calc.mk
@@ -0,0 +1,50 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+$(eval $(call gb_Library_Library,calc))
+
+$(eval $(call gb_Library_set_componentfile,calc,connectivity/source/drivers/calc/calc,services))
+
+$(eval $(call gb_Library_use_external,calc,boost_headers))
+
+$(eval $(call gb_Library_use_sdk_api,calc))
+
+$(eval $(call gb_Library_set_include,calc,\
+ $$(INCLUDE) \
+ -I$(SRCDIR)/connectivity/inc \
+ -I$(SRCDIR)/connectivity/source/inc \
+ -I$(WORKDIR)/YaccTarget/connectivity/source/parse \
+))
+
+$(eval $(call gb_Library_set_precompiled_header,calc,connectivity/inc/pch/precompiled_calc))
+
+$(eval $(call gb_Library_use_libraries,calc,\
+ cppu \
+ cppuhelper \
+ svl \
+ tl \
+ utl \
+ sal \
+ salhelper \
+ dbtools \
+ file \
+ comphelper \
+))
+
+$(eval $(call gb_Library_add_exception_objects,calc,\
+ connectivity/source/drivers/calc/CDatabaseMetaData \
+ connectivity/source/drivers/calc/CCatalog \
+ connectivity/source/drivers/calc/CTable \
+ connectivity/source/drivers/calc/CTables \
+ connectivity/source/drivers/calc/CConnection \
+ connectivity/source/drivers/calc/CDriver \
+))
+
+# vim: set noet sw=4 ts=4:
diff --git a/connectivity/Library_dbase.mk b/connectivity/Library_dbase.mk
new file mode 100644
index 0000000000..b69b25cb20
--- /dev/null
+++ b/connectivity/Library_dbase.mk
@@ -0,0 +1,61 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+$(eval $(call gb_Library_Library,dbase))
+
+$(eval $(call gb_Library_set_componentfile,dbase,connectivity/source/drivers/dbase/dbase,services))
+
+$(eval $(call gb_Library_use_external,dbase,boost_headers))
+
+$(eval $(call gb_Library_use_sdk_api,dbase))
+
+$(eval $(call gb_Library_set_include,dbase,\
+ $$(INCLUDE) \
+ -I$(SRCDIR)/connectivity/inc \
+ -I$(SRCDIR)/connectivity/source/inc \
+ -I$(WORKDIR)/YaccTarget/connectivity/source/parse \
+))
+
+$(eval $(call gb_Library_set_precompiled_header,dbase,connectivity/inc/pch/precompiled_dbase))
+
+$(eval $(call gb_Library_use_libraries,dbase,\
+ cppu \
+ cppuhelper \
+ svl \
+ tl \
+ ucbhelper \
+ sal \
+ salhelper \
+ dbtools \
+ file \
+ utl \
+ comphelper \
+ svt \
+))
+
+$(eval $(call gb_Library_add_exception_objects,dbase,\
+ connectivity/source/drivers/dbase/DResultSet \
+ connectivity/source/drivers/dbase/DStatement \
+ connectivity/source/drivers/dbase/DPreparedStatement \
+ connectivity/source/drivers/dbase/dindexnode \
+ connectivity/source/drivers/dbase/DIndexIter \
+ connectivity/source/drivers/dbase/DDatabaseMetaData \
+ connectivity/source/drivers/dbase/DCatalog \
+ connectivity/source/drivers/dbase/DColumns \
+ connectivity/source/drivers/dbase/DIndexColumns \
+ connectivity/source/drivers/dbase/DIndex \
+ connectivity/source/drivers/dbase/DIndexes \
+ connectivity/source/drivers/dbase/DTables \
+ connectivity/source/drivers/dbase/DConnection \
+ connectivity/source/drivers/dbase/DDriver \
+ connectivity/source/drivers/dbase/DTable \
+))
+
+# vim: set noet sw=4 ts=4:
diff --git a/connectivity/Library_dbpool2.mk b/connectivity/Library_dbpool2.mk
new file mode 100644
index 0000000000..334a225c89
--- /dev/null
+++ b/connectivity/Library_dbpool2.mk
@@ -0,0 +1,43 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+$(eval $(call gb_Library_Library,dbpool2))
+
+$(eval $(call gb_Library_set_componentfile,dbpool2,connectivity/source/cpool/dbpool2,services))
+
+$(eval $(call gb_Library_set_include,dbpool2,\
+ $$(INCLUDE) \
+ -I$(SRCDIR)/connectivity/inc \
+ -I$(SRCDIR)/connectivity/source/inc \
+))
+
+$(eval $(call gb_Library_set_precompiled_header,dbpool2,connectivity/inc/pch/precompiled_dbpool2))
+
+$(eval $(call gb_Library_use_sdk_api,dbpool2))
+
+$(eval $(call gb_Library_use_libraries,dbpool2,\
+ comphelper \
+ cppu \
+ cppuhelper \
+ dbtools \
+ sal \
+ salhelper \
+ tl \
+))
+
+$(eval $(call gb_Library_add_exception_objects,dbpool2,\
+ connectivity/source/cpool/ZConnectionWrapper \
+ connectivity/source/cpool/ZDriverWrapper \
+ connectivity/source/cpool/ZPooledConnection \
+ connectivity/source/cpool/ZConnectionPool \
+ connectivity/source/cpool/ZPoolCollection \
+))
+
+# vim: set noet sw=4 ts=4:
diff --git a/connectivity/Library_dbtools.mk b/connectivity/Library_dbtools.mk
new file mode 100644
index 0000000000..f8f457e5aa
--- /dev/null
+++ b/connectivity/Library_dbtools.mk
@@ -0,0 +1,127 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+$(eval $(call gb_Library_Library,dbtools))
+
+$(eval $(call gb_Library_add_defs,dbtools,\
+ -DOOO_DLLIMPLEMENTATION_DBTOOLS \
+))
+
+$(eval $(call gb_Library_set_componentfile,dbtools,connectivity/source/dbtools/dbtools,services))
+
+$(eval $(call gb_Library_set_include,dbtools,\
+ $$(INCLUDE) \
+ -I$(SRCDIR)/connectivity/inc \
+ -I$(SRCDIR)/connectivity/source/inc \
+))
+
+#$(eval $(call gb_Library_set_precompiled_header,dbtools,connectivity/inc/pch/precompiled_dbtools))
+
+$(eval $(call gb_Library_use_external,dbtools,boost_headers))
+
+$(eval $(call gb_Library_use_sdk_api,dbtools))
+
+$(eval $(call gb_Library_use_libraries,dbtools,\
+ cppu \
+ cppuhelper \
+ sal \
+ salhelper \
+ $(if $(ENABLE_JAVA), \
+ jvmaccess) \
+ utl \
+ tl \
+ comphelper \
+ i18nlangtag \
+ svt \
+ vcl \
+))
+
+ifeq ($(filter-out NETBSD MACOSX,$(OS)),)
+$(eval $(call gb_Library_use_libraries,dbtools,\
+ ucbhelper \
+))
+endif
+
+$(eval $(call gb_Library_add_exception_objects,dbtools,\
+))
+
+$(eval $(call gb_Library_add_grammars,dbtools,\
+ connectivity/source/parse/sqlbison \
+))
+
+$(call gb_YaccTarget_get_target,connectivity/source/parse/sqlbison) : T_YACCFLAGS := -d -l -pSQLyy -bsql
+
+$(eval $(call gb_Library_add_scanners,dbtools,\
+connectivity/source/parse/sqlflex \
+))
+
+$(call gb_LexTarget_get_scanner_target,connectivity/source/parse/sqlflex) : T_LEXFLAGS := -i -8 -PSQLyy -L
+
+$(eval $(call gb_Library_add_exception_objects,dbtools,\
+ connectivity/source/commontools/AutoRetrievingBase \
+ connectivity/source/commontools/BlobHelper \
+ connectivity/source/commontools/CommonTools \
+ connectivity/source/commontools/ConnectionWrapper \
+ connectivity/source/commontools/DateConversion \
+ connectivity/source/commontools/DriversConfig \
+ connectivity/source/commontools/FDatabaseMetaDataResultSet \
+ connectivity/source/commontools/FDatabaseMetaDataResultSetMetaData \
+ connectivity/source/commontools/FValue \
+ connectivity/source/commontools/ParameterSubstitution \
+ connectivity/source/commontools/RowFunctionParser \
+ connectivity/source/commontools/TColumnsHelper \
+ connectivity/source/commontools/TConnection \
+ connectivity/source/commontools/TDatabaseMetaDataBase \
+ connectivity/source/commontools/TIndex \
+ connectivity/source/commontools/TIndexColumns \
+ connectivity/source/commontools/TIndexes \
+ connectivity/source/commontools/TKey \
+ connectivity/source/commontools/TKeyColumns \
+ connectivity/source/commontools/TKeys \
+ connectivity/source/commontools/TPrivilegesResultSet \
+ connectivity/source/commontools/TSkipDeletedSet \
+ connectivity/source/commontools/TSortIndex \
+ connectivity/source/commontools/TTableHelper \
+ connectivity/source/commontools/conncleanup \
+ connectivity/source/commontools/dbcharset \
+ connectivity/source/commontools/dbconversion \
+ connectivity/source/commontools/dbexception \
+ connectivity/source/commontools/dbmetadata \
+ connectivity/source/commontools/dbtools \
+ connectivity/source/commontools/dbtools2 \
+ connectivity/source/commontools/filtermanager \
+ connectivity/source/commontools/formattedcolumnvalue \
+ connectivity/source/commontools/parameters \
+ connectivity/source/commontools/paramwrapper \
+ connectivity/source/commontools/predicateinput \
+ connectivity/source/commontools/propertyids \
+ connectivity/source/commontools/sqlerror \
+ connectivity/source/commontools/statementcomposer \
+ connectivity/source/commontools/warningscontainer \
+ connectivity/source/parse/PColumn \
+ connectivity/source/parse/internalnode \
+ connectivity/source/parse/sqliterator \
+ connectivity/source/parse/sqlnode \
+ connectivity/source/resource/sharedresources \
+ connectivity/source/sdbcx/VCatalog \
+ connectivity/source/sdbcx/VCollection \
+ connectivity/source/sdbcx/VColumn \
+ connectivity/source/sdbcx/VDescriptor \
+ connectivity/source/sdbcx/VGroup \
+ connectivity/source/sdbcx/VIndex \
+ connectivity/source/sdbcx/VIndexColumn \
+ connectivity/source/sdbcx/VKey \
+ connectivity/source/sdbcx/VKeyColumn \
+ connectivity/source/sdbcx/VTable \
+ connectivity/source/sdbcx/VUser \
+ connectivity/source/sdbcx/VView \
+))
+
+# vim: set noet sw=4 ts=4:
diff --git a/connectivity/Library_evoab.mk b/connectivity/Library_evoab.mk
new file mode 100644
index 0000000000..12f6977179
--- /dev/null
+++ b/connectivity/Library_evoab.mk
@@ -0,0 +1,59 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+$(eval $(call gb_Library_Library,evoab))
+
+$(eval $(call gb_Library_set_include,evoab,\
+ -I$(SRCDIR)/connectivity/inc \
+ -I$(SRCDIR)/connectivity/source/inc \
+ $$(INCLUDE) \
+ -I$(WORKDIR)/YaccTarget/connectivity/source/parse \
+))
+
+$(eval $(call gb_Library_use_externals,evoab,\
+ boost_headers \
+ gobject \
+))
+
+$(eval $(call gb_Library_set_componentfile,evoab,connectivity/source/drivers/evoab2/evoab,services))
+
+$(eval $(call gb_Library_use_sdk_api,evoab))
+
+$(eval $(call gb_Library_use_libraries,evoab,\
+ comphelper \
+ cppu \
+ cppuhelper \
+ i18nlangtag \
+ svl \
+ tl \
+ utl \
+ ucbhelper \
+ sal \
+ salhelper \
+ dbtools \
+ file \
+))
+
+$(eval $(call gb_Library_add_exception_objects,evoab,\
+ connectivity/source/drivers/evoab2/NDriver \
+ connectivity/source/drivers/evoab2/NTable \
+ connectivity/source/drivers/evoab2/NColumns \
+ connectivity/source/drivers/evoab2/NTables \
+ connectivity/source/drivers/evoab2/NCatalog \
+ connectivity/source/drivers/evoab2/NConnection \
+ connectivity/source/drivers/evoab2/NDatabaseMetaData \
+ connectivity/source/drivers/evoab2/NStatement \
+ connectivity/source/drivers/evoab2/NPreparedStatement \
+ connectivity/source/drivers/evoab2/NResultSet \
+ connectivity/source/drivers/evoab2/NResultSetMetaData \
+ connectivity/source/drivers/evoab2/EApi \
+))
+
+# vim: set noet sw=4 ts=4:
diff --git a/connectivity/Library_file.mk b/connectivity/Library_file.mk
new file mode 100644
index 0000000000..2ed564a2e7
--- /dev/null
+++ b/connectivity/Library_file.mk
@@ -0,0 +1,71 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+$(eval $(call gb_Library_Library,file))
+
+$(eval $(call gb_Library_add_defs,file,\
+ -DOOO_DLLIMPLEMENTATION_FILE \
+))
+
+$(eval $(call gb_Library_set_precompiled_header,file,connectivity/inc/pch/precompiled_file))
+
+$(eval $(call gb_Library_set_include,file,\
+ $$(INCLUDE) \
+ -I$(SRCDIR)/connectivity/inc \
+ -I$(SRCDIR)/connectivity/source/inc \
+ -I$(WORKDIR)/YaccTarget/connectivity/source/parse \
+))
+
+$(eval $(call gb_Library_use_external,file,boost_headers))
+
+$(eval $(call gb_Library_use_sdk_api,file))
+
+$(eval $(call gb_Library_use_libraries,file,\
+ cppu \
+ cppuhelper \
+ svl \
+ tl \
+ ucbhelper \
+ sal \
+ salhelper \
+ dbtools \
+ utl \
+ comphelper \
+))
+
+$(eval $(call gb_Library_add_exception_objects,file,\
+ connectivity/source/drivers/component/CColumns \
+ connectivity/source/drivers/component/CDatabaseMetaData \
+ connectivity/source/drivers/component/CPreparedStatement \
+ connectivity/source/drivers/component/CResultSet \
+ connectivity/source/drivers/component/CStatement \
+ connectivity/source/drivers/component/CTable \
+ connectivity/source/drivers/file/FCatalog \
+ connectivity/source/drivers/file/FColumns \
+ connectivity/source/drivers/file/FConnection \
+ connectivity/source/drivers/file/FDatabaseMetaData \
+ connectivity/source/drivers/file/FDateFunctions \
+ connectivity/source/drivers/file/FDriver \
+ connectivity/source/drivers/file/FNoException \
+ connectivity/source/drivers/file/FNumericFunctions \
+ connectivity/source/drivers/file/FPreparedStatement \
+ connectivity/source/drivers/file/FResultSet \
+ connectivity/source/drivers/file/FResultSetMetaData \
+ connectivity/source/drivers/file/FStatement \
+ connectivity/source/drivers/file/FStringFunctions \
+ connectivity/source/drivers/file/FTable \
+ connectivity/source/drivers/file/FTables \
+ connectivity/source/drivers/file/fanalyzer \
+ connectivity/source/drivers/file/fcode \
+ connectivity/source/drivers/file/fcomp \
+ connectivity/source/drivers/file/quotedstring \
+))
+
+# vim: set noet sw=4 ts=4:
diff --git a/connectivity/Library_firebird_sdbc.mk b/connectivity/Library_firebird_sdbc.mk
new file mode 100644
index 0000000000..720dfeb878
--- /dev/null
+++ b/connectivity/Library_firebird_sdbc.mk
@@ -0,0 +1,68 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+$(eval $(call gb_Library_Library,firebird_sdbc))
+
+$(eval $(call gb_Library_use_sdk_api,firebird_sdbc))
+
+$(eval $(call gb_Library_use_externals,firebird_sdbc,\
+ boost_headers \
+ libfbembed \
+))
+
+$(eval $(call gb_Library_set_include,firebird_sdbc,\
+ -I$(SRCDIR)/connectivity/inc \
+ -I$(SRCDIR)/connectivity/source/inc \
+ $$(INCLUDE) \
+ -I$(WORKDIR)/YaccTarget/connectivity/source/parse \
+))
+
+$(eval $(call gb_Library_set_precompiled_header,firebird_sdbc,connectivity/inc/pch/precompiled_firebird_sdbc))
+
+$(eval $(call gb_Library_use_libraries,firebird_sdbc, \
+ comphelper \
+ cppu \
+ cppuhelper \
+ dbtools \
+ sal \
+ salhelper \
+ utl \
+ svt \
+ tl \
+ vcl \
+))
+
+$(eval $(call gb_Library_set_componentfile,firebird_sdbc,connectivity/source/drivers/firebird/firebird_sdbc,services))
+
+$(eval $(call gb_Library_add_exception_objects,firebird_sdbc,\
+ connectivity/source/drivers/firebird/Blob \
+ connectivity/source/drivers/firebird/Clob \
+ connectivity/source/drivers/firebird/Catalog \
+ connectivity/source/drivers/firebird/Column \
+ connectivity/source/drivers/firebird/Columns \
+ connectivity/source/drivers/firebird/Connection \
+ connectivity/source/drivers/firebird/DatabaseMetaData \
+ connectivity/source/drivers/firebird/Driver \
+ connectivity/source/drivers/firebird/Indexes \
+ connectivity/source/drivers/firebird/Keys \
+ connectivity/source/drivers/firebird/PreparedStatement \
+ connectivity/source/drivers/firebird/ResultSet \
+ connectivity/source/drivers/firebird/ResultSetMetaData \
+ connectivity/source/drivers/firebird/Statement \
+ connectivity/source/drivers/firebird/StatementCommonBase \
+ connectivity/source/drivers/firebird/Table \
+ connectivity/source/drivers/firebird/Tables \
+ connectivity/source/drivers/firebird/User \
+ connectivity/source/drivers/firebird/Users \
+ connectivity/source/drivers/firebird/Util \
+ connectivity/source/drivers/firebird/View \
+ connectivity/source/drivers/firebird/Views \
+))
+
+# vim: set noet sw=4 ts=4:
diff --git a/connectivity/Library_flat.mk b/connectivity/Library_flat.mk
new file mode 100644
index 0000000000..0fdf432760
--- /dev/null
+++ b/connectivity/Library_flat.mk
@@ -0,0 +1,55 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+$(eval $(call gb_Library_Library,flat))
+
+$(eval $(call gb_Library_set_componentfile,flat,connectivity/source/drivers/flat/flat,services))
+
+$(eval $(call gb_Library_use_external,flat,boost_headers))
+
+$(eval $(call gb_Library_use_sdk_api,flat))
+
+$(eval $(call gb_Library_set_precompiled_header,flat,connectivity/inc/pch/precompiled_flat))
+
+$(eval $(call gb_Library_set_include,flat,\
+ $$(INCLUDE) \
+ -I$(SRCDIR)/connectivity/inc \
+ -I$(SRCDIR)/connectivity/source/inc \
+ -I$(WORKDIR)/YaccTarget/connectivity/source/parse \
+))
+
+$(eval $(call gb_Library_use_libraries,flat,\
+ cppu \
+ cppuhelper \
+ tl \
+ svl \
+ utl \
+ i18nlangtag \
+ sal \
+ salhelper \
+ dbtools \
+ file \
+ comphelper \
+))
+
+$(eval $(call gb_Library_add_exception_objects,flat,\
+ connectivity/source/drivers/flat/EResultSet \
+ connectivity/source/drivers/flat/EStatement \
+ connectivity/source/drivers/flat/EPreparedStatement \
+ connectivity/source/drivers/flat/ETable \
+ connectivity/source/drivers/flat/EDatabaseMetaData \
+ connectivity/source/drivers/flat/ECatalog \
+ connectivity/source/drivers/flat/EColumns \
+ connectivity/source/drivers/flat/ETables \
+ connectivity/source/drivers/flat/EConnection \
+ connectivity/source/drivers/flat/EDriver \
+))
+
+# vim: set noet sw=4 ts=4:
diff --git a/connectivity/Library_hsqldb.mk b/connectivity/Library_hsqldb.mk
new file mode 100644
index 0000000000..40764b9237
--- /dev/null
+++ b/connectivity/Library_hsqldb.mk
@@ -0,0 +1,61 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+$(eval $(call gb_Library_Library,hsqldb))
+
+$(eval $(call gb_Library_set_include,hsqldb,\
+ -I$(SRCDIR)/connectivity/inc \
+ -I$(SRCDIR)/connectivity/source/inc \
+ $$(INCLUDE) \
+))
+
+$(eval $(call gb_Library_use_externals,hsqldb,\
+ boost_headers \
+ hsqldb \
+))
+
+$(eval $(call gb_Library_use_sdk_api,hsqldb))
+
+$(eval $(call gb_Library_use_libraries,hsqldb,\
+ comphelper \
+ cppu \
+ cppuhelper \
+ dbtools \
+ jvmfwk \
+ sal \
+ salhelper \
+ tl \
+ utl \
+ i18nlangtag \
+))
+
+$(eval $(call gb_Library_set_componentfile,hsqldb,connectivity/source/drivers/hsqldb/hsqldb,services))
+
+$(eval $(call gb_Library_add_exception_objects,hsqldb,\
+ connectivity/source/drivers/hsqldb/HCatalog \
+ connectivity/source/drivers/hsqldb/HColumns \
+ connectivity/source/drivers/hsqldb/HConnection \
+ connectivity/source/drivers/hsqldb/HDriver \
+ connectivity/source/drivers/hsqldb/HStorageAccess \
+ connectivity/source/drivers/hsqldb/HStorageMap \
+ connectivity/source/drivers/hsqldb/HTable \
+ connectivity/source/drivers/hsqldb/HTables \
+ connectivity/source/drivers/hsqldb/HTerminateListener \
+ connectivity/source/drivers/hsqldb/HTools \
+ connectivity/source/drivers/hsqldb/HUser \
+ connectivity/source/drivers/hsqldb/HUsers \
+ connectivity/source/drivers/hsqldb/HView \
+ connectivity/source/drivers/hsqldb/HViews \
+ connectivity/source/drivers/hsqldb/StorageFileAccess \
+ connectivity/source/drivers/hsqldb/StorageNativeInputStream \
+ connectivity/source/drivers/hsqldb/StorageNativeOutputStream \
+ connectivity/source/drivers/hsqldb/accesslog \
+))
+
+# vim: set noet sw=4 ts=4:
diff --git a/connectivity/Library_jdbc.mk b/connectivity/Library_jdbc.mk
new file mode 100644
index 0000000000..578c7013db
--- /dev/null
+++ b/connectivity/Library_jdbc.mk
@@ -0,0 +1,76 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+$(eval $(call gb_Library_Library,jdbc))
+
+$(eval $(call gb_Library_set_componentfile,jdbc,connectivity/source/drivers/jdbc/jdbc,services))
+
+$(eval $(call gb_Library_use_external,jdbc,boost_headers))
+
+$(eval $(call gb_Library_use_sdk_api,jdbc))
+
+$(eval $(call gb_Library_set_include,jdbc,\
+ $$(INCLUDE) \
+ -I$(SRCDIR)/connectivity/inc \
+ -I$(SRCDIR)/connectivity/source/inc \
+ -I$(WORKDIR)/YaccTarget/connectivity/source/parse \
+))
+
+$(eval $(call gb_Library_use_common_precompiled_header,jdbc))
+
+$(eval $(call gb_Library_use_libraries,jdbc,\
+ cppu \
+ cppuhelper \
+ sal \
+ salhelper \
+ jvmaccess \
+ dbtools \
+ tl \
+ utl \
+ jvmfwk \
+ comphelper \
+))
+
+$(eval $(call gb_Library_add_exception_objects,jdbc,\
+ connectivity/source/drivers/jdbc/Array \
+ connectivity/source/drivers/jdbc/Blob \
+ connectivity/source/drivers/jdbc/Boolean \
+ connectivity/source/drivers/jdbc/CallableStatement \
+ connectivity/source/drivers/jdbc/Class \
+ connectivity/source/drivers/jdbc/Clob \
+ connectivity/source/drivers/jdbc/ConnectionLog \
+ connectivity/source/drivers/jdbc/DatabaseMetaData \
+ connectivity/source/drivers/jdbc/Date \
+ connectivity/source/drivers/jdbc/DriverPropertyInfo \
+ connectivity/source/drivers/jdbc/Exception \
+ connectivity/source/drivers/jdbc/InputStream \
+ connectivity/source/drivers/jdbc/JConnection \
+ connectivity/source/drivers/jdbc/JDriver \
+ connectivity/source/drivers/jdbc/JStatement \
+ connectivity/source/drivers/jdbc/Object \
+ connectivity/source/drivers/jdbc/PreparedStatement \
+ connectivity/source/drivers/jdbc/Reader \
+ connectivity/source/drivers/jdbc/Ref \
+ connectivity/source/drivers/jdbc/ResultSet \
+ connectivity/source/drivers/jdbc/ResultSetMetaData \
+ connectivity/source/drivers/jdbc/SQLException \
+ connectivity/source/drivers/jdbc/SQLWarning \
+ connectivity/source/drivers/jdbc/String \
+ connectivity/source/drivers/jdbc/Throwable \
+ connectivity/source/drivers/jdbc/Timestamp \
+ connectivity/source/drivers/jdbc/JBigDecimal \
+ connectivity/source/drivers/jdbc/tools \
+ connectivity/source/drivers/jdbc/ContextClassLoader \
+))
+
+# Runtime dependency for unit-tests
+$(call gb_Library_get_target,jdbc) :| $(call gb_Library_get_target,affine_uno_uno)
+
+# vim: set noet sw=4 ts=4:
diff --git a/connectivity/Library_macab1.mk b/connectivity/Library_macab1.mk
new file mode 100644
index 0000000000..82e3cf489b
--- /dev/null
+++ b/connectivity/Library_macab1.mk
@@ -0,0 +1,40 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+$(eval $(call gb_Library_Library,macab1))
+
+$(eval $(call gb_Library_set_componentfile,macab1,connectivity/source/drivers/macab/macab1,services))
+
+$(eval $(call gb_Library_use_external,macab1,boost_headers))
+
+$(eval $(call gb_Library_use_sdk_api,macab1))
+
+$(eval $(call gb_Library_use_libraries,macab1,\
+ comphelper \
+ cppu \
+ cppuhelper \
+ dbtools \
+ sal \
+ salhelper \
+ tl \
+))
+
+$(eval $(call gb_Library_set_include,macab1,\
+ $$(INCLUDE) \
+ -I$(SRCDIR)/connectivity/inc \
+ -I$(SRCDIR)/connectivity/source/inc \
+ -I$(WORKDIR)/YaccTarget/connectivity/source/parse \
+))
+
+$(eval $(call gb_Library_add_exception_objects,macab1,\
+ connectivity/source/drivers/macab/MacabDriver \
+))
+
+# vim: set noet sw=4 ts=4:
diff --git a/connectivity/Library_macabdrv1.mk b/connectivity/Library_macabdrv1.mk
new file mode 100644
index 0000000000..1baf464a60
--- /dev/null
+++ b/connectivity/Library_macabdrv1.mk
@@ -0,0 +1,58 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+$(eval $(call gb_Library_Library,macabdrv1))
+
+$(eval $(call gb_Library_use_external,macabdrv1,boost_headers))
+
+$(eval $(call gb_Library_use_sdk_api,macabdrv1))
+
+$(eval $(call gb_Library_use_system_darwin_frameworks,macabdrv1,\
+ Carbon \
+ AddressBook \
+))
+
+$(eval $(call gb_Library_use_libraries,macabdrv1,\
+ comphelper \
+ cppu \
+ cppuhelper \
+ dbtools \
+ sal \
+ salhelper \
+))
+
+$(eval $(call gb_Library_set_include,macabdrv1,\
+ $$(INCLUDE) \
+ -I$(SRCDIR)/connectivity/inc \
+ -I$(SRCDIR)/connectivity/source/inc \
+ -I$(WORKDIR)/YaccTarget/connectivity/source/parse \
+))
+
+$(eval $(call gb_Library_add_exception_objects,macabdrv1,\
+ connectivity/source/drivers/macab/MacabColumns \
+ connectivity/source/drivers/macab/MacabTable \
+ connectivity/source/drivers/macab/MacabTables \
+ connectivity/source/drivers/macab/MacabCatalog \
+ connectivity/source/drivers/macab/MacabResultSet \
+ connectivity/source/drivers/macab/MacabStatement \
+ connectivity/source/drivers/macab/MacabPreparedStatement \
+ connectivity/source/drivers/macab/MacabDatabaseMetaData \
+ connectivity/source/drivers/macab/MacabConnection \
+ connectivity/source/drivers/macab/MacabResultSetMetaData \
+ connectivity/source/drivers/macab/macabcondition \
+ connectivity/source/drivers/macab/macaborder \
+ connectivity/source/drivers/macab/MacabRecord \
+ connectivity/source/drivers/macab/MacabRecords \
+ connectivity/source/drivers/macab/MacabHeader \
+ connectivity/source/drivers/macab/MacabGroup \
+ connectivity/source/drivers/macab/MacabAddressBook \
+))
+
+# vim: set noet sw=4 ts=4:
diff --git a/connectivity/Library_mozbootstrap.mk b/connectivity/Library_mozbootstrap.mk
new file mode 100644
index 0000000000..dfa587fa0e
--- /dev/null
+++ b/connectivity/Library_mozbootstrap.mk
@@ -0,0 +1,35 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+$(eval $(call gb_Library_Library,mozbootstrap))
+
+$(eval $(call gb_Library_set_componentfile,mozbootstrap,connectivity/source/drivers/mozab/bootstrap/mozbootstrap,services))
+
+$(eval $(call gb_Library_set_include,mozbootstrap,\
+ -I$(SRCDIR)/connectivity/source/drivers/mozab \
+ $$(INCLUDE) \
+))
+
+$(eval $(call gb_Library_use_sdk_api,mozbootstrap))
+
+$(eval $(call gb_Library_use_libraries,mozbootstrap,\
+ comphelper \
+ cppu \
+ cppuhelper \
+ sal \
+))
+
+$(eval $(call gb_Library_add_exception_objects,mozbootstrap,\
+ connectivity/source/drivers/mozab/bootstrap/MMozillaBootstrap \
+ connectivity/source/drivers/mozab/bootstrap/MNSFolders \
+ connectivity/source/drivers/mozab/bootstrap/MNSINIParser \
+ connectivity/source/drivers/mozab/bootstrap/MNSProfileDiscover \
+))
+
+# vim: set noet sw=4 ts=4:
diff --git a/connectivity/Library_mysql_jdbc.mk b/connectivity/Library_mysql_jdbc.mk
new file mode 100644
index 0000000000..21317ad697
--- /dev/null
+++ b/connectivity/Library_mysql_jdbc.mk
@@ -0,0 +1,48 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+$(eval $(call gb_Library_Library,mysql_jdbc))
+
+$(eval $(call gb_Library_set_componentfile,mysql_jdbc,connectivity/source/drivers/mysql_jdbc/mysql_jdbc,services))
+
+$(eval $(call gb_Library_use_external,mysql_jdbc,boost_headers))
+
+$(eval $(call gb_Library_use_sdk_api,mysql_jdbc))
+
+$(eval $(call gb_Library_set_include,mysql_jdbc,\
+ $$(INCLUDE) \
+ -I$(SRCDIR)/connectivity/inc \
+ -I$(SRCDIR)/connectivity/source/inc \
+))
+
+$(eval $(call gb_Library_set_precompiled_header,mysql_jdbc,connectivity/inc/pch/precompiled_mysql_jdbc))
+
+$(eval $(call gb_Library_use_libraries,mysql_jdbc,\
+ cppu \
+ cppuhelper \
+ sal \
+ salhelper \
+ utl \
+ dbtools \
+ comphelper \
+))
+
+$(eval $(call gb_Library_add_exception_objects,mysql_jdbc,\
+ connectivity/source/drivers/mysql_jdbc/YDriver \
+ connectivity/source/drivers/mysql_jdbc/YTables \
+ connectivity/source/drivers/mysql_jdbc/YTable \
+ connectivity/source/drivers/mysql_jdbc/YViews \
+ connectivity/source/drivers/mysql_jdbc/YCatalog \
+ connectivity/source/drivers/mysql_jdbc/YColumns \
+ connectivity/source/drivers/mysql_jdbc/YUser \
+ connectivity/source/drivers/mysql_jdbc/YUsers \
+))
+
+# vim: set noet sw=4 ts=4:
diff --git a/connectivity/Library_mysqlc.mk b/connectivity/Library_mysqlc.mk
new file mode 100644
index 0000000000..af46fb9ba1
--- /dev/null
+++ b/connectivity/Library_mysqlc.mk
@@ -0,0 +1,78 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, you can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+$(eval $(call gb_Library_Library,mysqlc))
+
+$(eval $(call gb_Library_use_externals,mysqlc,\
+ boost_headers \
+ mariadb-connector-c \
+ openssl \
+))
+
+$(eval $(call gb_Library_set_include,mysqlc,\
+ -I$(SRCDIR)/connectivity/inc \
+ -I$(SRCDIR)/connectivity/source/inc \
+ $$(INCLUDE) \
+ -I$(WORKDIR)/YaccTarget/connectivity/source/parse \
+))
+
+$(eval $(call gb_Library_add_libs,mysqlc,\
+ $(if $(filter-out WNT,$(OS)),$(if $(filter HAIKU MACOSX SOLARIS,$(OS)),\
+ -lz -lm,-rdynamic -lz -lcrypt -lm)) \
+ $(if $(filter LINUX,$(OS)),-ldl,) \
+))
+
+$(eval $(call gb_Library_use_sdk_api,mysqlc))
+
+$(eval $(call gb_Library_use_libraries,mysqlc,\
+ comphelper \
+ cppu \
+ cppuhelper \
+ dbtools \
+ sal \
+ salhelper \
+))
+
+$(eval $(call gb_Library_add_defs,mysqlc,\
+ -DCPPDBC_EXPORTS \
+ -DCPPCONN_LIB_BUILD \
+ -DMARIADBC_VERSION_MAJOR=$(MARIADBC_MAJOR) \
+ -DMARIADBC_VERSION_MINOR=$(MARIADBC_MINOR) \
+ -DMARIADBC_VERSION_MICRO=$(MARIADBC_MICRO) \
+ $(if $(BUNDLE_MARIADB_CONNECTOR_C),-DBUNDLE_MARIADB=\"$(LIBMARIADB)\") \
+))
+
+$(eval $(call gb_Library_add_exception_objects,mysqlc,\
+ connectivity/source/drivers/mysqlc/mysqlc_catalog \
+ connectivity/source/drivers/mysqlc/mysqlc_column \
+ connectivity/source/drivers/mysqlc/mysqlc_columns \
+ connectivity/source/drivers/mysqlc/mysqlc_connection \
+ connectivity/source/drivers/mysqlc/mysqlc_databasemetadata \
+ connectivity/source/drivers/mysqlc/mysqlc_driver \
+ connectivity/source/drivers/mysqlc/mysqlc_general \
+ connectivity/source/drivers/mysqlc/mysqlc_indexes \
+ connectivity/source/drivers/mysqlc/mysqlc_keys \
+ connectivity/source/drivers/mysqlc/mysqlc_prepared_resultset \
+ connectivity/source/drivers/mysqlc/mysqlc_preparedstatement \
+ connectivity/source/drivers/mysqlc/mysqlc_resultset \
+ connectivity/source/drivers/mysqlc/mysqlc_resultsetmetadata \
+ connectivity/source/drivers/mysqlc/mysqlc_services \
+ connectivity/source/drivers/mysqlc/mysqlc_statement \
+ connectivity/source/drivers/mysqlc/mysqlc_table \
+ connectivity/source/drivers/mysqlc/mysqlc_tables \
+ connectivity/source/drivers/mysqlc/mysqlc_types \
+ connectivity/source/drivers/mysqlc/mysqlc_user \
+ connectivity/source/drivers/mysqlc/mysqlc_users \
+ connectivity/source/drivers/mysqlc/mysqlc_view \
+ connectivity/source/drivers/mysqlc/mysqlc_views \
+))
+
+$(eval $(call gb_Library_set_componentfile,mysqlc,connectivity/source/drivers/mysqlc/mysqlc,services))
+
+# vim: set noet sw=4 ts=4:
diff --git a/connectivity/Library_odbc.mk b/connectivity/Library_odbc.mk
new file mode 100644
index 0000000000..b144129320
--- /dev/null
+++ b/connectivity/Library_odbc.mk
@@ -0,0 +1,61 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+$(eval $(call gb_Library_Library,odbc))
+
+$(eval $(call gb_Library_set_componentfile,odbc,connectivity/source/drivers/odbc/odbc,services))
+
+$(eval $(call gb_Library_use_sdk_api,odbc))
+
+$(eval $(call gb_Library_set_include,odbc,\
+ $$(INCLUDE) \
+ -I$(SRCDIR)/connectivity/inc \
+ -I$(SRCDIR)/connectivity/source/inc \
+ -I$(WORKDIR)/YaccTarget/connectivity/source/parse \
+))
+
+$(eval $(call gb_Library_add_defs,odbc,\
+ -DOOO_DLLIMPLEMENTATION_ODBCBASE \
+ $(if $(and $(filter MACOSX,$(OS)), $(if $(SYSTEM_ODBC_HEADERS),,TRUE)), \
+ -DSQL_WCHART_CONVERT) \
+))
+
+$(eval $(call gb_Library_set_precompiled_header,odbc,connectivity/inc/pch/precompiled_odbc))
+
+$(eval $(call gb_Library_use_externals,odbc,\
+ boost_headers \
+ odbc_headers \
+))
+
+$(eval $(call gb_Library_use_libraries,odbc,\
+ cppu \
+ cppuhelper \
+ comphelper \
+ dbtools \
+ sal \
+ salhelper \
+ utl \
+))
+
+$(eval $(call gb_Library_add_exception_objects,odbc,\
+ connectivity/source/drivers/odbc/ORealDriver \
+ connectivity/source/drivers/odbc/OFunctions \
+ connectivity/source/drivers/odbc/OPreparedStatement \
+ connectivity/source/drivers/odbc/OStatement \
+ connectivity/source/drivers/odbc/OResultSetMetaData \
+ connectivity/source/drivers/odbc/OResultSet \
+ connectivity/source/drivers/odbc/OTools \
+ connectivity/source/drivers/odbc/ODatabaseMetaDataResultSet \
+ connectivity/source/drivers/odbc/ODatabaseMetaData \
+ connectivity/source/drivers/odbc/ODriver \
+ connectivity/source/drivers/odbc/OConnection \
+))
+
+# vim: set noet sw=4 ts=4:
diff --git a/connectivity/Library_postgresql-sdbc-impl.mk b/connectivity/Library_postgresql-sdbc-impl.mk
new file mode 100644
index 0000000000..19a61ff925
--- /dev/null
+++ b/connectivity/Library_postgresql-sdbc-impl.mk
@@ -0,0 +1,105 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+$(eval $(call gb_Library_Library,postgresql-sdbc-impl))
+
+$(eval $(call gb_Library_add_defs,postgresql-sdbc-impl,\
+ -DPQ_SDBC_MAJOR=0 \
+ -DPQ_SDBC_MINOR=8 \
+ -DPQ_SDBC_MICRO=2 \
+))
+
+$(eval $(call gb_Library_set_precompiled_header,postgresql-sdbc-impl,connectivity/inc/pch/precompiled_postgresql-sdbc-impl))
+
+$(eval $(call gb_Library_use_sdk_api,postgresql-sdbc-impl))
+
+$(eval $(call gb_Library_use_libraries,postgresql-sdbc-impl,\
+ comphelper \
+ cppu \
+ cppuhelper \
+ dbtools \
+ sal \
+ salhelper \
+))
+
+ifeq ($(OS),WNT)
+$(eval $(call gb_Library_use_system_win32_libs,postgresql-sdbc-impl,\
+ shell32 \
+ wldap32 \
+))
+
+ifeq ($(COM),MSC)
+$(eval $(call gb_Library_add_ldflags,postgresql-sdbc-impl,\
+ /NODEFAULTLIB:libcmt.lib \
+))
+endif
+
+endif
+
+$(eval $(call gb_Library_use_externals,postgresql-sdbc-impl,\
+ boost_headers \
+ postgresql \
+ $(if $(filter-out MSC,$(COM)), \
+ $(if $(ENABLE_OPENSSL),openssl) \
+ $(if $(ENABLE_LDAP), \
+ openldap \
+ ) \
+ ) \
+))
+
+ifeq ($(SYSTEM_POSTGRESQL),)
+ifneq ($(OS),WNT)
+
+$(eval $(call gb_Library_add_libs,postgresql-sdbc-impl,\
+ $(if $(WITH_GSSAPI),$(GSSAPI_LIBS)) \
+ $(if $(WITH_KRB5),$(KRB5_LIBS)) \
+ $(if $(filter-out MACOSX,$(OS)),-ldl) \
+))
+
+endif
+endif
+
+$(eval $(call gb_Library_set_componentfile,postgresql-sdbc-impl,connectivity/source/drivers/postgresql/postgresql-sdbc-impl,postgresql-sdbc))
+
+$(eval $(call gb_Library_add_exception_objects,postgresql-sdbc-impl,\
+ connectivity/source/drivers/postgresql/pq_array \
+ connectivity/source/drivers/postgresql/pq_baseresultset \
+ connectivity/source/drivers/postgresql/pq_connection \
+ connectivity/source/drivers/postgresql/pq_databasemetadata \
+ connectivity/source/drivers/postgresql/pq_fakedupdateableresultset \
+ connectivity/source/drivers/postgresql/pq_preparedstatement \
+ connectivity/source/drivers/postgresql/pq_resultset \
+ connectivity/source/drivers/postgresql/pq_resultsetmetadata \
+ connectivity/source/drivers/postgresql/pq_sequenceresultset \
+ connectivity/source/drivers/postgresql/pq_sequenceresultsetmetadata \
+ connectivity/source/drivers/postgresql/pq_statement \
+ connectivity/source/drivers/postgresql/pq_statics \
+ connectivity/source/drivers/postgresql/pq_tools \
+ connectivity/source/drivers/postgresql/pq_updateableresultset \
+ connectivity/source/drivers/postgresql/pq_xbase \
+ connectivity/source/drivers/postgresql/pq_xcolumn \
+ connectivity/source/drivers/postgresql/pq_xcolumns \
+ connectivity/source/drivers/postgresql/pq_xcontainer \
+ connectivity/source/drivers/postgresql/pq_xindex \
+ connectivity/source/drivers/postgresql/pq_xindexcolumn \
+ connectivity/source/drivers/postgresql/pq_xindexcolumns \
+ connectivity/source/drivers/postgresql/pq_xindexes \
+ connectivity/source/drivers/postgresql/pq_xkey \
+ connectivity/source/drivers/postgresql/pq_xkeycolumn \
+ connectivity/source/drivers/postgresql/pq_xkeycolumns \
+ connectivity/source/drivers/postgresql/pq_xkeys \
+ connectivity/source/drivers/postgresql/pq_xtable \
+ connectivity/source/drivers/postgresql/pq_xtables \
+ connectivity/source/drivers/postgresql/pq_xuser \
+ connectivity/source/drivers/postgresql/pq_xusers \
+ connectivity/source/drivers/postgresql/pq_xview \
+ connectivity/source/drivers/postgresql/pq_xviews \
+))
+
+# vim: set noet sw=4 ts=4:
diff --git a/connectivity/Library_postgresql-sdbc.mk b/connectivity/Library_postgresql-sdbc.mk
new file mode 100644
index 0000000000..b8b39faec9
--- /dev/null
+++ b/connectivity/Library_postgresql-sdbc.mk
@@ -0,0 +1,34 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+$(eval $(call gb_Library_Library,postgresql-sdbc))
+
+$(eval $(call gb_Library_add_defs,postgresql-sdbc,\
+ -DPQ_SDBC_MAJOR=0 \
+ -DPQ_SDBC_MINOR=8 \
+ -DPQ_SDBC_MICRO=2 \
+))
+
+$(eval $(call gb_Library_use_sdk_api,postgresql-sdbc))
+
+$(eval $(call gb_Library_use_libraries,postgresql-sdbc,\
+ comphelper \
+ cppu \
+ cppuhelper \
+ sal \
+ salhelper \
+))
+
+$(eval $(call gb_Library_set_componentfile,postgresql-sdbc,connectivity/source/drivers/postgresql/postgresql-sdbc,postgresql-sdbc))
+
+$(eval $(call gb_Library_add_exception_objects,postgresql-sdbc,\
+ connectivity/source/drivers/postgresql/pq_driver \
+))
+
+# vim: set noet sw=4 ts=4:
diff --git a/connectivity/Library_sdbc2.mk b/connectivity/Library_sdbc2.mk
new file mode 100644
index 0000000000..e7296a2efc
--- /dev/null
+++ b/connectivity/Library_sdbc2.mk
@@ -0,0 +1,38 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+$(eval $(call gb_Library_Library,sdbc2))
+
+$(eval $(call gb_Library_set_componentfile,sdbc2,connectivity/source/manager/sdbc2,services))
+
+$(eval $(call gb_Library_use_external,sdbc2,boost_headers))
+
+$(eval $(call gb_Library_use_sdk_api,sdbc2))
+
+$(eval $(call gb_Library_set_include,sdbc2,\
+ $$(INCLUDE) \
+ -I$(SRCDIR)/connectivity/inc \
+))
+
+$(eval $(call gb_Library_use_libraries,sdbc2,\
+ cppu \
+ cppuhelper \
+ comphelper \
+ dbtools \
+ utl \
+ sal \
+ tl \
+))
+
+$(eval $(call gb_Library_add_exception_objects,sdbc2,\
+ connectivity/source/manager/mdrivermanager \
+))
+
+# vim: set noet sw=4 ts=4:
diff --git a/connectivity/Library_writer.mk b/connectivity/Library_writer.mk
new file mode 100644
index 0000000000..a653e5502d
--- /dev/null
+++ b/connectivity/Library_writer.mk
@@ -0,0 +1,48 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+$(eval $(call gb_Library_Library,writer))
+
+$(eval $(call gb_Library_set_componentfile,writer,connectivity/source/drivers/writer/writer,services))
+
+$(eval $(call gb_Library_use_external,writer,boost_headers))
+
+$(eval $(call gb_Library_use_sdk_api,writer))
+
+$(eval $(call gb_Library_set_include,writer,\
+ $$(INCLUDE) \
+ -I$(SRCDIR)/connectivity/inc \
+ -I$(SRCDIR)/connectivity/source/inc \
+ -I$(WORKDIR)/YaccTarget/connectivity/source/parse \
+))
+
+$(eval $(call gb_Library_use_libraries,writer,\
+ cppu \
+ cppuhelper \
+ svl \
+ tl \
+ utl \
+ sal \
+ salhelper \
+ dbtools \
+ file \
+ comphelper \
+))
+
+$(eval $(call gb_Library_add_exception_objects,writer,\
+ connectivity/source/drivers/writer/WCatalog \
+ connectivity/source/drivers/writer/WConnection \
+ connectivity/source/drivers/writer/WDatabaseMetaData \
+ connectivity/source/drivers/writer/WDriver \
+ connectivity/source/drivers/writer/WTable \
+ connectivity/source/drivers/writer/WTables \
+))
+
+# vim: set noet sw=4 ts=4:
diff --git a/connectivity/Makefile b/connectivity/Makefile
new file mode 100644
index 0000000000..ccb1c85a04
--- /dev/null
+++ b/connectivity/Makefile
@@ -0,0 +1,7 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+
+module_directory:=$(dir $(realpath $(firstword $(MAKEFILE_LIST))))
+
+include $(module_directory)/../solenv/gbuild/partial_build.mk
+
+# vim: set noet sw=4 ts=4:
diff --git a/connectivity/Module_connectivity.mk b/connectivity/Module_connectivity.mk
new file mode 100644
index 0000000000..b952594b00
--- /dev/null
+++ b/connectivity/Module_connectivity.mk
@@ -0,0 +1,136 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+$(eval $(call gb_Module_Module,connectivity))
+
+$(eval $(call gb_Module_add_targets,connectivity,\
+ Library_dbtools \
+))
+
+ifneq (,$(filter DBCONNECTIVITY,$(BUILD_TYPE)))
+
+$(eval $(call gb_Module_add_targets,connectivity,\
+ Configuration_calc \
+ Configuration_dbase \
+ Configuration_flat \
+ Configuration_mysql_jdbc \
+ Configuration_odbc \
+ Configuration_mysql_jdbc \
+ Configuration_writer \
+ Library_calc \
+ Library_dbase \
+ Library_dbpool2 \
+ Library_file \
+ Library_flat \
+ $(if $(filter ANDROID iOS,$(OS)),,Library_odbc) \
+ Library_mysql_jdbc \
+ Library_sdbc2 \
+ Library_writer \
+))
+
+$(eval $(call gb_Module_add_l10n_targets,connectivity,\
+ AllLangMoTarget_cnr \
+))
+
+ifneq ($(ENABLE_JAVA),)
+$(eval $(call gb_Module_add_targets,connectivity,\
+ Configuration_hsqldb \
+ Configuration_jdbc \
+ Jar_sdbc_hsqldb \
+ Library_hsqldb \
+ Library_jdbc \
+))
+endif
+
+ifeq ($(OS),MACOSX)
+$(eval $(call gb_Module_add_targets,connectivity,\
+ Configuration_macab \
+ Library_macab1 \
+ Library_macabdrv1 \
+))
+endif
+
+ifeq ($(OS),WNT)
+$(eval $(call gb_Module_add_targets,connectivity,\
+ Configuration_ado \
+ Library_ado \
+))
+
+# "ADO is not available on 64bit" said the commit
+ifeq ($(CPUNAME),INTEL)
+$(eval $(call gb_Module_add_check_targets,connectivity,\
+ CppunitTest_connectivity_ado \
+))
+endif
+endif # WNT
+
+ifeq ($(ENABLE_EVOAB2),TRUE)
+$(eval $(call gb_Module_add_targets,connectivity,\
+ Configuration_evoab \
+ Library_evoab \
+))
+endif
+
+ifeq ($(ENABLE_FIREBIRD_SDBC),TRUE)
+$(eval $(call gb_Module_add_targets,connectivity,\
+ Configuration_firebird \
+ Library_firebird_sdbc \
+))
+endif
+
+ifeq ($(ENABLE_MARIADBC),TRUE)
+$(eval $(call gb_Module_add_targets,connectivity,\
+ Configuration_mysql \
+ Library_mysqlc \
+))
+endif
+
+ifneq ($(BUILD_POSTGRESQL_SDBC),)
+$(eval $(call gb_Module_add_targets,connectivity,\
+ Configuration_postgresql \
+ Library_postgresql-sdbc \
+ Library_postgresql-sdbc-impl \
+ Package_postgresql-sdbc \
+ Rdb_postgresql-sdbc \
+))
+endif
+
+ifneq (,$(filter DESKTOP,$(BUILD_TYPE)))
+
+$(eval $(call gb_Module_add_targets,connectivity,\
+ Library_mozbootstrap \
+))
+
+endif
+
+ifneq ($(filter QADEVOOO,$(BUILD_TYPE)),)
+$(eval $(call gb_Module_add_subsequentcheck_targets,connectivity,\
+ Jar_ConnectivityTools \
+))
+# FIXME: Does not work. Convert to JUnit.
+# JunitTest_complex \
+
+endif
+
+ifneq ($(CONNECTIVITY_TEST_MYSQL_DRIVER),)
+$(eval $(call gb_Module_add_check_targets,connectivity,\
+ CppunitTest_connectivity_mysql_test \
+))
+endif
+
+# general tests
+$(eval $(call gb_Module_add_check_targets,connectivity,\
+ CppunitTest_connectivity_commontools \
+ CppunitTest_connectivity_sharedresources \
+))
+
+endif # DBCONNECTIVITY
+
+# vim: set noet sw=4 ts=4:
diff --git a/connectivity/Package_postgresql-sdbc.mk b/connectivity/Package_postgresql-sdbc.mk
new file mode 100644
index 0000000000..171fb6e23d
--- /dev/null
+++ b/connectivity/Package_postgresql-sdbc.mk
@@ -0,0 +1,12 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+$(eval $(call gb_Package_Package,connectivity_postgresql-sdbc,$(SRCDIR)/connectivity/source/drivers/postgresql))
+
+# vim: set noet sw=4 ts=4:
diff --git a/connectivity/README.md b/connectivity/README.md
new file mode 100644
index 0000000000..a2c27677c3
--- /dev/null
+++ b/connectivity/README.md
@@ -0,0 +1,66 @@
+# Database Connectivity
+
+Contains database pieces, drivers, etc.
+
+`dbaccess` builds UI on top of this.
+
+## Testing
+### PostgreSQL
+
+For testing, use:
+
+ podman pull postgres:latest
+ podman run --name=postgres -e POSTGRES_PASSWORD=foobarbaz -p 127.0.0.1:5432:5432 postgres:latest
+
+In Base, Connect to an existing database, select PostgreSQL:
+
+ URL: host=127.0.0.1 port=5432 dbname=postgres
+ User: postgres
+ Password: foobarbaz
+
+ podman stop postgres
+ podman rm postgres
+
+In order to test SCRAM authentication, create the container like this:
+
+ podman run --name=postgres -e POSTGRES_PASSWORD=foobarbaz -e POSTGRES_INITDB_ARGS=--auth-host=scram-sha-256 -e POSTGRES_HOST_AUTH_METHOD=scram-sha-256 -p 127.0.0.1:5432:5432 postgres:latest
+
+### MySQL
+
+For mysql_test:
+
+- The CppunitTest_mysql_test unit test can be used to test the mysqlc
+library with any versions of mysql or mariadb server of your choice.
+
+- This test does not run automatically. It can be triggered with setting
+the environment variable "CONNECTIVITY_TEST_MYSQL_DRIVER".
+
+- The environment variable should contain a URL of the following format:
+`[user]/[passwd]@sdbc:mysql:mysqlc:[host]:[port]/db_name`
+
+- tl;dr:
+
+```
+ podman pull mariadb/server
+ podman run --name=mariadb -e MYSQL_ROOT_PASSWORD=foobarbaz -p 127.0.0.1:3306:3306 mariadb/server
+ podman exec -it mariadb /bin/bash -c "echo -e CREATE DATABASE test | /usr/bin/mysql -u root"
+ (cd connectivity && make -srj8 CppunitTest_connectivity_mysql_test CONNECTIVITY_TEST_MYSQL_DRIVER="root/foobarbaz@sdbc:mysql:mysqlc:127.0.0.1:3306/test")
+ podman stop mariadb
+ podman rm mariadb
+```
+
+### Firebird
+
+Firebird has two primary file types:
+
+- Databases - FDB files. These are version-specific, platform-specific, optimized for performance, and thus incompatible between versions. These are what those comments are about. Initially, when FB integration was considered, these files were evaluated for ODBs, but were rejected because of the said incompatibility - even when the version is the same, it will differ on big endian architecture and little endian one. The problem discussed in those comments is when people open stand-alone FDBs that are shipped e.g. with FB installation itself, not when people open ODBs.
+
+- Database backups - FBKs. These are what we use inside ODBs. These are designed to be compatible, independent of architecture; and later versions of FB are always able to open FBKs created in older FB versions.
+
+Our embedded FB is used like this:
+- FBK is extracted from ODB;
+- Embedded FB extracts the compatible FBK into an incompatible FDB (specific to this version of embedded FB DLL);
+- FB works with this temporary FDB;
+- When saving ODB, embedded FB backups the FDB into FBK again, and that is stored inside the ODB.
+
+It, indeed, creates additional performance penalty, but makes the ODB readable by all the future LO versions, no matter what future FB version they embed.
diff --git a/connectivity/Rdb_postgresql-sdbc.mk b/connectivity/Rdb_postgresql-sdbc.mk
new file mode 100644
index 0000000000..e6c3b06e06
--- /dev/null
+++ b/connectivity/Rdb_postgresql-sdbc.mk
@@ -0,0 +1,12 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+$(eval $(call gb_Rdb_Rdb_install,postgresql-sdbc))
+
+# vim: set noet sw=4 ts=4:
diff --git a/connectivity/com/sun/star/sdbcx/comp/hsqldb/NativeInputStreamHelper.java b/connectivity/com/sun/star/sdbcx/comp/hsqldb/NativeInputStreamHelper.java
new file mode 100644
index 0000000000..66b6f54898
--- /dev/null
+++ b/connectivity/com/sun/star/sdbcx/comp/hsqldb/NativeInputStreamHelper.java
@@ -0,0 +1,62 @@
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+package com.sun.star.sdbcx.comp.hsqldb;
+
+public class NativeInputStreamHelper extends java.io.InputStream{
+ private final String key;
+ private final String file;
+ private final StorageNativeInputStream in;
+ /** Creates a new instance of NativeInputStreamHelper */
+ public NativeInputStreamHelper(String key,String _file) {
+ file = _file;
+ this.key = key;
+ in = new StorageNativeInputStream(key,file);
+ }
+
+ @Override
+ public int read() throws java.io.IOException {
+ return in.read(key,file);
+ }
+
+ @Override
+ public int read(byte[] b, int off, int len) throws java.io.IOException {
+ return in.read(key,file,b,off,len);
+ }
+
+ @Override
+ public void close() throws java.io.IOException {
+ in.close(key,file);
+ }
+
+ @Override
+ public long skip(long n) throws java.io.IOException {
+ return in.skip(key,file,n);
+ }
+
+ @Override
+ public int available() throws java.io.IOException {
+ return in.available(key,file);
+ }
+
+ @Override
+ public int read(byte[] b) throws java.io.IOException {
+ return in.read(key,file,b);
+ }
+
+}
diff --git a/connectivity/com/sun/star/sdbcx/comp/hsqldb/NativeLibraries.java b/connectivity/com/sun/star/sdbcx/comp/hsqldb/NativeLibraries.java
new file mode 100644
index 0000000000..e8ea8d44ee
--- /dev/null
+++ b/connectivity/com/sun/star/sdbcx/comp/hsqldb/NativeLibraries.java
@@ -0,0 +1,71 @@
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+package com.sun.star.sdbcx.comp.hsqldb;
+
+import java.io.File;
+import java.net.URL;
+import java.net.URLClassLoader;
+
+final class NativeLibraries {
+ public static void load() {
+ if (System.getProperty( "os.name" ).startsWith("Windows")) {
+ loadLibrary("msvcr71");
+ loadLibrary("sal3");
+ loadLibrary("dbtoolsmi");
+ }
+ loadLibrary("hsqldb");
+ }
+
+ private static void loadLibrary(String libname) {
+ // At least on macOS Tiger, System.loadLibrary("hsqldb2") does not
+ // find the hsqldb2 library one directory above sdbc_hsqldb.jar, even
+ // though ".." is on the jar's Class-Path; however, the alternative
+ // code (needing Java 1.5, which is given for macOS Tiger) works
+ // there:
+ try {
+ System.loadLibrary(libname);
+ } catch (UnsatisfiedLinkError e) {
+ ClassLoader cl = NativeLibraries.class.getClassLoader();
+ if (cl instanceof URLClassLoader) {
+ String sysname = System.mapLibraryName(libname);
+ // At least Oracle's 1.7.0_51 now maps to .dylib rather than
+ // .jnilib:
+ if (System.getProperty("os.name").startsWith("Mac")
+ && sysname.endsWith(".dylib"))
+ {
+ sysname
+ = sysname.substring(
+ 0, sysname.length() - "dylib".length())
+ + "jnilib";
+ }
+ URL url = ((URLClassLoader) cl).findResource(sysname);
+ if (url != null) {
+ try {
+ System.load(new File(url.toURI()).getAbsolutePath());
+ } catch (Throwable t) {
+ throw new UnsatisfiedLinkError(
+ e.toString()+ " - " + t.toString());
+ }
+ }
+ }
+ }
+ }
+
+ private NativeLibraries() {}
+}
diff --git a/connectivity/com/sun/star/sdbcx/comp/hsqldb/NativeOutputStreamHelper.java b/connectivity/com/sun/star/sdbcx/comp/hsqldb/NativeOutputStreamHelper.java
new file mode 100644
index 0000000000..6445f24139
--- /dev/null
+++ b/connectivity/com/sun/star/sdbcx/comp/hsqldb/NativeOutputStreamHelper.java
@@ -0,0 +1,60 @@
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+package com.sun.star.sdbcx.comp.hsqldb;
+
+public class NativeOutputStreamHelper extends java.io.OutputStream{
+
+ private final String key;
+ private final String file;
+ private final StorageNativeOutputStream out;
+ /** Creates a new instance of NativeOutputStreamHelper */
+ public NativeOutputStreamHelper(String key,String _file) {
+ file = _file;
+ this.key = key;
+ out = new StorageNativeOutputStream(file,key);
+ }
+
+ @Override
+ public void write(byte[] b, int off, int len) throws java.io.IOException{
+ out.write(key,file,b, off, len);
+ }
+
+ @Override
+ public void write(byte[] b) throws java.io.IOException{
+ out.write(key,file,b);
+ }
+
+ @Override
+ public void close() throws java.io.IOException{
+ out.close(key,file);
+ }
+
+ @Override
+ public void write(int b) throws java.io.IOException{
+ out.write(key,file,b);
+ }
+
+ @Override
+ public void flush() throws java.io.IOException{
+ out.flush(key,file);
+ }
+
+ public void sync() throws java.io.IOException{
+ out.sync(key,file);
+ }
+}
diff --git a/connectivity/com/sun/star/sdbcx/comp/hsqldb/NativeStorageAccess.java b/connectivity/com/sun/star/sdbcx/comp/hsqldb/NativeStorageAccess.java
new file mode 100644
index 0000000000..5a9bc8bb6c
--- /dev/null
+++ b/connectivity/com/sun/star/sdbcx/comp/hsqldb/NativeStorageAccess.java
@@ -0,0 +1,62 @@
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+package com.sun.star.sdbcx.comp.hsqldb;
+
+public class NativeStorageAccess {
+ static { NativeLibraries.load(); }
+
+ public static final int READ = 1;
+ private static final int SEEKABLE = 2;
+ private static final int SEEKABLEREAD = 3;
+ public static final int WRITE = 4;
+ private static final int READWRITE = 7;
+ public static final int TRUNCATE = 8;
+
+ /** Creates a new instance of StorageAccess */
+ public NativeStorageAccess(String name,String _mode,Object key) throws java.io.IOException{
+ try {
+ int mode = NativeStorageAccess.SEEKABLEREAD;
+ if ( _mode.equals("rw") )
+ mode = NativeStorageAccess.READWRITE | NativeStorageAccess.SEEKABLE;
+
+ openStream(name, (String)key, mode);
+ } catch(Exception ex1){
+ java.io.IOException ex2 = new java.io.IOException();
+ ex2.initCause(ex1);
+ throw ex2;
+ }
+ }
+ private native void openStream(String name,String key, int mode);
+ public native void close(String name,String key) throws java.io.IOException;
+
+ public native long getFilePointer(String name,String key) throws java.io.IOException;
+
+ public native long length(String name,String key) throws java.io.IOException;
+
+ public native int read(String name,String key) throws java.io.IOException;
+
+ public native int read(String name,String key,byte[] b, int off, int len) throws java.io.IOException;
+
+
+
+ public native void seek(String name,String key,long position) throws java.io.IOException;
+
+ public native void write(String name,String key,byte[] b, int offset, int length) throws java.io.IOException;
+
+
+}
diff --git a/connectivity/com/sun/star/sdbcx/comp/hsqldb/StorageAccess.java b/connectivity/com/sun/star/sdbcx/comp/hsqldb/StorageAccess.java
new file mode 100644
index 0000000000..6a53d110e6
--- /dev/null
+++ b/connectivity/com/sun/star/sdbcx/comp/hsqldb/StorageAccess.java
@@ -0,0 +1,126 @@
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+package com.sun.star.sdbcx.comp.hsqldb;
+
+@SuppressWarnings("ucd")
+public class StorageAccess implements org.hsqldb.lib.Storage {
+ String key;
+ String name;
+ boolean readonly;
+ NativeStorageAccess access;
+ /** Creates a new instance of StorageAccess */
+ public StorageAccess(String name,Boolean readonly,Object key) throws java.io.IOException{
+ this.key = (String)key;
+ this.name = name;
+ this.readonly = readonly.booleanValue();
+ try {
+ access = new NativeStorageAccess(name,
+ this.readonly ? "r" : "rw"
+ ,key);
+ } catch(Exception ex1){
+ java.io.IOException ex2 = new java.io.IOException();
+ ex2.initCause(ex1);
+ throw ex2;
+ }
+ }
+ public void close() throws java.io.IOException{
+ access.close(name,key);
+ }
+
+ public long getFilePointer() throws java.io.IOException{
+ return access.getFilePointer(name,key);
+ }
+
+ public long length() throws java.io.IOException{
+ return access.length(name,key);
+ }
+
+ public int read() throws java.io.IOException{
+ return access.read(name,key);
+ }
+
+ public void read(byte[] b, int off, int len) throws java.io.IOException{
+ access.read(name,key,b,off,len);
+ }
+
+ // based on the same code that reads an int from the .data file in HSQLDB
+ public int readInt() throws java.io.IOException{
+ byte [] tmp = new byte [4];
+
+ int count = access.read(name,key,tmp,0, 4);
+
+ if (count != 4){
+ throw new java.io.IOException();
+ }
+
+ count = 0;
+ int ch0 = tmp[count++] & 0xff;
+ int ch1 = tmp[count++] & 0xff;
+ int ch2 = tmp[count++] & 0xff;
+ int ch3 = tmp[count] & 0xff;
+
+ return ((ch0 << 24) + (ch1 << 16) + (ch2 << 8) + (ch3));
+ }
+
+ public void seek(long position) throws java.io.IOException{
+ access.seek(name,key,position);
+ }
+
+ public void write(byte[] b, int offset, int length) throws java.io.IOException{
+ access.write(name,key,b,offset,length);
+ }
+
+ public void writeInt(int v) throws java.io.IOException{
+ byte [] oneByte = new byte [4];
+ oneByte[0] = (byte) ((v >>> 24) & 0xFF);
+ oneByte[1] = (byte) ((v >>> 16) & 0xFF);
+ oneByte[2] = (byte) ((v >>> 8) & 0xFF);
+ oneByte[3] = (byte) ((v >>> 0) & 0xFF);
+
+ write(oneByte,0,4);
+ }
+
+ public boolean isReadOnly() {
+ return readonly;
+ }
+
+ @SuppressWarnings("cast")
+ public long readLong() throws java.io.IOException {
+ return (((long) readInt()) << 32) + (((long) readInt()) & 0xFFFFFFFFL);
+ }
+
+ public boolean wasNio() {
+ return false;
+ }
+
+ public void writeLong(long v) throws java.io.IOException {
+ byte [] oneByte = new byte [8];
+
+ oneByte[0] = (byte) ((v >>> 56) & 0xFF);
+ oneByte[1] = (byte) ((v >>> 48) & 0xFF);
+ oneByte[2] = (byte) ((v >>> 40) & 0xFF);
+ oneByte[3] = (byte) ((v >>> 32) & 0xFF);
+ oneByte[4] = (byte) ((v >>> 24) & 0xFF);
+ oneByte[5] = (byte) ((v >>> 16) & 0xFF);
+ oneByte[6] = (byte) ((v >>> 8) & 0xFF);
+ oneByte[7] = (byte) ((v >>> 0) & 0xFF);
+
+ write(oneByte,0,8);
+ }
+}
diff --git a/connectivity/com/sun/star/sdbcx/comp/hsqldb/StorageFileAccess.java b/connectivity/com/sun/star/sdbcx/comp/hsqldb/StorageFileAccess.java
new file mode 100644
index 0000000000..0dd640c4ec
--- /dev/null
+++ b/connectivity/com/sun/star/sdbcx/comp/hsqldb/StorageFileAccess.java
@@ -0,0 +1,90 @@
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+package com.sun.star.sdbcx.comp.hsqldb;
+
+import org.hsqldb.lib.FileAccess;
+import org.hsqldb.lib.FileSystemRuntimeException;
+
+@SuppressWarnings("ucd")
+public class StorageFileAccess implements org.hsqldb.lib.FileAccess{
+ static { NativeLibraries.load(); }
+
+ String ds_name;
+ String key;
+ /** Creates a new instance of StorageFileAccess */
+ public StorageFileAccess(Object key) throws java.lang.Exception{
+ this.key = (String)key;
+ }
+
+ public void createParentDirs(String filename) {
+ }
+
+ public boolean isStreamElement(String elementName) {
+ return isStreamElement(key,elementName);
+ }
+
+ public java.io.InputStream openInputStreamElement(String streamName) throws java.io.IOException {
+ return new NativeInputStreamHelper(key,streamName);
+ }
+
+ public java.io.OutputStream openOutputStreamElement(String streamName) throws java.io.IOException {
+ return new NativeOutputStreamHelper(key,streamName);
+ }
+
+ public void removeElement(String filename) throws java.util.NoSuchElementException {
+ try {
+ if ( isStreamElement(key,filename) )
+ removeElement(key,filename);
+ } catch (java.io.IOException e) {
+ throw new FileSystemRuntimeException( e );
+ }
+ }
+
+ public void renameElement(String oldName, String newName) throws java.util.NoSuchElementException {
+ try {
+ if ( isStreamElement(key,oldName) ){
+ removeElement(key,newName);
+ renameElement(key,oldName, newName);
+ }
+ } catch (java.io.IOException e) {
+ throw new FileSystemRuntimeException( e );
+ }
+ }
+
+ private static class FileSync implements FileAccess.FileSync
+ {
+ private final NativeOutputStreamHelper os;
+ private FileSync(NativeOutputStreamHelper _os)
+ {
+ os = _os;
+ }
+ public void sync() throws java.io.IOException
+ {
+ os.sync();
+ }
+ }
+
+ public FileAccess.FileSync getFileSync(java.io.OutputStream os) throws java.io.IOException
+ {
+ return new FileSync((NativeOutputStreamHelper)os);
+ }
+
+ static native boolean isStreamElement(String key,String elementName);
+ static native void removeElement(String key,String filename) throws java.util.NoSuchElementException, java.io.IOException;
+ static native void renameElement(String key,String oldName, String newName) throws java.util.NoSuchElementException, java.io.IOException;
+}
diff --git a/connectivity/com/sun/star/sdbcx/comp/hsqldb/StorageNativeInputStream.java b/connectivity/com/sun/star/sdbcx/comp/hsqldb/StorageNativeInputStream.java
new file mode 100644
index 0000000000..cf147c9b50
--- /dev/null
+++ b/connectivity/com/sun/star/sdbcx/comp/hsqldb/StorageNativeInputStream.java
@@ -0,0 +1,34 @@
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+package com.sun.star.sdbcx.comp.hsqldb;
+
+public class StorageNativeInputStream {
+ static { NativeLibraries.load(); }
+
+ /** Creates a new instance of StorageNativeInputStream */
+ public StorageNativeInputStream(String key,String _file) {
+ openStream(key,_file, NativeStorageAccess.READ);
+ }
+ private native void openStream(String key,String name, int mode);
+ public native int read(String key,String name) throws java.io.IOException;
+ public native int read(String key,String name,byte[] b, int off, int len) throws java.io.IOException;
+ public native void close(String key,String name) throws java.io.IOException;
+ public native long skip(String key,String name,long n) throws java.io.IOException;
+ public native int available(String key,String name) throws java.io.IOException;
+ public native int read(String key,String name,byte[] b) throws java.io.IOException;
+}
diff --git a/connectivity/com/sun/star/sdbcx/comp/hsqldb/StorageNativeOutputStream.java b/connectivity/com/sun/star/sdbcx/comp/hsqldb/StorageNativeOutputStream.java
new file mode 100644
index 0000000000..8cc6cb07d3
--- /dev/null
+++ b/connectivity/com/sun/star/sdbcx/comp/hsqldb/StorageNativeOutputStream.java
@@ -0,0 +1,145 @@
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+package com.sun.star.sdbcx.comp.hsqldb;
+
+public class StorageNativeOutputStream {
+ static { NativeLibraries.load(); }
+
+ /** Creates a new instance of StorageNativeOutputStream */
+ public StorageNativeOutputStream(String _name, Object key) {
+ openStream(_name, (String)key, NativeStorageAccess.WRITE | NativeStorageAccess.TRUNCATE);
+ }
+
+ private native void openStream(String name,String key, int mode);
+ /**
+ * Writes <code>len</code> bytes from the specified byte array
+ * starting at offset <code>off</code> to this output stream.
+ * The general contract for <code>write(b, off, len)</code> is that
+ * some of the bytes in the array <code>b</code> are written to the
+ * output stream in order; element <code>b[off]</code> is the first
+ * byte written and <code>b[off+len-1]</code> is the last byte written
+ * by this operation.
+ * <p>
+ * The <code>write</code> method of <code>OutputStream</code> calls
+ * the write method of one argument on each of the bytes to be
+ * written out. Subclasses are encouraged to override this method and
+ * provide a more efficient implementation.
+ * <p>
+ * If <code>b</code> is <code>null</code>, a
+ * <code>NullPointerException</code> is thrown.
+ * <p>
+ * If <code>off</code> is negative, or <code>len</code> is negative, or
+ * <code>off+len</code> is greater than the length of the array
+ * <code>b</code>, then an <tt>IndexOutOfBoundsException</tt> is thrown.
+ * @param key The name of the data source.
+ * @param _file The name of the file to write to.
+ * @param b the data.
+ * @param off the start offset in the data.
+ * @param len the number of bytes to write.
+ * @exception java.io.IOException if an I/O error occurs. In particular,
+ * an <code>IOException</code> is thrown if the output
+ * stream is closed.
+ */
+ public native void write(String key,String _file,byte[] b, int off, int len) throws java.io.IOException;
+
+ /**
+ * Writes <code>b.length</code> bytes from the specified byte array
+ * to this output stream. The general contract for <code>write(b)</code>
+ * is that it should have exactly the same effect as the call
+ * <code>write(b, 0, b.length)</code>.
+ *
+ * @param b the data.
+ * @exception java.io.IOException if an I/O error occurs.
+ * @see java.io.OutputStream#write(byte[], int, int)
+ */
+ public native void write(String key,String _file,byte[] b) throws java.io.IOException;
+
+ /**
+ * Closes this output stream and releases any system resources
+ * associated with this stream. The general contract of <code>close</code>
+ * is that it closes the output stream. A closed stream cannot perform
+ * output operations and cannot be reopened.
+ * <p>
+ * The <code>close</code> method of <code>OutputStream</code> does nothing.
+ * @param key The name of the data source.
+ * @param _file The name of the file to write to.
+ *
+ * @exception java.io.IOException if an I/O error occurs.
+ */
+ public native void close(String key,String _file) throws java.io.IOException;
+
+ /**
+ * Writes the specified byte to this output stream. The general
+ * contract for <code>write</code> is that one byte is written
+ * to the output stream. The byte to be written is the eight
+ * low-order bits of the argument <code>b</code>. The 24
+ * high-order bits of <code>b</code> are ignored.
+ * <p>
+ * Subclasses of <code>OutputStream</code> must provide an
+ * implementation for this method.
+ *
+ * @param key The name of the data source.
+ * @param _file The name of the file to write to.
+ * @param b the <code>byte</code>.
+ * @exception java.io.IOException if an I/O error occurs. In particular,
+ * an <code>IOException</code> may be thrown if the
+ * output stream has been closed.
+ */
+ public native void write(String key,String _file,int b) throws java.io.IOException;
+
+ /**
+ * Flushes this output stream and forces any buffered output bytes
+ * to be written out. The general contract of <code>flush</code> is
+ * that calling it is an indication that, if any bytes previously
+ * written have been buffered by the implementation of the output
+ * stream, such bytes should immediately be written to their
+ * intended destination.
+ * <p>
+ * The <code>flush</code> method of <code>OutputStream</code> does nothing.
+ * @param key The name of the data source.
+ * @param _file The name of the file to write to.
+ *
+ * @exception java.io.IOException if an I/O error occurs.
+ */
+ public native void flush(String key,String _file) throws java.io.IOException;
+
+ /**
+ * Force all system buffers to synchronize with the underlying
+ * device. This method returns after all modified data and
+ * attributes have been written to the relevant device(s).
+ *
+ * sync is meant to be used by code that requires physical
+ * storage (such as a file) to be in a known state For
+ * example, a class that provided a simple transaction facility
+ * might use sync to ensure that all changes to a file caused
+ * by a given transaction were recorded on a storage medium.
+ *
+ * sync only affects buffers downstream. If
+ * any in-memory buffering is being done by the application (for
+ * example, by a BufferedOutputStream object), those buffers must
+ * be flushed (for example, by invoking
+ * OutputStream.flush) before that data will be affected by sync.
+ *
+ * @exception java.io.IOException
+ * Thrown when the buffers cannot be flushed,
+ * or because the system cannot guarantee that all the
+ * buffers have been synchronized with physical media.
+ */
+ public native void sync(String key,String _file) throws java.io.IOException;
+
+}
diff --git a/connectivity/inc/ParameterCont.hxx b/connectivity/inc/ParameterCont.hxx
new file mode 100644
index 0000000000..9e479db920
--- /dev/null
+++ b/connectivity/inc/ParameterCont.hxx
@@ -0,0 +1,48 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <com/sun/star/sdb/XInteractionSupplyParameters.hpp>
+#include <comphelper/interaction.hxx>
+
+namespace dbtools
+{
+
+ //= OParameterContinuation
+
+ class OParameterContinuation final : public comphelper::OInteraction< css::sdb::XInteractionSupplyParameters >
+ {
+ css::uno::Sequence< css::beans::PropertyValue > m_aValues;
+
+ public:
+ OParameterContinuation() { }
+
+ const css::uno::Sequence< css::beans::PropertyValue >& getValues() const { return m_aValues; }
+
+ // XInteractionSupplyParameters
+ virtual void SAL_CALL setParameters( const css::uno::Sequence< css::beans::PropertyValue >& _rValues ) override;
+
+ private:
+ virtual ~OParameterContinuation() override { }
+ OParameterContinuation(const OParameterContinuation&) = delete;
+ void operator =(const OParameterContinuation&) = delete;
+ };
+} // dbtools
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/inc/SQLStatementHelper.hxx b/connectivity/inc/SQLStatementHelper.hxx
new file mode 100644
index 0000000000..0b5ddecf09
--- /dev/null
+++ b/connectivity/inc/SQLStatementHelper.hxx
@@ -0,0 +1,43 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <connectivity/dbtoolsdllapi.hxx>
+#include <rtl/ustrbuf.hxx>
+
+namespace com::sun::star::beans { class XPropertySet; }
+namespace com::sun::star::uno { template <typename > class Reference; }
+
+namespace dbtools
+{
+ class OOO_DLLPUBLIC_DBTOOLS ISQLStatementHelper
+ {
+ public:
+ virtual void addComment(const css::uno::Reference< css::beans::XPropertySet >& descriptor,OUStringBuffer& _rOut) = 0;
+
+ protected:
+ ~ISQLStatementHelper() {}
+ };
+
+
+} // namespace dbtools
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/inc/TIndex.hxx b/connectivity/inc/TIndex.hxx
new file mode 100644
index 0000000000..7523b787e4
--- /dev/null
+++ b/connectivity/inc/TIndex.hxx
@@ -0,0 +1,45 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "sdbcx/VIndex.hxx"
+
+namespace connectivity
+{
+ class OTableHelper;
+ class OIndexHelper final : public connectivity::sdbcx::OIndex
+ {
+ OTableHelper* m_pTable;
+ public:
+ virtual void refreshColumns() override;
+ public:
+ OIndexHelper( OTableHelper* _pTable);
+ OIndexHelper( OTableHelper* _pTable,
+ const OUString& Name,
+ const OUString& Catalog,
+ bool _isUnique,
+ bool _isPrimaryKeyIndex,
+ bool _isClustered
+ );
+ OTableHelper* getTable() const { return m_pTable; }
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/inc/TIndexColumns.hxx b/connectivity/inc/TIndexColumns.hxx
new file mode 100644
index 0000000000..6d02c445ed
--- /dev/null
+++ b/connectivity/inc/TIndexColumns.hxx
@@ -0,0 +1,40 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <connectivity/sdbcx/VCollection.hxx>
+
+namespace connectivity
+{
+ class OIndexHelper;
+ class OIndexColumns final : public sdbcx::OCollection
+ {
+ OIndexHelper* m_pIndex;
+ virtual sdbcx::ObjectType createObject(const OUString& _rName) override;
+ virtual css::uno::Reference< css::beans::XPropertySet > createDescriptor() override;
+ virtual void impl_refresh() override;
+ public:
+ OIndexColumns( OIndexHelper* _pIndex,
+ ::osl::Mutex& _rMutex,
+ const ::std::vector< OUString> &_rVector);
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/inc/TKey.hxx b/connectivity/inc/TKey.hxx
new file mode 100644
index 0000000000..d7c762e308
--- /dev/null
+++ b/connectivity/inc/TKey.hxx
@@ -0,0 +1,43 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "sdbcx/VKey.hxx"
+
+namespace connectivity
+{
+ class OTableHelper;
+ class OTableKeyHelper final : public connectivity::sdbcx::OKey
+ {
+ OTableHelper* m_pTable;
+ public:
+ virtual void refreshColumns() override;
+ public:
+ OTableKeyHelper( OTableHelper* _pTable);
+ OTableKeyHelper( OTableHelper* _pTable
+ ,const OUString& Name
+ ,const std::shared_ptr<sdbcx::KeyProperties>& _rProps
+ );
+ OTableHelper* getTable() const { return m_pTable; }
+ };
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/inc/TKeyColumns.hxx b/connectivity/inc/TKeyColumns.hxx
new file mode 100644
index 0000000000..19510e4965
--- /dev/null
+++ b/connectivity/inc/TKeyColumns.hxx
@@ -0,0 +1,40 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <connectivity/sdbcx/VCollection.hxx>
+
+namespace connectivity
+{
+ class OTableKeyHelper;
+ class OKeyColumnsHelper final : public connectivity::sdbcx::OCollection
+ {
+ OTableKeyHelper* m_pKey;
+ virtual sdbcx::ObjectType createObject(const OUString& _rName) override;
+ virtual css::uno::Reference< css::beans::XPropertySet > createDescriptor() override;
+ virtual void impl_refresh() override;
+ public:
+ OKeyColumnsHelper( OTableKeyHelper* _pKey,
+ ::osl::Mutex& _rMutex,
+ const ::std::vector< OUString> &_rVector);
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/inc/bitmaps.hlst b/connectivity/inc/bitmaps.hlst
new file mode 100644
index 0000000000..e2bf53892d
--- /dev/null
+++ b/connectivity/inc/bitmaps.hlst
@@ -0,0 +1,14 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#define LINKED_TEXT_TABLE_IMAGE_RESOURCE "dbaccess/res/linked_text_table.png"
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/connectivity/inc/pch/precompiled_ado.cxx b/connectivity/inc/pch/precompiled_ado.cxx
new file mode 100644
index 0000000000..6798d4b410
--- /dev/null
+++ b/connectivity/inc/pch/precompiled_ado.cxx
@@ -0,0 +1,12 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "precompiled_ado.hxx"
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/inc/pch/precompiled_ado.hxx b/connectivity/inc/pch/precompiled_ado.hxx
new file mode 100644
index 0000000000..90be947c2e
--- /dev/null
+++ b/connectivity/inc/pch/precompiled_ado.hxx
@@ -0,0 +1,114 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+/*
+ This file has been autogenerated by update_pch.sh. It is possible to edit it
+ manually (such as when an include file has been moved/renamed/removed). All such
+ manual changes will be rewritten by the next run of update_pch.sh (which presumably
+ also fixes all possible problems, so it's usually better to use it).
+
+ Generated on 2021-04-11 19:47:44 using:
+ ./bin/update_pch connectivity ado --cutoff=2 --exclude:system --exclude:module --exclude:local
+
+ If after updating build fails, use the following command to locate conflicting headers:
+ ./bin/update_pch_bisect ./connectivity/inc/pch/precompiled_ado.hxx "make connectivity.build" --find-conflicts
+*/
+
+#include <sal/config.h>
+#if PCH_LEVEL >= 1
+#include <algorithm>
+#include <cassert>
+#include <cstddef>
+#include <cstdlib>
+#include <limits>
+#include <map>
+#include <oledb.h>
+#include <sstream>
+#include <string>
+#include <string_view>
+#include <vector>
+#endif // PCH_LEVEL >= 1
+#if PCH_LEVEL >= 2
+#include <osl/diagnose.h>
+#include <osl/file.hxx>
+#include <osl/mutex.hxx>
+#include <osl/thread.h>
+#include <osl/time.h>
+#include <rtl/alloc.h>
+#include <rtl/ref.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <rtl/ustring.hxx>
+#include <sal/detail/log.h>
+#include <sal/log.hxx>
+#include <sal/macros.h>
+#include <sal/saldllapi.h>
+#include <sal/types.h>
+#endif // PCH_LEVEL >= 2
+#if PCH_LEVEL >= 3
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/sdbc/ColumnValue.hpp>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <com/sun/star/sdbc/FetchDirection.hpp>
+#include <com/sun/star/sdbc/IndexType.hpp>
+#include <com/sun/star/sdbc/KeyRule.hpp>
+#include <com/sun/star/sdbc/ProcedureResult.hpp>
+#include <com/sun/star/sdbc/ResultSetConcurrency.hpp>
+#include <com/sun/star/sdbc/ResultSetType.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <com/sun/star/sdbc/SQLWarning.hpp>
+#include <com/sun/star/sdbc/TransactionIsolation.hpp>
+#include <com/sun/star/sdbc/XCloseable.hpp>
+#include <com/sun/star/sdbc/XColumnLocate.hpp>
+#include <com/sun/star/sdbc/XDatabaseMetaData.hpp>
+#include <com/sun/star/sdbc/XResultSet.hpp>
+#include <com/sun/star/sdbc/XResultSetMetaData.hpp>
+#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
+#include <com/sun/star/sdbc/XResultSetUpdate.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XRowUpdate.hpp>
+#include <com/sun/star/sdbc/XWarningsSupplier.hpp>
+#include <com/sun/star/sdbcx/KeyType.hpp>
+#include <com/sun/star/sdbcx/PrivilegeObject.hpp>
+#include <com/sun/star/uno/Sequence.hxx>
+#include <com/sun/star/util/Date.hpp>
+#include <com/sun/star/util/XCancellable.hpp>
+#include <comphelper/proparrhlp.hxx>
+#include <comphelper/property.hxx>
+#include <comphelper/seqstream.hxx>
+#include <comphelper/sequence.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <comphelper/types.hxx>
+#include <cppuhelper/basemutex.hxx>
+#include <cppuhelper/compbase.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/queryinterface.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <cppuhelper/typeprovider.hxx>
+#include <resource/sharedresources.hxx>
+#include <salhelper/singletonref.hxx>
+#endif // PCH_LEVEL >= 3
+#if PCH_LEVEL >= 4
+#include <OColumn.hxx>
+#include <TConnection.hxx>
+#include <connectivity/CommonTools.hxx>
+#include <connectivity/dbexception.hxx>
+#include <connectivity/dbtools.hxx>
+#include <connectivity/dbtoolsdllapi.hxx>
+#include <connectivity/sdbcx/IRefreshable.hxx>
+#include <connectivity/sdbcx/VCollection.hxx>
+#endif // PCH_LEVEL >= 4
+
+// Cleanup windows header macro pollution.
+#if defined(_WIN32) && defined(WINAPI)
+#include <postwin.h>
+#undef RGB
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/inc/pch/precompiled_calc.cxx b/connectivity/inc/pch/precompiled_calc.cxx
new file mode 100644
index 0000000000..4258091558
--- /dev/null
+++ b/connectivity/inc/pch/precompiled_calc.cxx
@@ -0,0 +1,12 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "precompiled_calc.hxx"
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/inc/pch/precompiled_calc.hxx b/connectivity/inc/pch/precompiled_calc.hxx
new file mode 100644
index 0000000000..ff6ff7ed81
--- /dev/null
+++ b/connectivity/inc/pch/precompiled_calc.hxx
@@ -0,0 +1,76 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+/*
+ This file has been autogenerated by update_pch.sh. It is possible to edit it
+ manually (such as when an include file has been moved/renamed/removed). All such
+ manual changes will be rewritten by the next run of update_pch.sh (which presumably
+ also fixes all possible problems, so it's usually better to use it).
+
+ Generated on 2021-03-08 13:12:43 using:
+ ./bin/update_pch connectivity calc --cutoff=2 --exclude:system --exclude:module --exclude:local
+
+ If after updating build fails, use the following command to locate conflicting headers:
+ ./bin/update_pch_bisect ./connectivity/inc/pch/precompiled_calc.hxx "make connectivity.build" --find-conflicts
+*/
+
+#include <sal/config.h>
+#if PCH_LEVEL >= 1
+#include <cassert>
+#include <cstddef>
+#include <cstring>
+#include <limits>
+#include <new>
+#include <string_view>
+#endif // PCH_LEVEL >= 1
+#if PCH_LEVEL >= 2
+#include <rtl/alloc.h>
+#include <rtl/instance.hxx>
+#include <rtl/math.hxx>
+#include <rtl/stringconcat.hxx>
+#include <rtl/stringutils.hxx>
+#include <rtl/textenc.h>
+#include <rtl/ustrbuf.h>
+#include <rtl/ustrbuf.hxx>
+#include <rtl/ustring.hxx>
+#include <rtl/uuid.h>
+#include <sal/log.hxx>
+#include <sal/types.h>
+#endif // PCH_LEVEL >= 2
+#if PCH_LEVEL >= 3
+#include <calc/CCatalog.hxx>
+#include <calc/CConnection.hxx>
+#include <calc/CDatabaseMetaData.hxx>
+#include <calc/CDriver.hxx>
+#include <calc/CTable.hxx>
+#include <calc/CTables.hxx>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <com/sun/star/sdbc/XResultSet.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sheet/XCellRangeAddressable.hpp>
+#include <com/sun/star/sheet/XDatabaseRange.hpp>
+#include <com/sun/star/sheet/XDatabaseRanges.hpp>
+#include <com/sun/star/sheet/XSpreadsheet.hpp>
+#include <com/sun/star/sheet/XSpreadsheetDocument.hpp>
+#include <com/sun/star/uno/Sequence.hxx>
+#include <cppuhelper/basemutex.hxx>
+#include <cppuhelper/compbase.hxx>
+#include <cppuhelper/cppuhelperdllapi.h>
+#include <file/filedllapi.hxx>
+#include <resource/sharedresources.hxx>
+#include <tools/toolsdllapi.h>
+#endif // PCH_LEVEL >= 3
+#if PCH_LEVEL >= 4
+#include <connectivity/CommonTools.hxx>
+#include <connectivity/dbexception.hxx>
+#include <connectivity/dbtoolsdllapi.hxx>
+#endif // PCH_LEVEL >= 4
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/inc/pch/precompiled_dbase.cxx b/connectivity/inc/pch/precompiled_dbase.cxx
new file mode 100644
index 0000000000..244f98557a
--- /dev/null
+++ b/connectivity/inc/pch/precompiled_dbase.cxx
@@ -0,0 +1,12 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "precompiled_dbase.hxx"
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/inc/pch/precompiled_dbase.hxx b/connectivity/inc/pch/precompiled_dbase.hxx
new file mode 100644
index 0000000000..bef5dafcd9
--- /dev/null
+++ b/connectivity/inc/pch/precompiled_dbase.hxx
@@ -0,0 +1,231 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+/*
+ This file has been autogenerated by update_pch.sh. It is possible to edit it
+ manually (such as when an include file has been moved/renamed/removed). All such
+ manual changes will be rewritten by the next run of update_pch.sh (which presumably
+ also fixes all possible problems, so it's usually better to use it).
+
+ Generated on 2021-04-08 13:55:37 using:
+ ./bin/update_pch connectivity dbase --cutoff=2 --exclude:system --include:module --include:local
+
+ If after updating build fails, use the following command to locate conflicting headers:
+ ./bin/update_pch_bisect ./connectivity/inc/pch/precompiled_dbase.hxx "make connectivity.build" --find-conflicts
+*/
+
+#include <sal/config.h>
+#if PCH_LEVEL >= 1
+#include <algorithm>
+#include <cassert>
+#include <chrono>
+#include <cstddef>
+#include <cstdlib>
+#include <cstring>
+#include <functional>
+#include <initializer_list>
+#include <iomanip>
+#include <limits>
+#include <map>
+#include <math.h>
+#include <memory>
+#include <new>
+#include <optional>
+#include <ostream>
+#include <stack>
+#include <stddef.h>
+#include <string.h>
+#include <string>
+#include <string_view>
+#include <type_traits>
+#include <utility>
+#include <vector>
+#endif // PCH_LEVEL >= 1
+#if PCH_LEVEL >= 2
+#include <osl/diagnose.h>
+#include <osl/doublecheckedlocking.h>
+#include <osl/endian.h>
+#include <osl/file.h>
+#include <osl/file.hxx>
+#include <osl/getglobalmutex.hxx>
+#include <osl/interlck.h>
+#include <osl/mutex.h>
+#include <osl/mutex.hxx>
+#include <osl/time.h>
+#include <rtl/alloc.h>
+#include <rtl/instance.hxx>
+#include <rtl/math.h>
+#include <rtl/math.hxx>
+#include <rtl/ref.hxx>
+#include <rtl/strbuf.h>
+#include <rtl/strbuf.hxx>
+#include <rtl/string.h>
+#include <rtl/string.hxx>
+#include <rtl/stringconcat.hxx>
+#include <rtl/stringutils.hxx>
+#include <rtl/textcvt.h>
+#include <rtl/textenc.h>
+#include <rtl/ustrbuf.h>
+#include <rtl/ustrbuf.hxx>
+#include <rtl/ustring.h>
+#include <rtl/ustring.hxx>
+#include <sal/detail/log.h>
+#include <sal/log.hxx>
+#include <sal/macros.h>
+#include <sal/mathconf.h>
+#include <sal/saldllapi.h>
+#include <sal/types.h>
+#include <sal/typesizes.h>
+#include <vcl/dllapi.h>
+#include <comphelper/errcode.hxx>
+#endif // PCH_LEVEL >= 2
+#if PCH_LEVEL >= 3
+#include <com/sun/star/beans/Property.hpp>
+#include <com/sun/star/beans/PropertyState.hpp>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/beans/XFastPropertySet.hpp>
+#include <com/sun/star/beans/XMultiPropertySet.hpp>
+#include <com/sun/star/beans/XPropertiesChangeListener.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/beans/XPropertySetOption.hpp>
+#include <com/sun/star/beans/XPropertyState.hpp>
+#include <com/sun/star/beans/XVetoableChangeListener.hpp>
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <com/sun/star/lang/EventObject.hpp>
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+#include <com/sun/star/lang/Locale.hpp>
+#include <com/sun/star/lang/XComponent.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/lang/XTypeProvider.hpp>
+#include <com/sun/star/lang/XUnoTunnel.hpp>
+#include <com/sun/star/sdbc/ColumnValue.hpp>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <com/sun/star/sdbc/XCloseable.hpp>
+#include <com/sun/star/sdbc/XColumnLocate.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <com/sun/star/sdbc/XResultSet.hpp>
+#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XWarningsSupplier.hpp>
+#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
+#include <com/sun/star/sdbcx/XGroupsSupplier.hpp>
+#include <com/sun/star/sdbcx/XTablesSupplier.hpp>
+#include <com/sun/star/sdbcx/XUsersSupplier.hpp>
+#include <com/sun/star/sdbcx/XViewsSupplier.hpp>
+#include <com/sun/star/ucb/XContent.hpp>
+#include <com/sun/star/ucb/XDynamicResultSet.hpp>
+#include <com/sun/star/uno/Any.h>
+#include <com/sun/star/uno/Any.hxx>
+#include <com/sun/star/uno/Reference.h>
+#include <com/sun/star/uno/Reference.hxx>
+#include <com/sun/star/uno/RuntimeException.hpp>
+#include <com/sun/star/uno/Sequence.h>
+#include <com/sun/star/uno/Sequence.hxx>
+#include <com/sun/star/uno/Type.h>
+#include <com/sun/star/uno/Type.hxx>
+#include <com/sun/star/uno/TypeClass.hdl>
+#include <com/sun/star/uno/TypeClass.hpp>
+#include <com/sun/star/uno/XAggregation.hpp>
+#include <com/sun/star/uno/XInterface.hpp>
+#include <com/sun/star/uno/XWeak.hpp>
+#include <com/sun/star/uno/genfunc.h>
+#include <com/sun/star/uno/genfunc.hxx>
+#include <com/sun/star/util/Date.hpp>
+#include <com/sun/star/util/XCancellable.hpp>
+#include <comphelper/broadcasthelper.hxx>
+#include <comphelper/comphelperdllapi.h>
+#include <comphelper/extract.hxx>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/propagg.hxx>
+#include <comphelper/proparrhlp.hxx>
+#include <comphelper/propertycontainer.hxx>
+#include <comphelper/propertycontainerhelper.hxx>
+#include <comphelper/propstate.hxx>
+#include <comphelper/sequence.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <comphelper/stl_types.hxx>
+#include <comphelper/types.hxx>
+#include <comphelper/uno3.hxx>
+#include <cppu/cppudllapi.h>
+#include <cppu/unotype.hxx>
+#include <cppuhelper/basemutex.hxx>
+#include <cppuhelper/compbase.hxx>
+#include <cppuhelper/compbase_ex.hxx>
+#include <cppuhelper/cppuhelperdllapi.h>
+#include <cppuhelper/exc_hlp.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/implbase_ex.hxx>
+#include <cppuhelper/implbase_ex_post.hxx>
+#include <cppuhelper/implbase_ex_pre.hxx>
+#include <cppuhelper/interfacecontainer.h>
+#include <cppuhelper/propshlp.hxx>
+#include <cppuhelper/proptypehlp.h>
+#include <cppuhelper/proptypehlp.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <cppuhelper/typeprovider.hxx>
+#include <cppuhelper/weak.hxx>
+#include <cppuhelper/weakagg.hxx>
+#include <cppuhelper/weakref.hxx>
+#include <dbase/DCatalog.hxx>
+#include <dbase/DColumns.hxx>
+#include <dbase/DConnection.hxx>
+#include <dbase/DDatabaseMetaData.hxx>
+#include <dbase/DDriver.hxx>
+#include <dbase/DIndex.hxx>
+#include <dbase/DIndexColumns.hxx>
+#include <dbase/DIndexIter.hxx>
+#include <dbase/DIndexes.hxx>
+#include <dbase/DPreparedStatement.hxx>
+#include <dbase/DResultSet.hxx>
+#include <dbase/DStatement.hxx>
+#include <dbase/DTable.hxx>
+#include <dbase/DTables.hxx>
+#include <file/fcode.hxx>
+#include <file/filedllapi.hxx>
+#include <o3tl/safeint.hxx>
+#include <o3tl/typed_flags_set.hxx>
+#include <o3tl/underlyingenumvalue.hxx>
+#include <resource/sharedresources.hxx>
+#include <salhelper/salhelperdllapi.h>
+#include <salhelper/simplereferenceobject.hxx>
+#include <sdbcx/VCatalog.hxx>
+#include <svl/svldllapi.h>
+#include <tools/config.hxx>
+#include <tools/lineend.hxx>
+#include <tools/long.hxx>
+#include <tools/ref.hxx>
+#include <tools/stream.hxx>
+#include <tools/toolsdllapi.h>
+#include <typelib/typeclass.h>
+#include <typelib/typedescription.h>
+#include <typelib/uik.h>
+#include <ucbhelper/content.hxx>
+#include <uno/any2.h>
+#include <uno/data.h>
+#include <uno/sequence2.h>
+#include <unotools/sharedunocomponent.hxx>
+#include <unotools/ucbhelper.hxx>
+#include <unotools/unotoolsdllapi.h>
+#endif // PCH_LEVEL >= 3
+#if PCH_LEVEL >= 4
+#include <TConnection.hxx>
+#include <connectivity/CommonTools.hxx>
+#include <connectivity/FValue.hxx>
+#include <connectivity/IParseContext.hxx>
+#include <connectivity/dbexception.hxx>
+#include <connectivity/dbtoolsdllapi.hxx>
+#include <connectivity/sdbcx/IRefreshable.hxx>
+#include <connectivity/sdbcx/VColumn.hxx>
+#include <connectivity/sqliterator.hxx>
+#include <propertyids.hxx>
+#endif // PCH_LEVEL >= 4
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/inc/pch/precompiled_dbpool2.cxx b/connectivity/inc/pch/precompiled_dbpool2.cxx
new file mode 100644
index 0000000000..297c81f04e
--- /dev/null
+++ b/connectivity/inc/pch/precompiled_dbpool2.cxx
@@ -0,0 +1,12 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "precompiled_dbpool2.hxx"
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/inc/pch/precompiled_dbpool2.hxx b/connectivity/inc/pch/precompiled_dbpool2.hxx
new file mode 100644
index 0000000000..39808df459
--- /dev/null
+++ b/connectivity/inc/pch/precompiled_dbpool2.hxx
@@ -0,0 +1,93 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+/*
+ This file has been autogenerated by update_pch.sh. It is possible to edit it
+ manually (such as when an include file has been moved/renamed/removed). All such
+ manual changes will be rewritten by the next run of update_pch.sh (which presumably
+ also fixes all possible problems, so it's usually better to use it).
+
+ Generated on 2021-03-08 13:12:45 using:
+ ./bin/update_pch connectivity dbpool2 --cutoff=5 --exclude:system --include:module --exclude:local
+
+ If after updating build fails, use the following command to locate conflicting headers:
+ ./bin/update_pch_bisect ./connectivity/inc/pch/precompiled_dbpool2.hxx "make connectivity.build" --find-conflicts
+*/
+
+#include <sal/config.h>
+#if PCH_LEVEL >= 1
+#include <algorithm>
+#include <cassert>
+#include <cstddef>
+#include <cstdlib>
+#include <cstring>
+#include <initializer_list>
+#include <iomanip>
+#include <limits>
+#include <new>
+#include <ostream>
+#include <stddef.h>
+#include <string.h>
+#include <string>
+#include <string_view>
+#include <type_traits>
+#include <utility>
+#endif // PCH_LEVEL >= 1
+#if PCH_LEVEL >= 2
+#include <osl/diagnose.h>
+#include <osl/interlck.h>
+#include <osl/mutex.h>
+#include <osl/mutex.hxx>
+#include <rtl/alloc.h>
+#include <rtl/ref.hxx>
+#include <rtl/string.h>
+#include <rtl/string.hxx>
+#include <rtl/stringconcat.hxx>
+#include <rtl/stringutils.hxx>
+#include <rtl/textcvt.h>
+#include <rtl/textenc.h>
+#include <rtl/ustrbuf.h>
+#include <rtl/ustrbuf.hxx>
+#include <rtl/ustring.h>
+#include <rtl/ustring.hxx>
+#include <sal/log.hxx>
+#include <sal/macros.h>
+#include <sal/saldllapi.h>
+#include <sal/types.h>
+#include <sal/typesizes.h>
+#endif // PCH_LEVEL >= 2
+#if PCH_LEVEL >= 3
+#include <com/sun/star/uno/Any.h>
+#include <com/sun/star/uno/Any.hxx>
+#include <com/sun/star/uno/Reference.h>
+#include <com/sun/star/uno/Reference.hxx>
+#include <com/sun/star/uno/RuntimeException.hpp>
+#include <com/sun/star/uno/Type.h>
+#include <com/sun/star/uno/Type.hxx>
+#include <com/sun/star/uno/TypeClass.hdl>
+#include <com/sun/star/uno/XInterface.hpp>
+#include <com/sun/star/uno/XWeak.hpp>
+#include <com/sun/star/uno/genfunc.h>
+#include <com/sun/star/uno/genfunc.hxx>
+#include <cppu/cppudllapi.h>
+#include <cppu/unotype.hxx>
+#include <cppuhelper/cppuhelperdllapi.h>
+#include <cppuhelper/weakref.hxx>
+#include <salhelper/simplereferenceobject.hxx>
+#include <typelib/typeclass.h>
+#include <typelib/typedescription.h>
+#include <typelib/uik.h>
+#include <uno/any2.h>
+#include <uno/data.h>
+#include <uno/sequence2.h>
+#endif // PCH_LEVEL >= 3
+#if PCH_LEVEL >= 4
+#endif // PCH_LEVEL >= 4
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/inc/pch/precompiled_dbtools.cxx b/connectivity/inc/pch/precompiled_dbtools.cxx
new file mode 100644
index 0000000000..a4d00e7610
--- /dev/null
+++ b/connectivity/inc/pch/precompiled_dbtools.cxx
@@ -0,0 +1,12 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "precompiled_dbtools.hxx"
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/inc/pch/precompiled_dbtools.hxx b/connectivity/inc/pch/precompiled_dbtools.hxx
new file mode 100644
index 0000000000..f848fe094a
--- /dev/null
+++ b/connectivity/inc/pch/precompiled_dbtools.hxx
@@ -0,0 +1,214 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+/*
+ This file has been autogenerated by update_pch.sh. It is possible to edit it
+ manually (such as when an include file has been moved/renamed/removed). All such
+ manual changes will be rewritten by the next run of update_pch.sh (which presumably
+ also fixes all possible problems, so it's usually better to use it).
+
+ Generated on 2021-04-11 19:47:45 using:
+ ./bin/update_pch connectivity dbtools --cutoff=2 --exclude:system --exclude:module --include:local
+
+ If after updating build fails, use the following command to locate conflicting headers:
+ ./bin/update_pch_bisect ./connectivity/inc/pch/precompiled_dbtools.hxx "make connectivity.build" --find-conflicts
+*/
+
+#include <sal/config.h>
+#if PCH_LEVEL >= 1
+#include <algorithm>
+#include <cassert>
+#include <cstddef>
+#include <cstdlib>
+#include <functional>
+#include <iterator>
+#include <limits>
+#include <memory>
+#include <new>
+#include <optional>
+#include <ostream>
+#include <set>
+#include <string.h>
+#include <string_view>
+#include <type_traits>
+#include <utility>
+#include <vector>
+#endif // PCH_LEVEL >= 1
+#if PCH_LEVEL >= 2
+#include <osl/diagnose.h>
+#include <osl/mutex.h>
+#include <osl/mutex.hxx>
+#include <osl/thread.h>
+#include <rtl/character.hxx>
+#include <rtl/digest.h>
+#include <rtl/locale.h>
+#include <rtl/math.hxx>
+#include <rtl/process.h>
+#include <rtl/ref.hxx>
+#include <rtl/string.hxx>
+#include <rtl/stringconcat.hxx>
+#include <rtl/stringutils.hxx>
+#include <rtl/tencinfo.h>
+#include <rtl/textenc.h>
+#include <rtl/ustrbuf.hxx>
+#include <rtl/ustring.h>
+#include <rtl/ustring.hxx>
+#include <sal/log.hxx>
+#include <sal/macros.h>
+#include <sal/saldllapi.h>
+#include <sal/types.h>
+#endif // PCH_LEVEL >= 2
+#if PCH_LEVEL >= 3
+#include <com/sun/star/beans/NamedValue.hpp>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/container/XChild.hpp>
+#include <com/sun/star/container/XEnumerationAccess.hpp>
+#include <com/sun/star/container/XIndexAccess.hpp>
+#include <com/sun/star/container/XNamed.hpp>
+#include <com/sun/star/i18n/LocaleData.hpp>
+#include <com/sun/star/io/XInputStream.hpp>
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <com/sun/star/lang/Locale.hpp>
+#include <com/sun/star/lang/XComponent.hpp>
+#include <com/sun/star/lang/XEventListener.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/sdb/BooleanComparisonMode.hpp>
+#include <com/sun/star/sdb/CommandType.hpp>
+#include <com/sun/star/sdb/ErrorCondition.hpp>
+#include <com/sun/star/sdb/ParametersRequest.hpp>
+#include <com/sun/star/sdb/SQLContext.hpp>
+#include <com/sun/star/sdb/XColumn.hpp>
+#include <com/sun/star/sdb/XColumnUpdate.hpp>
+#include <com/sun/star/sdb/XParametersSupplier.hpp>
+#include <com/sun/star/sdb/XQueriesSupplier.hpp>
+#include <com/sun/star/sdb/XSingleSelectQueryComposer.hpp>
+#include <com/sun/star/sdb/tools/XIndexAlteration.hpp>
+#include <com/sun/star/sdb/tools/XKeyAlteration.hpp>
+#include <com/sun/star/sdbc/ColumnValue.hpp>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <com/sun/star/sdbc/DriverManager.hpp>
+#include <com/sun/star/sdbc/KeyRule.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <com/sun/star/sdbc/XBlob.hpp>
+#include <com/sun/star/sdbc/XCloseable.hpp>
+#include <com/sun/star/sdbc/XColumnLocate.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <com/sun/star/sdbc/XDataSource.hpp>
+#include <com/sun/star/sdbc/XDatabaseMetaData.hpp>
+#include <com/sun/star/sdbc/XDatabaseMetaData2.hpp>
+#include <com/sun/star/sdbc/XParameters.hpp>
+#include <com/sun/star/sdbc/XResultSet.hpp>
+#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XRowSet.hpp>
+#include <com/sun/star/sdbc/XWarningsSupplier.hpp>
+#include <com/sun/star/sdbcx/KeyType.hpp>
+#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
+#include <com/sun/star/sdbcx/XDataDefinitionSupplier.hpp>
+#include <com/sun/star/sdbcx/XDataDescriptorFactory.hpp>
+#include <com/sun/star/sdbcx/XGroupsSupplier.hpp>
+#include <com/sun/star/sdbcx/XKeysSupplier.hpp>
+#include <com/sun/star/sdbcx/XTablesSupplier.hpp>
+#include <com/sun/star/sdbcx/XUsersSupplier.hpp>
+#include <com/sun/star/task/XInteractionRequest.hpp>
+#include <com/sun/star/uno/Any.hxx>
+#include <com/sun/star/uno/Reference.hxx>
+#include <com/sun/star/uno/Sequence.hxx>
+#include <com/sun/star/uno/XAggregation.hpp>
+#include <com/sun/star/util/Date.hpp>
+#include <com/sun/star/util/DateTime.hpp>
+#include <com/sun/star/util/NumberFormat.hpp>
+#include <com/sun/star/util/NumberFormatter.hpp>
+#include <com/sun/star/util/Time.hpp>
+#include <com/sun/star/util/XCancellable.hpp>
+#include <com/sun/star/util/XNumberFormatTypes.hpp>
+#include <com/sun/star/util/XNumberFormatter.hpp>
+#include <comphelper/IdPropArrayHelper.hxx>
+#include <comphelper/broadcasthelper.hxx>
+#include <comphelper/comphelperdllapi.h>
+#include <comphelper/enumhelper.hxx>
+#include <comphelper/extract.hxx>
+#include <comphelper/numbers.hxx>
+#include <comphelper/proparrhlp.hxx>
+#include <comphelper/property.hxx>
+#include <comphelper/propertycontainer.hxx>
+#include <comphelper/sequence.hxx>
+#include <comphelper/sequenceashashmap.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <comphelper/types.hxx>
+#include <comphelper/uno3.hxx>
+#include <cppuhelper/basemutex.hxx>
+#include <cppuhelper/compbase.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/propshlp.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <cppuhelper/typeprovider.hxx>
+#include <cppuhelper/weak.hxx>
+#include <i18nlangtag/i18nlangtagdllapi.h>
+#include <i18nlangtag/lang.h>
+#include <o3tl/any.hxx>
+#include <o3tl/functional.hxx>
+#include <o3tl/safeint.hxx>
+#include <o3tl/typed_flags_set.hxx>
+#include <o3tl/unreachable.hxx>
+#include <resource/sharedresources.hxx>
+#include <salhelper/simplereferenceobject.hxx>
+#include <sdbcx/VIndexColumn.hxx>
+#include <sdbcx/VKey.hxx>
+#include <sdbcx/VKeyColumn.hxx>
+#include <comphelper/diagnose_ex.hxx>
+#include <tools/toolsdllapi.h>
+#include <unotools/resmgr.hxx>
+#include <unotools/sharedunocomponent.hxx>
+#include <unotools/unotoolsdllapi.h>
+#endif // PCH_LEVEL >= 3
+#if PCH_LEVEL >= 4
+#include <FDatabaseMetaDataResultSet.hxx>
+#include <FDatabaseMetaDataResultSetMetaData.hxx>
+#include <ParameterCont.hxx>
+#include <ParameterSubstitution.hxx>
+#include <RowFunctionParser.hxx>
+#include <TConnection.hxx>
+#include <TIndex.hxx>
+#include <TIndexColumns.hxx>
+#include <TKey.hxx>
+#include <TKeyColumns.hxx>
+#include <connectivity/CommonTools.hxx>
+#include <connectivity/DriversConfig.hxx>
+#include <connectivity/FValue.hxx>
+#include <connectivity/IParseContext.hxx>
+#include <connectivity/PColumn.hxx>
+#include <connectivity/TTableHelper.hxx>
+#include <connectivity/conncleanup.hxx>
+#include <connectivity/dbcharset.hxx>
+#include <connectivity/dbconversion.hxx>
+#include <connectivity/dbexception.hxx>
+#include <connectivity/dbmetadata.hxx>
+#include <connectivity/dbtools.hxx>
+#include <connectivity/dbtoolsdllapi.hxx>
+#include <connectivity/filtermanager.hxx>
+#include <connectivity/internalnode.hxx>
+#include <connectivity/paramwrapper.hxx>
+#include <connectivity/sdbcx/IRefreshable.hxx>
+#include <connectivity/sdbcx/VCollection.hxx>
+#include <connectivity/sdbcx/VColumn.hxx>
+#include <connectivity/sdbcx/VDescriptor.hxx>
+#include <connectivity/sdbcx/VTable.hxx>
+#include <connectivity/sqlerror.hxx>
+#include <connectivity/sqlnode.hxx>
+#include <connectivity/sqlparse.hxx>
+#include <connectivity/statementcomposer.hxx>
+#endif // PCH_LEVEL >= 4
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/inc/pch/precompiled_file.cxx b/connectivity/inc/pch/precompiled_file.cxx
new file mode 100644
index 0000000000..4845c91c4f
--- /dev/null
+++ b/connectivity/inc/pch/precompiled_file.cxx
@@ -0,0 +1,12 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "precompiled_file.hxx"
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/inc/pch/precompiled_file.hxx b/connectivity/inc/pch/precompiled_file.hxx
new file mode 100644
index 0000000000..7d8dee5048
--- /dev/null
+++ b/connectivity/inc/pch/precompiled_file.hxx
@@ -0,0 +1,225 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+/*
+ This file has been autogenerated by update_pch.sh. It is possible to edit it
+ manually (such as when an include file has been moved/renamed/removed). All such
+ manual changes will be rewritten by the next run of update_pch.sh (which presumably
+ also fixes all possible problems, so it's usually better to use it).
+
+ Generated on 2021-04-08 13:55:38 using:
+ ./bin/update_pch connectivity file --cutoff=2 --exclude:system --include:module --exclude:local
+
+ If after updating build fails, use the following command to locate conflicting headers:
+ ./bin/update_pch_bisect ./connectivity/inc/pch/precompiled_file.hxx "make connectivity.build" --find-conflicts
+*/
+
+#include <sal/config.h>
+#if PCH_LEVEL >= 1
+#include <algorithm>
+#include <cassert>
+#include <chrono>
+#include <cstddef>
+#include <cstdlib>
+#include <cstring>
+#include <functional>
+#include <initializer_list>
+#include <iomanip>
+#include <limits>
+#include <map>
+#include <math.h>
+#include <memory>
+#include <new>
+#include <optional>
+#include <ostream>
+#include <set>
+#include <stddef.h>
+#include <string.h>
+#include <string>
+#include <string_view>
+#include <type_traits>
+#include <utility>
+#include <vector>
+#endif // PCH_LEVEL >= 1
+#if PCH_LEVEL >= 2
+#include <osl/diagnose.h>
+#include <osl/doublecheckedlocking.h>
+#include <osl/endian.h>
+#include <osl/getglobalmutex.hxx>
+#include <osl/interlck.h>
+#include <osl/mutex.h>
+#include <osl/mutex.hxx>
+#include <osl/thread.h>
+#include <osl/time.h>
+#include <rtl/alloc.h>
+#include <rtl/instance.hxx>
+#include <rtl/math.h>
+#include <rtl/math.hxx>
+#include <rtl/ref.hxx>
+#include <rtl/strbuf.h>
+#include <rtl/strbuf.hxx>
+#include <rtl/string.h>
+#include <rtl/string.hxx>
+#include <rtl/stringconcat.hxx>
+#include <rtl/stringutils.hxx>
+#include <rtl/tencinfo.h>
+#include <rtl/textcvt.h>
+#include <rtl/textenc.h>
+#include <rtl/ustrbuf.hxx>
+#include <rtl/ustring.h>
+#include <rtl/ustring.hxx>
+#include <sal/log.hxx>
+#include <sal/macros.h>
+#include <sal/mathconf.h>
+#include <sal/saldllapi.h>
+#include <sal/types.h>
+#include <sal/typesizes.h>
+#include <vcl/dllapi.h>
+#include <comphelper/errcode.hxx>
+#endif // PCH_LEVEL >= 2
+#if PCH_LEVEL >= 3
+#include <com/sun/star/beans/Property.hpp>
+#include <com/sun/star/beans/PropertyState.hpp>
+#include <com/sun/star/beans/XFastPropertySet.hpp>
+#include <com/sun/star/beans/XMultiPropertySet.hpp>
+#include <com/sun/star/beans/XPropertiesChangeListener.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/beans/XPropertySetOption.hpp>
+#include <com/sun/star/beans/XPropertyState.hpp>
+#include <com/sun/star/beans/XVetoableChangeListener.hpp>
+#include <com/sun/star/container/XNamed.hpp>
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <com/sun/star/lang/EventObject.hpp>
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+#include <com/sun/star/lang/XComponent.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/lang/XTypeProvider.hpp>
+#include <com/sun/star/lang/XUnoTunnel.hpp>
+#include <com/sun/star/sdb/SQLFilterOperator.hpp>
+#include <com/sun/star/sdbc/ColumnValue.hpp>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <com/sun/star/sdbc/FetchDirection.hpp>
+#include <com/sun/star/sdbc/ResultSetConcurrency.hpp>
+#include <com/sun/star/sdbc/ResultSetType.hpp>
+#include <com/sun/star/sdbc/XResultSet.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
+#include <com/sun/star/sdbcx/XDataDescriptorFactory.hpp>
+#include <com/sun/star/uno/Any.h>
+#include <com/sun/star/uno/Any.hxx>
+#include <com/sun/star/uno/Reference.h>
+#include <com/sun/star/uno/Reference.hxx>
+#include <com/sun/star/uno/RuntimeException.hpp>
+#include <com/sun/star/uno/Sequence.h>
+#include <com/sun/star/uno/Sequence.hxx>
+#include <com/sun/star/uno/Type.h>
+#include <com/sun/star/uno/Type.hxx>
+#include <com/sun/star/uno/TypeClass.hdl>
+#include <com/sun/star/uno/TypeClass.hpp>
+#include <com/sun/star/uno/XAggregation.hpp>
+#include <com/sun/star/uno/XInterface.hpp>
+#include <com/sun/star/uno/XWeak.hpp>
+#include <com/sun/star/uno/genfunc.h>
+#include <com/sun/star/uno/genfunc.hxx>
+#include <com/sun/star/util/Date.hpp>
+#include <com/sun/star/util/DateTime.hpp>
+#include <com/sun/star/util/Time.hpp>
+#include <comphelper/IdPropArrayHelper.hxx>
+#include <comphelper/broadcasthelper.hxx>
+#include <comphelper/comphelperdllapi.h>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/propagg.hxx>
+#include <comphelper/proparrhlp.hxx>
+#include <comphelper/propertycontainer.hxx>
+#include <comphelper/propertycontainerhelper.hxx>
+#include <comphelper/propstate.hxx>
+#include <comphelper/sequence.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <comphelper/stl_types.hxx>
+#include <comphelper/types.hxx>
+#include <comphelper/uno3.hxx>
+#include <component/CColumns.hxx>
+#include <component/CResultSet.hxx>
+#include <cppu/cppudllapi.h>
+#include <cppu/unotype.hxx>
+#include <cppuhelper/basemutex.hxx>
+#include <cppuhelper/compbase.hxx>
+#include <cppuhelper/compbase_ex.hxx>
+#include <cppuhelper/cppuhelperdllapi.h>
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/implbase1.hxx>
+#include <cppuhelper/implbase_ex.hxx>
+#include <cppuhelper/implbase_ex_post.hxx>
+#include <cppuhelper/implbase_ex_pre.hxx>
+#include <cppuhelper/interfacecontainer.h>
+#include <cppuhelper/propshlp.hxx>
+#include <cppuhelper/queryinterface.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <cppuhelper/typeprovider.hxx>
+#include <cppuhelper/weak.hxx>
+#include <cppuhelper/weakagg.hxx>
+#include <cppuhelper/weakref.hxx>
+#include <file/FCatalog.hxx>
+#include <file/FColumns.hxx>
+#include <file/FConnection.hxx>
+#include <file/FDatabaseMetaData.hxx>
+#include <file/FDateFunctions.hxx>
+#include <file/FDriver.hxx>
+#include <file/FNumericFunctions.hxx>
+#include <file/FPreparedStatement.hxx>
+#include <file/FResultSet.hxx>
+#include <file/FResultSetMetaData.hxx>
+#include <file/FStatement.hxx>
+#include <file/FStringFunctions.hxx>
+#include <file/FTable.hxx>
+#include <file/FTables.hxx>
+#include <file/fanalyzer.hxx>
+#include <file/fcode.hxx>
+#include <file/fcomp.hxx>
+#include <file/filedllapi.hxx>
+#include <o3tl/typed_flags_set.hxx>
+#include <o3tl/underlyingenumvalue.hxx>
+#include <resource/sharedresources.hxx>
+#include <salhelper/salhelperdllapi.h>
+#include <salhelper/simplereferenceobject.hxx>
+#include <tools/date.hxx>
+#include <tools/debug.hxx>
+#include <comphelper/diagnose_ex.hxx>
+#include <tools/lineend.hxx>
+#include <tools/long.hxx>
+#include <tools/ref.hxx>
+#include <tools/stream.hxx>
+#include <tools/time.hxx>
+#include <tools/toolsdllapi.h>
+#include <tools/urlobj.hxx>
+#include <typelib/typeclass.h>
+#include <typelib/typedescription.h>
+#include <typelib/uik.h>
+#include <ucbhelper/content.hxx>
+#include <uno/any2.h>
+#include <uno/data.h>
+#include <uno/sequence2.h>
+#include <unotools/options.hxx>
+#include <unotools/unotoolsdllapi.h>
+#endif // PCH_LEVEL >= 3
+#if PCH_LEVEL >= 4
+#include <FDatabaseMetaDataResultSet.hxx>
+#include <connectivity/CommonTools.hxx>
+#include <connectivity/FValue.hxx>
+#include <connectivity/dbconversion.hxx>
+#include <connectivity/dbexception.hxx>
+#include <connectivity/dbmetadata.hxx>
+#include <connectivity/dbtools.hxx>
+#include <connectivity/dbtoolsdllapi.hxx>
+#include <connectivity/sdbcx/VColumn.hxx>
+#include <connectivity/sdbcx/VDescriptor.hxx>
+#include <connectivity/sqlparse.hxx>
+#endif // PCH_LEVEL >= 4
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/inc/pch/precompiled_firebird_sdbc.cxx b/connectivity/inc/pch/precompiled_firebird_sdbc.cxx
new file mode 100644
index 0000000000..777da8c9c3
--- /dev/null
+++ b/connectivity/inc/pch/precompiled_firebird_sdbc.cxx
@@ -0,0 +1,12 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "precompiled_firebird_sdbc.hxx"
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/inc/pch/precompiled_firebird_sdbc.hxx b/connectivity/inc/pch/precompiled_firebird_sdbc.hxx
new file mode 100644
index 0000000000..bd628cf76a
--- /dev/null
+++ b/connectivity/inc/pch/precompiled_firebird_sdbc.hxx
@@ -0,0 +1,75 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+/*
+ This file has been autogenerated by update_pch.sh. It is possible to edit it
+ manually (such as when an include file has been moved/renamed/removed). All such
+ manual changes will be rewritten by the next run of update_pch.sh (which presumably
+ also fixes all possible problems, so it's usually better to use it).
+
+ Generated on 2021-03-08 13:12:28 using:
+ ./bin/update_pch connectivity firebird_sdbc --cutoff=2 --exclude:system --exclude:module --exclude:local
+
+ If after updating build fails, use the following command to locate conflicting headers:
+ ./bin/update_pch_bisect ./connectivity/inc/pch/precompiled_firebird_sdbc.hxx "make connectivity.build" --find-conflicts
+*/
+
+#include <sal/config.h>
+#if PCH_LEVEL >= 1
+#include <cassert>
+#include <cstddef>
+#include <memory>
+#include <string_view>
+#include <vector>
+#endif // PCH_LEVEL >= 1
+#if PCH_LEVEL >= 2
+#include <osl/diagnose.h>
+#include <osl/file.h>
+#include <osl/file.hxx>
+#include <osl/mutex.hxx>
+#include <osl/process.h>
+#include <osl/thread.h>
+#include <osl/time.h>
+#include <rtl/alloc.h>
+#include <rtl/bootstrap.hxx>
+#include <rtl/strbuf.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <rtl/ustring.hxx>
+#include <sal/log.hxx>
+#include <sal/types.h>
+#endif // PCH_LEVEL >= 2
+#if PCH_LEVEL >= 3
+#include <com/sun/star/embed/ElementModes.hpp>
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
+#include <com/sun/star/sdbc/ColumnValue.hpp>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <com/sun/star/sdbc/ResultSetConcurrency.hpp>
+#include <com/sun/star/sdbc/ResultSetType.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <com/sun/star/sdbc/TransactionIsolation.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
+#include <com/sun/star/uno/Reference.hxx>
+#include <comphelper/comphelperdllapi.h>
+#include <comphelper/sequence.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <resource/sharedresources.hxx>
+#include <unotools/localfilehelper.hxx>
+#endif // PCH_LEVEL >= 3
+#if PCH_LEVEL >= 4
+#include <TConnection.hxx>
+#include <connectivity/CommonTools.hxx>
+#include <connectivity/dbexception.hxx>
+#include <connectivity/dbtools.hxx>
+#include <propertyids.hxx>
+#endif // PCH_LEVEL >= 4
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/inc/pch/precompiled_flat.cxx b/connectivity/inc/pch/precompiled_flat.cxx
new file mode 100644
index 0000000000..474aa00da2
--- /dev/null
+++ b/connectivity/inc/pch/precompiled_flat.cxx
@@ -0,0 +1,12 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "precompiled_flat.hxx"
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/inc/pch/precompiled_flat.hxx b/connectivity/inc/pch/precompiled_flat.hxx
new file mode 100644
index 0000000000..73a8ee883b
--- /dev/null
+++ b/connectivity/inc/pch/precompiled_flat.hxx
@@ -0,0 +1,207 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+/*
+ This file has been autogenerated by update_pch.sh. It is possible to edit it
+ manually (such as when an include file has been moved/renamed/removed). All such
+ manual changes will be rewritten by the next run of update_pch.sh (which presumably
+ also fixes all possible problems, so it's usually better to use it).
+
+ Generated on 2021-04-08 13:43:09 using:
+ ./bin/update_pch connectivity flat --cutoff=2 --exclude:system --include:module --include:local
+
+ If after updating build fails, use the following command to locate conflicting headers:
+ ./bin/update_pch_bisect ./connectivity/inc/pch/precompiled_flat.hxx "make connectivity.build" --find-conflicts
+*/
+
+#include <sal/config.h>
+#if PCH_LEVEL >= 1
+#include <algorithm>
+#include <cassert>
+#include <cstddef>
+#include <cstdlib>
+#include <cstring>
+#include <functional>
+#include <initializer_list>
+#include <iomanip>
+#include <limits>
+#include <map>
+#include <math.h>
+#include <memory>
+#include <new>
+#include <ostream>
+#include <stddef.h>
+#include <string.h>
+#include <string>
+#include <string_view>
+#include <type_traits>
+#include <utility>
+#include <vector>
+#endif // PCH_LEVEL >= 1
+#if PCH_LEVEL >= 2
+#include <osl/diagnose.h>
+#include <osl/doublecheckedlocking.h>
+#include <osl/endian.h>
+#include <osl/getglobalmutex.hxx>
+#include <osl/interlck.h>
+#include <osl/mutex.h>
+#include <osl/mutex.hxx>
+#include <rtl/alloc.h>
+#include <rtl/instance.hxx>
+#include <rtl/locale.h>
+#include <rtl/math.h>
+#include <rtl/math.hxx>
+#include <rtl/ref.hxx>
+#include <rtl/strbuf.h>
+#include <rtl/strbuf.hxx>
+#include <rtl/string.h>
+#include <rtl/string.hxx>
+#include <rtl/stringconcat.hxx>
+#include <rtl/stringutils.hxx>
+#include <rtl/textcvt.h>
+#include <rtl/textenc.h>
+#include <rtl/ustrbuf.h>
+#include <rtl/ustrbuf.hxx>
+#include <rtl/ustring.h>
+#include <rtl/ustring.hxx>
+#include <rtl/uuid.h>
+#include <sal/detail/log.h>
+#include <sal/log.hxx>
+#include <sal/macros.h>
+#include <sal/mathconf.h>
+#include <sal/saldllapi.h>
+#include <sal/types.h>
+#include <sal/typesizes.h>
+#endif // PCH_LEVEL >= 2
+#if PCH_LEVEL >= 3
+#include <com/sun/star/beans/Property.hpp>
+#include <com/sun/star/beans/PropertyState.hpp>
+#include <com/sun/star/beans/XFastPropertySet.hpp>
+#include <com/sun/star/beans/XMultiPropertySet.hpp>
+#include <com/sun/star/beans/XPropertiesChangeListener.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/beans/XPropertySetOption.hpp>
+#include <com/sun/star/beans/XPropertyState.hpp>
+#include <com/sun/star/beans/XVetoableChangeListener.hpp>
+#include <com/sun/star/container/XNamed.hpp>
+#include <com/sun/star/i18n/DirectionProperty.hpp>
+#include <com/sun/star/i18n/KCharacterType.hpp>
+#include <com/sun/star/i18n/ParseResult.hpp>
+#include <com/sun/star/i18n/UnicodeScript.hpp>
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <com/sun/star/lang/EventObject.hpp>
+#include <com/sun/star/lang/Locale.hpp>
+#include <com/sun/star/lang/XComponent.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/lang/XTypeProvider.hpp>
+#include <com/sun/star/lang/XUnoTunnel.hpp>
+#include <com/sun/star/sdbc/ColumnValue.hpp>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <com/sun/star/sdbc/XCloseable.hpp>
+#include <com/sun/star/sdbc/XColumnLocate.hpp>
+#include <com/sun/star/sdbc/XDriver.hpp>
+#include <com/sun/star/sdbc/XResultSet.hpp>
+#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XWarningsSupplier.hpp>
+#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
+#include <com/sun/star/sdbcx/XDataDefinitionSupplier.hpp>
+#include <com/sun/star/sdbcx/XDataDescriptorFactory.hpp>
+#include <com/sun/star/sdbcx/XGroupsSupplier.hpp>
+#include <com/sun/star/sdbcx/XTablesSupplier.hpp>
+#include <com/sun/star/sdbcx/XUsersSupplier.hpp>
+#include <com/sun/star/sdbcx/XViewsSupplier.hpp>
+#include <com/sun/star/uno/Any.h>
+#include <com/sun/star/uno/Any.hxx>
+#include <com/sun/star/uno/Reference.h>
+#include <com/sun/star/uno/Reference.hxx>
+#include <com/sun/star/uno/RuntimeException.hpp>
+#include <com/sun/star/uno/Sequence.h>
+#include <com/sun/star/uno/Sequence.hxx>
+#include <com/sun/star/uno/Type.h>
+#include <com/sun/star/uno/Type.hxx>
+#include <com/sun/star/uno/TypeClass.hdl>
+#include <com/sun/star/uno/XAggregation.hpp>
+#include <com/sun/star/uno/XInterface.hpp>
+#include <com/sun/star/uno/XWeak.hpp>
+#include <com/sun/star/uno/genfunc.h>
+#include <com/sun/star/uno/genfunc.hxx>
+#include <com/sun/star/util/Date.hpp>
+#include <com/sun/star/util/DateTime.hpp>
+#include <com/sun/star/util/Time.hpp>
+#include <com/sun/star/util/XCancellable.hpp>
+#include <comphelper/IdPropArrayHelper.hxx>
+#include <comphelper/broadcasthelper.hxx>
+#include <comphelper/comphelperdllapi.h>
+#include <comphelper/propagg.hxx>
+#include <comphelper/proparrhlp.hxx>
+#include <comphelper/propertycontainer.hxx>
+#include <comphelper/propertycontainerhelper.hxx>
+#include <comphelper/propstate.hxx>
+#include <comphelper/sequence.hxx>
+#include <comphelper/stl_types.hxx>
+#include <comphelper/types.hxx>
+#include <comphelper/uno3.hxx>
+#include <cppu/cppudllapi.h>
+#include <cppu/unotype.hxx>
+#include <cppuhelper/basemutex.hxx>
+#include <cppuhelper/compbase.hxx>
+#include <cppuhelper/compbase_ex.hxx>
+#include <cppuhelper/cppuhelperdllapi.h>
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/implbase1.hxx>
+#include <cppuhelper/implbase_ex.hxx>
+#include <cppuhelper/implbase_ex_post.hxx>
+#include <cppuhelper/implbase_ex_pre.hxx>
+#include <cppuhelper/interfacecontainer.h>
+#include <cppuhelper/propshlp.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <cppuhelper/weak.hxx>
+#include <cppuhelper/weakagg.hxx>
+#include <cppuhelper/weakref.hxx>
+#include <file/filedllapi.hxx>
+#include <flat/ECatalog.hxx>
+#include <flat/EColumns.hxx>
+#include <flat/EConnection.hxx>
+#include <flat/EDatabaseMetaData.hxx>
+#include <flat/EDriver.hxx>
+#include <flat/EPreparedStatement.hxx>
+#include <flat/EResultSet.hxx>
+#include <flat/EStatement.hxx>
+#include <flat/ETable.hxx>
+#include <flat/ETables.hxx>
+#include <i18nlangtag/i18nlangtagdllapi.h>
+#include <i18nlangtag/lang.h>
+#include <i18nlangtag/languagetag.hxx>
+#include <o3tl/strong_int.hxx>
+#include <o3tl/typed_flags_set.hxx>
+#include <o3tl/underlyingenumvalue.hxx>
+#include <salhelper/salhelperdllapi.h>
+#include <salhelper/simplereferenceobject.hxx>
+#include <sdbcx/VCatalog.hxx>
+#include <tools/toolsdllapi.h>
+#include <typelib/typeclass.h>
+#include <typelib/typedescription.h>
+#include <typelib/uik.h>
+#include <uno/any2.h>
+#include <uno/data.h>
+#include <uno/sequence2.h>
+#include <unotools/unotoolsdllapi.h>
+#endif // PCH_LEVEL >= 3
+#if PCH_LEVEL >= 4
+#include <connectivity/CommonTools.hxx>
+#include <connectivity/FValue.hxx>
+#include <connectivity/dbexception.hxx>
+#include <connectivity/dbtoolsdllapi.hxx>
+#include <connectivity/sdbcx/IRefreshable.hxx>
+#include <connectivity/sdbcx/VDescriptor.hxx>
+#endif // PCH_LEVEL >= 4
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/inc/pch/precompiled_mysql_jdbc.cxx b/connectivity/inc/pch/precompiled_mysql_jdbc.cxx
new file mode 100644
index 0000000000..1f7782e675
--- /dev/null
+++ b/connectivity/inc/pch/precompiled_mysql_jdbc.cxx
@@ -0,0 +1,12 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "precompiled_mysql_jdbc.hxx"
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/inc/pch/precompiled_mysql_jdbc.hxx b/connectivity/inc/pch/precompiled_mysql_jdbc.hxx
new file mode 100644
index 0000000000..4bb225104c
--- /dev/null
+++ b/connectivity/inc/pch/precompiled_mysql_jdbc.hxx
@@ -0,0 +1,62 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+/*
+ This file has been autogenerated by update_pch.sh. It is possible to edit it
+ manually (such as when an include file has been moved/renamed/removed). All such
+ manual changes will be rewritten by the next run of update_pch.sh (which presumably
+ also fixes all possible problems, so it's usually better to use it).
+
+ Generated on 2021-03-08 13:12:51 using:
+ ./bin/update_pch connectivity mysql_jdbc --cutoff=1 --exclude:system --include:module --include:local
+
+ If after updating build fails, use the following command to locate conflicting headers:
+ ./bin/update_pch_bisect ./connectivity/inc/pch/precompiled_mysql_jdbc.hxx "make connectivity.build" --find-conflicts
+*/
+
+#include <sal/config.h>
+#if PCH_LEVEL >= 1
+#endif // PCH_LEVEL >= 1
+#if PCH_LEVEL >= 2
+#endif // PCH_LEVEL >= 2
+#if PCH_LEVEL >= 3
+#include <com/sun/star/sdbc/DriverManager.hpp>
+#include <com/sun/star/sdbc/XResultSet.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbcx/PrivilegeObject.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <comphelper/namedvaluecollection.hxx>
+#include <comphelper/property.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <comphelper/types.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <cppuhelper/typeprovider.hxx>
+#include <mysql/YCatalog.hxx>
+#include <mysql/YColumns.hxx>
+#include <mysql/YDriver.hxx>
+#include <mysql/YTable.hxx>
+#include <mysql/YTables.hxx>
+#include <mysql/YUser.hxx>
+#include <mysql/YUsers.hxx>
+#include <mysql/YViews.hxx>
+#include <resource/sharedresources.hxx>
+#endif // PCH_LEVEL >= 3
+#if PCH_LEVEL >= 4
+#include <TConnection.hxx>
+#include <connectivity/TIndexes.hxx>
+#include <connectivity/TKeys.hxx>
+#include <connectivity/dbcharset.hxx>
+#include <connectivity/dbexception.hxx>
+#include <connectivity/dbtools.hxx>
+#include <connectivity/sdbcx/IRefreshable.hxx>
+#include <connectivity/sdbcx/VColumn.hxx>
+#include <connectivity/sdbcx/VView.hxx>
+#endif // PCH_LEVEL >= 4
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/inc/pch/precompiled_odbc.cxx b/connectivity/inc/pch/precompiled_odbc.cxx
new file mode 100644
index 0000000000..f55f2ec84c
--- /dev/null
+++ b/connectivity/inc/pch/precompiled_odbc.cxx
@@ -0,0 +1,12 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "precompiled_odbc.hxx"
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/inc/pch/precompiled_odbc.hxx b/connectivity/inc/pch/precompiled_odbc.hxx
new file mode 100644
index 0000000000..719180c13a
--- /dev/null
+++ b/connectivity/inc/pch/precompiled_odbc.hxx
@@ -0,0 +1,90 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+/*
+ This file has been autogenerated by update_pch.sh. It is possible to edit it
+ manually (such as when an include file has been moved/renamed/removed). All such
+ manual changes will be rewritten by the next run of update_pch.sh (which presumably
+ also fixes all possible problems, so it's usually better to use it).
+
+ Generated on 2021-03-08 13:12:40 using:
+ ./bin/update_pch connectivity odbc --cutoff=2 --exclude:system --exclude:module --include:local
+
+ If after updating build fails, use the following command to locate conflicting headers:
+ ./bin/update_pch_bisect ./connectivity/inc/pch/precompiled_odbc.hxx "make connectivity.build" --find-conflicts
+*/
+
+#include <sal/config.h>
+#if PCH_LEVEL >= 1
+#include <string.h>
+#include <vector>
+#endif // PCH_LEVEL >= 1
+#if PCH_LEVEL >= 2
+#include <osl/diagnose.h>
+#include <osl/endian.h>
+#include <rtl/ref.hxx>
+#include <rtl/strbuf.hxx>
+#include <rtl/tencinfo.h>
+#include <rtl/textenc.h>
+#include <rtl/ustrbuf.hxx>
+#include <rtl/ustring.hxx>
+#include <sal/log.hxx>
+#include <sal/types.h>
+#endif // PCH_LEVEL >= 2
+#if PCH_LEVEL >= 3
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <com/sun/star/sdbc/ResultSetConcurrency.hpp>
+#include <com/sun/star/sdbc/ResultSetType.hpp>
+#include <com/sun/star/sdbc/XCloseable.hpp>
+#include <com/sun/star/sdbc/XColumnLocate.hpp>
+#include <com/sun/star/sdbc/XResultSet.hpp>
+#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XWarningsSupplier.hpp>
+#include <com/sun/star/uno/Any.hxx>
+#include <com/sun/star/uno/Sequence.hxx>
+#include <com/sun/star/util/Date.hpp>
+#include <com/sun/star/util/DateTime.hpp>
+#include <com/sun/star/util/Time.hpp>
+#include <com/sun/star/util/XCancellable.hpp>
+#include <comphelper/proparrhlp.hxx>
+#include <comphelper/property.hxx>
+#include <comphelper/propertycontainer.hxx>
+#include <comphelper/sequence.hxx>
+#include <comphelper/types.hxx>
+#include <cppuhelper/basemutex.hxx>
+#include <cppuhelper/compbase.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <cppuhelper/typeprovider.hxx>
+#include <o3tl/safeint.hxx>
+#include <odbc/OConnection.hxx>
+#include <odbc/ODatabaseMetaData.hxx>
+#include <odbc/ODatabaseMetaDataResultSet.hxx>
+#include <odbc/ODriver.hxx>
+#include <odbc/OFunctions.hxx>
+#include <odbc/OPreparedStatement.hxx>
+#include <odbc/OResultSet.hxx>
+#include <odbc/OResultSetMetaData.hxx>
+#include <odbc/OStatement.hxx>
+#include <odbc/OTools.hxx>
+#include <resource/sharedresources.hxx>
+#include <salhelper/simplereferenceobject.hxx>
+#endif // PCH_LEVEL >= 3
+#if PCH_LEVEL >= 4
+#include <FDatabaseMetaDataResultSet.hxx>
+#include <connectivity/CommonTools.hxx>
+#include <connectivity/FValue.hxx>
+#include <connectivity/dbexception.hxx>
+#include <connectivity/dbtools.hxx>
+#include <connectivity/dbtoolsdllapi.hxx>
+#endif // PCH_LEVEL >= 4
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/inc/pch/precompiled_postgresql-sdbc-impl.cxx b/connectivity/inc/pch/precompiled_postgresql-sdbc-impl.cxx
new file mode 100644
index 0000000000..9dbbeaf362
--- /dev/null
+++ b/connectivity/inc/pch/precompiled_postgresql-sdbc-impl.cxx
@@ -0,0 +1,12 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "precompiled_postgresql-sdbc-impl.hxx"
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/inc/pch/precompiled_postgresql-sdbc-impl.hxx b/connectivity/inc/pch/precompiled_postgresql-sdbc-impl.hxx
new file mode 100644
index 0000000000..d94cdcde31
--- /dev/null
+++ b/connectivity/inc/pch/precompiled_postgresql-sdbc-impl.hxx
@@ -0,0 +1,61 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+/*
+ This file has been autogenerated by update_pch.sh. It is possible to edit it
+ manually (such as when an include file has been moved/renamed/removed). All such
+ manual changes will be rewritten by the next run of update_pch.sh (which presumably
+ also fixes all possible problems, so it's usually better to use it).
+
+ Generated on 2021-03-08 13:12:50 using:
+ ./bin/update_pch connectivity postgresql-sdbc-impl --cutoff=3 --exclude:system --exclude:module --exclude:local
+
+ If after updating build fails, use the following command to locate conflicting headers:
+ ./bin/update_pch_bisect ./connectivity/inc/pch/precompiled_postgresql-sdbc-impl.hxx "make connectivity.build" --find-conflicts
+*/
+
+#include <sal/config.h>
+#if PCH_LEVEL >= 1
+#include <string.h>
+#include <string_view>
+#endif // PCH_LEVEL >= 1
+#if PCH_LEVEL >= 2
+#include <osl/time.h>
+#include <rtl/instance.hxx>
+#include <rtl/ref.hxx>
+#include <rtl/strbuf.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <rtl/ustring.hxx>
+#include <rtl/uuid.h>
+#include <sal/log.hxx>
+#include <sal/macros.h>
+#include <sal/types.h>
+#endif // PCH_LEVEL >= 2
+#if PCH_LEVEL >= 3
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
+#include <com/sun/star/sdbc/ColumnValue.hpp>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <com/sun/star/sdbc/ResultSetConcurrency.hpp>
+#include <com/sun/star/sdbc/ResultSetType.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <com/sun/star/sdbc/XParameters.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbcx/KeyType.hpp>
+#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
+#include <comphelper/sequence.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+#include <cppuhelper/queryinterface.hxx>
+#include <cppuhelper/typeprovider.hxx>
+#endif // PCH_LEVEL >= 3
+#if PCH_LEVEL >= 4
+#include <connectivity/dbconversion.hxx>
+#endif // PCH_LEVEL >= 4
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/inc/sdbcx/VCatalog.hxx b/connectivity/inc/sdbcx/VCatalog.hxx
new file mode 100644
index 0000000000..3c87a08700
--- /dev/null
+++ b/connectivity/inc/sdbcx/VCatalog.hxx
@@ -0,0 +1,116 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/sdbcx/XTablesSupplier.hpp>
+#include <com/sun/star/sdbcx/XViewsSupplier.hpp>
+#include <com/sun/star/sdbcx/XUsersSupplier.hpp>
+#include <com/sun/star/sdbcx/XGroupsSupplier.hpp>
+#include <cppuhelper/compbase.hxx>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <connectivity/CommonTools.hxx>
+#include <connectivity/sdbcx/IRefreshable.hxx>
+#include <connectivity/dbtoolsdllapi.hxx>
+#include <memory>
+
+namespace com::sun::star::sdbc { class XConnection; }
+namespace com::sun::star::sdbc { class XDatabaseMetaData; }
+namespace com::sun::star::sdbc { class XResultSet; }
+namespace com::sun::star::sdbc { class XRow; }
+
+namespace connectivity::sdbcx
+ {
+
+ class OCollection;
+ // OCatalog is a general catalog class
+ // other drivers can be derived their catalog from this class when they want to support sdbcx
+ // it holds already tables, views, groups and users
+
+ typedef ::cppu::WeakComponentImplHelper< css::sdbcx::XTablesSupplier,
+ css::sdbcx::XViewsSupplier,
+ css::sdbcx::XUsersSupplier,
+ css::sdbcx::XGroupsSupplier,
+ css::lang::XServiceInfo> OCatalog_BASE;
+
+
+ class OOO_DLLPUBLIC_DBTOOLS SAL_NO_VTABLE OCatalog :
+ public OCatalog_BASE,
+ public IRefreshableGroups,
+ public IRefreshableUsers
+ {
+ protected:
+
+ ::osl::Mutex m_aMutex;
+
+ // this members are deleted when the dtor is called
+ // they are hold weak
+ std::unique_ptr<OCollection> m_pTables;
+ std::unique_ptr<OCollection> m_pViews;
+ std::unique_ptr<OCollection> m_pGroups;
+ std::unique_ptr<OCollection> m_pUsers;
+
+ css::uno::Reference< css::sdbc::XDatabaseMetaData > m_xMetaData; // just to make things easier
+
+ /** builds the name which should be used to access the object later on in the collection.
+ Will only be called in fillNames.
+ @param _xRow
+ The current row from the resultset given to fillNames.
+ */
+ virtual OUString buildName( const css::uno::Reference< css::sdbc::XRow >& _xRow);
+
+ /** fills a vector with the necessary names which can be used in combination with the collections.
+ For each row buildName will be called.
+ @param _xResult
+ The resultset which should be used to fill the names. Will be disposed after return and set to NULL.
+ @param _rNames
+ The vector who will be filled.
+ */
+ void fillNames(css::uno::Reference< css::sdbc::XResultSet >& _xResult,::std::vector< OUString>& _rNames);
+
+ public:
+ OCatalog(const css::uno::Reference< css::sdbc::XConnection> &_xConnection);
+ virtual ~OCatalog() override;
+
+ DECLARE_SERVICE_INFO();
+
+ // refreshTables is called when the method getTables had been called
+ // the member m_pTables has to be created
+ virtual void refreshTables() = 0;
+ // refreshViews is called when the method getViews had been called
+ virtual void refreshViews() = 0;
+
+ // the other refresh methods come from base classes IRefreshableGroups and IRefreshableUsers
+
+ // ::cppu::OComponentHelper
+ virtual void SAL_CALL disposing() override;
+ // XTablesSupplier
+ virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getTables( ) override;
+ // XViewsSupplier
+ virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getViews( ) override;
+ // XUsersSupplier
+ virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getUsers( ) override;
+ // XGroupsSupplier
+ virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getGroups( ) override;
+
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/inc/sdbcx/VGroup.hxx b/connectivity/inc/sdbcx/VGroup.hxx
new file mode 100644
index 0000000000..9c292adc6d
--- /dev/null
+++ b/connectivity/inc/sdbcx/VGroup.hxx
@@ -0,0 +1,95 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/sdbcx/XUsersSupplier.hpp>
+#include <com/sun/star/sdbcx/XAuthorizable.hpp>
+#include <com/sun/star/container/XNamed.hpp>
+#include <comphelper/proparrhlp.hxx>
+#include <cppuhelper/compbase.hxx>
+#include <cppuhelper/basemutex.hxx>
+#include <connectivity/sdbcx/VCollection.hxx>
+#include <connectivity/sdbcx/IRefreshable.hxx>
+#include <connectivity/sdbcx/VDescriptor.hxx>
+#include <connectivity/dbtoolsdllapi.hxx>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+
+namespace connectivity::sdbcx
+ {
+ typedef OCollection OUsers;
+
+ typedef ::cppu::WeakComponentImplHelper< css::sdbcx::XUsersSupplier,
+ css::sdbcx::XAuthorizable,
+ css::container::XNamed,
+ css::lang::XServiceInfo> OGroup_BASE;
+
+ class OOO_DLLPUBLIC_DBTOOLS OGroup :
+ public cppu::BaseMutex,
+ public OGroup_BASE,
+ public IRefreshableUsers,
+ public ::comphelper::OPropertyArrayUsageHelper<OGroup>,
+ public ODescriptor
+ {
+ protected:
+ // no Reference! see OCollection::acquire
+ std::unique_ptr<OUsers> m_pUsers;
+
+ using OGroup_BASE::rBHelper;
+
+ // OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override;
+ // OPropertySetHelper
+ virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override;
+ public:
+ OGroup(bool _bCase);
+ OGroup( const OUString& Name, bool _bCase);
+ virtual ~OGroup() override;
+ DECLARE_SERVICE_INFO();
+
+ // XInterface
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+
+ //XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ //XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override;
+
+ // ::cppu::OComponentHelper
+ virtual void SAL_CALL disposing() override;
+ // XPropertySet
+ virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override;
+ // XUsersSupplier
+ virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getUsers( ) override;
+ // XAuthorizable
+ virtual sal_Int32 SAL_CALL getPrivileges( const OUString& objName, sal_Int32 objType ) override;
+ virtual sal_Int32 SAL_CALL getGrantablePrivileges( const OUString& objName, sal_Int32 objType ) override;
+ virtual void SAL_CALL grantPrivileges( const OUString& objName, sal_Int32 objType, sal_Int32 objPrivileges ) override;
+ virtual void SAL_CALL revokePrivileges( const OUString& objName, sal_Int32 objType, sal_Int32 objPrivileges ) override;
+
+ // XNamed
+ virtual OUString SAL_CALL getName( ) override;
+ virtual void SAL_CALL setName( const OUString& aName ) override;
+ };
+
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/inc/sdbcx/VIndex.hxx b/connectivity/inc/sdbcx/VIndex.hxx
new file mode 100644
index 0000000000..5d597efe3a
--- /dev/null
+++ b/connectivity/inc/sdbcx/VIndex.hxx
@@ -0,0 +1,98 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/sdbcx/XDataDescriptorFactory.hpp>
+#include <comphelper/IdPropArrayHelper.hxx>
+#include <cppuhelper/basemutex.hxx>
+#include <connectivity/CommonTools.hxx>
+#include <sdbcx/VTypeDef.hxx>
+#include <connectivity/sdbcx/IRefreshable.hxx>
+#include <connectivity/sdbcx/VDescriptor.hxx>
+#include <connectivity/dbtoolsdllapi.hxx>
+#include <cppuhelper/implbase1.hxx>
+
+namespace connectivity::sdbcx
+ {
+ class OCollection;
+ class OIndex;
+ typedef ::cppu::ImplHelper1< css::sdbcx::XDataDescriptorFactory > OIndex_BASE;
+ typedef ::comphelper::OIdPropertyArrayUsageHelper<OIndex> OIndex_PROP;
+
+ class OOO_DLLPUBLIC_DBTOOLS OIndex :
+ public cppu::BaseMutex,
+ public ODescriptor_BASE,
+ public IRefreshableColumns,
+ public OIndex_PROP,
+ public ODescriptor,
+ public OIndex_BASE
+ {
+ protected:
+ OUString m_Catalog;
+ bool m_IsUnique;
+ bool m_IsPrimaryKeyIndex;
+ bool m_IsClustered;
+
+ // no Reference! see OCollection::acquire
+ std::unique_ptr<OCollection> m_pColumns;
+
+ using ODescriptor_BASE::rBHelper;
+ virtual void refreshColumns() override;
+ // OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper( sal_Int32 _nId) const override;
+ virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override;
+ public:
+ OIndex(bool _bCase);
+ OIndex( const OUString& Name,
+ OUString Catalog,
+ bool _isUnique,
+ bool _isPrimaryKeyIndex,
+ bool _isClustered,
+ bool _bCase);
+
+ virtual ~OIndex( ) override;
+
+ DECLARE_SERVICE_INFO();
+
+ //XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+ //XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override;
+ // ODescriptor
+ virtual void construct() override;
+ // ::cppu::OComponentHelper
+ virtual void SAL_CALL disposing() override;
+ // XPropertySet
+ virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override;
+ // XColumnsSupplier
+ virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getColumns( ) override;
+
+ // XNamed
+ virtual OUString SAL_CALL getName( ) override;
+ virtual void SAL_CALL setName( const OUString& aName ) override;
+ // XDataDescriptorFactory
+ virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL createDataDescriptor( ) override;
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/inc/sdbcx/VIndexColumn.hxx b/connectivity/inc/sdbcx/VIndexColumn.hxx
new file mode 100644
index 0000000000..056b823941
--- /dev/null
+++ b/connectivity/inc/sdbcx/VIndexColumn.hxx
@@ -0,0 +1,58 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <connectivity/dbtoolsdllapi.hxx>
+#include <connectivity/sdbcx/VColumn.hxx>
+
+namespace connectivity::sdbcx
+ {
+ class OIndexColumn;
+ typedef ::comphelper::OIdPropertyArrayUsageHelper<OIndexColumn> OIndexColumn_PROP;
+
+ class OOO_DLLPUBLIC_DBTOOLS OIndexColumn :
+ public OColumn, public OIndexColumn_PROP
+ {
+ bool m_IsAscending;
+ protected:
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper( sal_Int32 _nId) const override;
+ virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override;
+ public:
+ OIndexColumn( bool _bCase);
+ OIndexColumn( bool IsAscending,
+ const OUString& Name,
+ const OUString& TypeName,
+ const OUString& DefaultValue,
+ sal_Int32 IsNullable,
+ sal_Int32 Precision,
+ sal_Int32 Scale,
+ sal_Int32 Type,
+ bool _bCase,
+ const OUString& CatalogName,
+ const OUString& SchemaName,
+ const OUString& TableName);
+
+ virtual void construct() override;
+ DECLARE_SERVICE_INFO();
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/inc/sdbcx/VKey.hxx b/connectivity/inc/sdbcx/VKey.hxx
new file mode 100644
index 0000000000..df17eba872
--- /dev/null
+++ b/connectivity/inc/sdbcx/VKey.hxx
@@ -0,0 +1,109 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+
+#include <comphelper/IdPropArrayHelper.hxx>
+#include <connectivity/CommonTools.hxx>
+#include <sdbcx/VTypeDef.hxx>
+#include <connectivity/sdbcx/IRefreshable.hxx>
+#include <connectivity/sdbcx/VDescriptor.hxx>
+#include <connectivity/dbtoolsdllapi.hxx>
+#include <cppuhelper/implbase1.hxx>
+#include <cppuhelper/basemutex.hxx>
+#include <com/sun/star/sdbcx/XDataDescriptorFactory.hpp>
+#include <memory>
+#include <utility>
+
+namespace connectivity::sdbcx
+ {
+
+ struct OOO_DLLPUBLIC_DBTOOLS KeyProperties
+ {
+ ::std::vector< OUString> m_aKeyColumnNames;
+ OUString m_ReferencedTable;
+ sal_Int32 m_Type;
+ sal_Int32 m_UpdateRule;
+ sal_Int32 m_DeleteRule;
+ KeyProperties(OUString ReferencedTable,
+ sal_Int32 Type,
+ sal_Int32 UpdateRule,
+ sal_Int32 DeleteRule)
+ :m_ReferencedTable(std::move(ReferencedTable)),
+ m_Type(Type),
+ m_UpdateRule(UpdateRule),
+ m_DeleteRule(DeleteRule)
+ {}
+ KeyProperties():m_Type(0),m_UpdateRule(0),m_DeleteRule(0){}
+ };
+ typedef ::cppu::ImplHelper1< css::sdbcx::XDataDescriptorFactory > OKey_BASE;
+ class OCollection;
+
+ class OOO_DLLPUBLIC_DBTOOLS OKey :
+ public cppu::BaseMutex,
+ public ODescriptor_BASE,
+ public IRefreshableColumns,
+ public ::comphelper::OIdPropertyArrayUsageHelper<OKey>,
+ public ODescriptor,
+ public OKey_BASE
+ {
+ protected:
+ std::shared_ptr<KeyProperties> m_aProps;
+ // no Reference! see OCollection::acquire
+ std::unique_ptr<OCollection> m_pColumns;
+
+ using ODescriptor_BASE::rBHelper;
+ // OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper( sal_Int32 _nId) const override;
+ // OPropertySetHelper
+ virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override;
+ public:
+ OKey(bool _bCase);
+ OKey(const OUString& Name,std::shared_ptr<KeyProperties> _xProps,bool _bCase);
+
+ virtual ~OKey( ) override;
+
+ DECLARE_SERVICE_INFO();
+ //XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+ //XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override;
+ // ODescriptor
+ virtual void construct() override;
+
+ // ::cppu::OComponentHelper
+ virtual void SAL_CALL disposing() override;
+ // XPropertySet
+ virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override;
+ // XColumnsSupplier
+ virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getColumns( ) override;
+
+ // XNamed
+ virtual OUString SAL_CALL getName( ) override;
+ virtual void SAL_CALL setName( const OUString& aName ) override;
+ // XDataDescriptorFactory
+ virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL createDataDescriptor( ) override;
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/inc/sdbcx/VKeyColumn.hxx b/connectivity/inc/sdbcx/VKeyColumn.hxx
new file mode 100644
index 0000000000..59b26131db
--- /dev/null
+++ b/connectivity/inc/sdbcx/VKeyColumn.hxx
@@ -0,0 +1,59 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <connectivity/sdbcx/VColumn.hxx>
+
+namespace connectivity::sdbcx
+ {
+ class OKeyColumn;
+ typedef ::comphelper::OIdPropertyArrayUsageHelper<OKeyColumn> OKeyColumn_PROP;
+
+ class OKeyColumn :
+ public OColumn, public OKeyColumn_PROP
+ {
+ OUString m_ReferencedColumn;
+ protected:
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper( sal_Int32 _nId) const override;
+ virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override;
+ public:
+ OKeyColumn(bool _bCase);
+ OKeyColumn( OUString ReferencedColumn,
+ const OUString& Name,
+ const OUString& TypeName,
+ const OUString& DefaultValue,
+ sal_Int32 IsNullable,
+ sal_Int32 Precision,
+ sal_Int32 Scale,
+ sal_Int32 Type,
+ bool _bCase,
+ const OUString& CatalogName,
+ const OUString& SchemaName,
+ const OUString& TableName);
+ // just to make it not inline
+ virtual ~OKeyColumn() override;
+
+ virtual void construct() override;
+ DECLARE_SERVICE_INFO();
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/inc/sdbcx/VTypeDef.hxx b/connectivity/inc/sdbcx/VTypeDef.hxx
new file mode 100644
index 0000000000..92a1f3c9c1
--- /dev/null
+++ b/connectivity/inc/sdbcx/VTypeDef.hxx
@@ -0,0 +1,34 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
+#include <cppuhelper/compbase.hxx>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/container/XNamed.hpp>
+
+namespace connectivity::sdbcx
+{
+ typedef cppu::WeakComponentImplHelper< css::sdbcx::XColumnsSupplier,
+ css::container::XNamed,
+ css::lang::XServiceInfo> ODescriptor_BASE;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/inc/sdbcx/VUser.hxx b/connectivity/inc/sdbcx/VUser.hxx
new file mode 100644
index 0000000000..7086cb04f2
--- /dev/null
+++ b/connectivity/inc/sdbcx/VUser.hxx
@@ -0,0 +1,96 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/sdbcx/XUser.hpp>
+#include <com/sun/star/sdbcx/XGroupsSupplier.hpp>
+#include <comphelper/proparrhlp.hxx>
+#include <cppuhelper/compbase.hxx>
+#include <cppuhelper/basemutex.hxx>
+#include <connectivity/CommonTools.hxx>
+#include <connectivity/sdbcx/VCollection.hxx>
+#include <com/sun/star/container/XNamed.hpp>
+#include <connectivity/sdbcx/IRefreshable.hxx>
+#include <connectivity/sdbcx/VDescriptor.hxx>
+#include <connectivity/dbtoolsdllapi.hxx>
+
+namespace connectivity::sdbcx
+{
+ typedef OCollection OGroups;
+
+ typedef ::cppu::WeakComponentImplHelper< css::sdbcx::XUser,
+ css::sdbcx::XGroupsSupplier,
+ css::container::XNamed,
+ css::lang::XServiceInfo> OUser_BASE;
+
+ class OOO_DLLPUBLIC_DBTOOLS OUser :
+ public cppu::BaseMutex,
+ public OUser_BASE,
+ public IRefreshableGroups,
+ public ::comphelper::OPropertyArrayUsageHelper<OUser>,
+ public ODescriptor
+ {
+ protected:
+ // no Reference! see OCollection::acquire
+ std::unique_ptr<OGroups> m_pGroups;
+
+ using OUser_BASE::rBHelper;
+
+ // OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override;
+ // OPropertySetHelper
+ virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override;
+ public:
+ OUser(bool _bCase);
+ OUser(const OUString& Name,bool _bCase);
+
+ virtual ~OUser( ) override;
+
+ DECLARE_SERVICE_INFO();
+
+ // ::cppu::OComponentHelper
+ virtual void SAL_CALL disposing() override;
+ //XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+ //XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override;
+ // XPropertySet
+ virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override;
+ // XUser
+ virtual void SAL_CALL changePassword( const OUString& objPassword, const OUString& newPassword ) override;
+ // XAuthorizable
+ virtual sal_Int32 SAL_CALL getPrivileges( const OUString& objName, sal_Int32 objType ) override;
+ virtual sal_Int32 SAL_CALL getGrantablePrivileges( const OUString& objName, sal_Int32 objType ) override;
+ virtual void SAL_CALL grantPrivileges( const OUString& objName, sal_Int32 objType, sal_Int32 objPrivileges ) override;
+ virtual void SAL_CALL revokePrivileges( const OUString& objName, sal_Int32 objType, sal_Int32 objPrivileges ) override;
+ // XGroupsSupplier
+ virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getGroups( ) override;
+
+ // XNamed
+ virtual OUString SAL_CALL getName( ) override;
+ virtual void SAL_CALL setName( const OUString& aName ) override;
+ };
+
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/inc/strings.hrc b/connectivity/inc/strings.hrc
new file mode 100644
index 0000000000..873623bba0
--- /dev/null
+++ b/connectivity/inc/strings.hrc
@@ -0,0 +1,129 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#define NC_(Context, String) TranslateId(Context, u8##String)
+
+// = common strings
+#define STR_NO_CONNECTION_GIVEN NC_("STR_NO_CONNECTION_GIVEN", "No connection to the database exists.")
+#define STR_WRONG_PARAM_INDEX NC_("STR_WRONG_PARAM_INDEX", "You tried to set a parameter at position “$pos$” but there is/are only “$count$” parameter(s) allowed. One reason may be that the property “ParameterNameSubstitution” is not set to TRUE in the data source.")
+#define STR_NO_INPUTSTREAM NC_("STR_NO_INPUTSTREAM", "The input stream was not set.")
+#define STR_NO_ELEMENT_NAME NC_("STR_NO_ELEMENT_NAME", "There is no element named “$name$”.")
+#define STR_INVALID_BOOKMARK NC_("STR_INVALID_BOOKMARK", "Invalid bookmark value")
+#define STR_PRIVILEGE_NOT_GRANTED NC_("STR_PRIVILEGE_NOT_GRANTED", "Privilege not granted: Only table privileges can be granted.")
+#define STR_PRIVILEGE_NOT_REVOKED NC_("STR_PRIVILEGE_NOT_REVOKED", "Privilege not revoked: Only table privileges can be revoked.")
+#define STR_ERRORMSG_SEQUENCE NC_("STR_ERRORMSG_SEQUENCE", "Function sequence error.")
+#define STR_INVALID_INDEX NC_("STR_INVALID_INDEX", "Invalid descriptor index.")
+#define STR_UNSUPPORTED_FUNCTION NC_("STR_UNSUPPORTED_FUNCTION", "The driver does not support the function “$functionname$”.")
+#define STR_UNSUPPORTED_FEATURE NC_("STR_UNSUPPORTED_FEATURE", "The driver does not support the functionality for “$featurename$”. It is not implemented.")
+#define STR_FORMULA_WRONG NC_("STR_FORMULA_WRONG", "The formula for TypeInfoSettings is wrong!")
+#define STR_STRING_LENGTH_EXCEEDED NC_("STR_STRING_LENGTH_EXCEEDED", "The string “$string$” exceeds the maximum length of $maxlen$ characters when converted to the target character set “$charset$”.")
+#define STR_CANNOT_CONVERT_STRING NC_("STR_CANNOT_CONVERT_STRING", "The string “$string$” cannot be converted using the encoding “$charset$”.")
+#define STR_URI_SYNTAX_ERROR NC_("STR_URI_SYNTAX_ERROR", "The connection URL is invalid.")
+#define STR_QUERY_TOO_COMPLEX NC_("STR_QUERY_TOO_COMPLEX", "The query cannot be executed. It is too complex.")
+#define STR_OPERATOR_TOO_COMPLEX NC_("STR_OPERATOR_TOO_COMPLEX", "The query cannot be executed. The operator is too complex.")
+#define STR_QUERY_INVALID_LIKE_COLUMN NC_("STR_QUERY_INVALID_LIKE_COLUMN", "The query cannot be executed. You cannot use “LIKE” with columns of this type.")
+#define STR_QUERY_INVALID_LIKE_STRING NC_("STR_QUERY_INVALID_LIKE_STRING", "The query cannot be executed. “LIKE” can be used with a string argument only.")
+#define STR_QUERY_NOT_LIKE_TOO_COMPLEX NC_("STR_QUERY_NOT_LIKE_TOO_COMPLEX", "The query cannot be executed. The “NOT LIKE” condition is too complex.")
+#define STR_QUERY_LIKE_WILDCARD NC_("STR_QUERY_LIKE_WILDCARD", "The query cannot be executed. The “LIKE” condition contains wildcard in the middle.")
+#define STR_QUERY_LIKE_WILDCARD_MANY NC_("STR_QUERY_LIKE_WILDCARD_MANY", "The query cannot be executed. The “LIKE” condition contains too many wildcards.")
+#define STR_INVALID_COLUMNNAME NC_("STR_INVALID_COLUMNNAME", "The column name “$columnname$” is not valid.")
+#define STR_INVALID_COLUMN_SELECTION NC_("STR_INVALID_COLUMN_SELECTION", "The statement contains an invalid selection of columns.")
+#define STR_COULD_NOT_LOAD_FILE NC_("STR_COULD_NOT_LOAD_FILE", "The file $filename$ could not be loaded.")
+#define STR_LOAD_FILE_ERROR_MESSAGE NC_("STR_LOAD_FILE_ERROR_MESSAGE", "The attempt to load the file resulted in the following error message ($exception_type$):\n\n$error_message$")
+// = the ado driver's resource strings
+#define STR_TYPE_NOT_CONVERT NC_("STR_TYPE_NOT_CONVERT", "The type could not be converted.")
+#define STR_INVALID_COLUMN_DESCRIPTOR_ERROR NC_("STR_INVALID_COLUMN_DESCRIPTOR_ERROR", "Could not append column: invalid column descriptor.")
+#define STR_INVALID_GROUP_DESCRIPTOR_ERROR NC_("STR_INVALID_GROUP_DESCRIPTOR_ERROR", "Could not create group: invalid object descriptor.")
+#define STR_INVALID_INDEX_DESCRIPTOR_ERROR NC_("STR_INVALID_INDEX_DESCRIPTOR_ERROR", "Could not create index: invalid object descriptor.")
+#define STR_INVALID_KEY_DESCRIPTOR_ERROR NC_("STR_INVALID_KEY_DESCRIPTOR_ERROR", "Could not create key: invalid object descriptor.")
+#define STR_INVALID_TABLE_DESCRIPTOR_ERROR NC_("STR_INVALID_TABLE_DESCRIPTOR_ERROR", "Could not create table: invalid object descriptor.")
+#define STR_INVALID_USER_DESCRIPTOR_ERROR NC_("STR_INVALID_USER_DESCRIPTOR_ERROR", "Could not create user: invalid object descriptor.")
+#define STR_INVALID_VIEW_DESCRIPTOR_ERROR NC_("STR_INVALID_VIEW_DESCRIPTOR_ERROR", "Could not create view: invalid object descriptor.")
+#define STR_VIEW_NO_COMMAND_ERROR NC_("STR_VIEW_NO_COMMAND_ERROR", "Could not create view: no command object.")
+#define STR_NO_CONNECTION NC_("STR_NO_CONNECTION", "The connection could not be created. Maybe the necessary data provider is not installed.")
+// dbase
+#define STR_COULD_NOT_DELETE_INDEX NC_("STR_COULD_NOT_DELETE_INDEX", "The index could not be deleted. An unknown error while accessing the file system occurred.")
+#define STR_ONL_ONE_COLUMN_PER_INDEX NC_("STR_ONL_ONE_COLUMN_PER_INDEX", "The index could not be created. Only one column per index is allowed.")
+#define STR_COULD_NOT_CREATE_INDEX_NOT_UNIQUE NC_("STR_COULD_NOT_CREATE_INDEX_NOT_UNIQUE", "The index could not be created. The values are not unique.")
+#define STR_COULD_NOT_CREATE_INDEX NC_("STR_COULD_NOT_CREATE_INDEX", "The index could not be created. An unknown error appeared.")
+#define STR_COULD_NOT_CREATE_INDEX_NAME NC_("STR_COULD_NOT_CREATE_INDEX_NAME", "The index could not be created. The file “$filename$” is used by another index.")
+#define STR_COULD_NOT_CREATE_INDEX_KEYSIZE NC_("STR_COULD_NOT_CREATE_INDEX_KEYSIZE", "The index could not be created. The size of the chosen column is too big.")
+#define STR_SQL_NAME_ERROR NC_("STR_SQL_NAME_ERROR", "The name “$name$” does not match SQL naming constraints.")
+#define STR_COULD_NOT_DELETE_FILE NC_("STR_COULD_NOT_DELETE_FILE", "The file $filename$ could not be deleted.")
+#define STR_INVALID_COLUMN_TYPE NC_("STR_INVALID_COLUMN_TYPE", "Invalid column type for column “$columnname$”.")
+#define STR_INVALID_COLUMN_PRECISION NC_("STR_INVALID_COLUMN_PRECISION", "Invalid precision for column “$columnname$”.")
+#define STR_INVALID_PRECISION_SCALE NC_("STR_INVALID_PRECISION_SCALE", "Precision is less than scale for column “$columnname$”.")
+#define STR_INVALID_COLUMN_NAME_LENGTH NC_("STR_INVALID_COLUMN_NAME_LENGTH", "Invalid column name length for column “$columnname$”.")
+#define STR_DUPLICATE_VALUE_IN_COLUMN NC_("STR_DUPLICATE_VALUE_IN_COLUMN", "Duplicate value found in column “$columnname$”.")
+#define STR_INVALID_COLUMN_DECIMAL_VALUE NC_("STR_INVALID_COLUMN_DECIMAL_VALUE", "The “$columnname$” column has been defined as a “Decimal” type, the maximum length is $precision$ characters (with $scale$ decimal places).\n\nThe specified value “$value$” is longer than the number of digits allowed.")
+#define STR_COLUMN_NOT_ALTERABLE NC_("STR_COLUMN_NOT_ALTERABLE", "The column “$columnname$” could not be altered. Maybe the file system is write-protected.")
+#define STR_INVALID_COLUMN_VALUE NC_("STR_INVALID_COLUMN_VALUE", "The column “$columnname$” could not be updated. The value is invalid for that column.")
+#define STR_COLUMN_NOT_ADDABLE NC_("STR_COLUMN_NOT_ADDABLE", "The column “$columnname$” could not be added. Maybe the file system is write-protected.")
+#define STR_COLUMN_NOT_DROP NC_("STR_COLUMN_NOT_DROP", "The column at position “$position$” could not be dropped. Maybe the file system is write-protected.")
+#define STR_TABLE_NOT_DROP NC_("STR_TABLE_NOT_DROP", "The table “$tablename$” could not be dropped. Maybe the file system is write-protected.")
+#define STR_COULD_NOT_ALTER_TABLE NC_("STR_COULD_NOT_ALTER_TABLE", "The table could not be altered.")
+#define STR_INVALID_DBASE_FILE NC_("STR_INVALID_DBASE_FILE", "The file “$filename$” is an invalid (or unrecognized) dBASE file.")
+// Evoab2
+#define STR_CANNOT_OPEN_BOOK NC_("STR_CANNOT_OPEN_BOOK", "Cannot open Evolution address book.")
+#define STR_SORT_BY_COL_ONLY NC_("STR_SORT_BY_COL_ONLY", "Can only sort by table columns.")
+// File
+#define STR_QUERY_COMPLEX_COUNT NC_("STR_QUERY_COMPLEX_COUNT", "The query cannot be executed. It is too complex. Only “COUNT(*)” is supported.")
+#define STR_QUERY_INVALID_BETWEEN NC_("STR_QUERY_INVALID_BETWEEN", "The query cannot be executed. The “BETWEEN” arguments are not correct.")
+#define STR_QUERY_FUNCTION_NOT_SUPPORTED NC_("STR_QUERY_FUNCTION_NOT_SUPPORTED", "The query cannot be executed. The function is not supported.")
+#define STR_TABLE_READONLY NC_("STR_TABLE_READONLY", "The table cannot be changed. It is read only.")
+#define STR_DELETE_ROW NC_("STR_DELETE_ROW", "The row could not be deleted. The option “Display inactive records” is set.")
+#define STR_ROW_ALREADY_DELETED NC_("STR_ROW_ALREADY_DELETED", "The row could not be deleted. It is already deleted.")
+#define STR_QUERY_MORE_TABLES NC_("STR_QUERY_MORE_TABLES", "The query cannot be executed. It contains more than one table.")
+#define STR_QUERY_NO_TABLE NC_("STR_QUERY_NO_TABLE", "The query cannot be executed. It contains no valid table.")
+#define STR_QUERY_NO_COLUMN NC_("STR_QUERY_NO_COLUMN", "The query cannot be executed. It contains no valid columns.")
+#define STR_INVALID_PARA_COUNT NC_("STR_INVALID_PARA_COUNT", "The count of the given parameter values does not match the parameters.")
+#define STR_NO_VALID_FILE_URL NC_("STR_NO_VALID_FILE_URL", "The URL “$URL$” is not valid. A connection cannot be created.")
+#define STR_NO_CLASSNAME NC_("STR_NO_CLASSNAME", "The driver class “$classname$” could not be loaded.")
+#define STR_NO_JAVA NC_("STR_NO_JAVA", "No Java installation could be found. Please check your installation.")
+#define STR_NO_RESULTSET NC_("STR_NO_RESULTSET", "The execution of the query does not return a valid result set.")
+#define STR_NO_ROWCOUNT NC_("STR_NO_ROWCOUNT", "The execution of the update statement does not affect any rows.")
+#define STR_NO_CLASSNAME_PATH NC_("STR_NO_CLASSNAME_PATH", "The additional driver class path is “$classpath$”.")
+#define STR_UNKNOWN_PARA_TYPE NC_("STR_UNKNOWN_PARA_TYPE", "The type of parameter at position “$position$” is unknown.")
+#define STR_UNKNOWN_COLUMN_TYPE NC_("STR_UNKNOWN_COLUMN_TYPE", "The type of column at position “$position$” is unknown.")
+// KAB
+#define STR_PARA_ONLY_PREPARED NC_("STR_PARA_ONLY_PREPARED", "Parameters can appear only in prepared statements.")
+// MACAB
+#define STR_NO_TABLE NC_("STR_NO_TABLE", "No such table!")
+#define STR_NO_MAC_OS_FOUND NC_("STR_NO_MAC_OS_FOUND", "No suitable macOS installation was found.")
+// hsqldb
+#define STR_NO_STORAGE NC_("STR_NO_STORAGE", "The connection can not be established. No storage or URL was given.")
+#define STR_INVALID_FILE_URL NC_("STR_INVALID_FILE_URL", "The given URL contains no valid local file system path. Please check the location of your database file.")
+#define STR_NO_TABLE_CONTAINER NC_("STR_NO_TABLE_CONTAINER", "An error occurred while obtaining the connection’s table container.")
+#define STR_NO_TABLENAME NC_("STR_NO_TABLENAME", "There is no table named “$tablename$”.")
+#define STR_NO_DOCUMENTUI NC_("STR_NO_DOCUMENTUI", "The provided DocumentUI is not allowed to be NULL.")
+#define STR_ERROR_NEW_VERSION NC_("STR_ERROR_NEW_VERSION", "The connection could not be established. The database was created by a newer version of %PRODUCTNAME.")
+
+#define STR_ROW_SET_OPERATION_VETOED NC_("STR_ROW_SET_OPERATION_VETOED", "The record operation has been vetoed.")
+#define STR_PARSER_CYCLIC_SUB_QUERIES NC_("STR_PARSER_CYCLIC_SUB_QUERIES", "The statement contains a cyclic reference to one or more subqueries.")
+#define STR_DB_OBJECT_NAME_WITH_SLASHES NC_("STR_DB_OBJECT_NAME_WITH_SLASHES", "The name must not contain any slashes (“/”).")
+#define STR_DB_INVALID_SQL_NAME NC_("STR_DB_INVALID_SQL_NAME", "$1$ is no SQL conform identifier.")
+#define STR_DB_QUERY_NAME_WITH_QUOTES NC_("STR_DB_QUERY_NAME_WITH_QUOTES", "Query names must not contain quote characters.")
+#define STR_DB_OBJECT_NAME_IS_USED NC_("STR_DB_OBJECT_NAME_IS_USED", "The name “$1$” is already in use in the database.")
+#define STR_DB_NOT_CONNECTED NC_("STR_DB_NOT_CONNECTED", "No connection to the database exists.")
+#define STR_AB_ADDRESSBOOK_NOT_FOUND NC_("STR_AB_ADDRESSBOOK_NOT_FOUND", "No $1$ exists.")
+#define STR_DATA_CANNOT_SELECT_UNFILTERED NC_("STR_DATA_CANNOT_SELECT_UNFILTERED", "Unable to display the complete table content. Please apply a filter.")
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/inc/strings.hxx b/connectivity/inc/strings.hxx
new file mode 100644
index 0000000000..b6bd8e5458
--- /dev/null
+++ b/connectivity/inc/strings.hxx
@@ -0,0 +1,76 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include <rtl/ustring.hxx>
+
+// = log messages for the JDBC driver
+
+#define STR_LOG_DRIVER_CONNECTING_URL "jdbcBridge: connecting to URL '$1$'"
+inline constexpr OUString STR_LOG_DRIVER_SUCCESS = u"jdbcBridge: success"_ustr;
+inline constexpr OUString STR_LOG_CREATE_STATEMENT = u"c$1$: creating statement"_ustr;
+inline constexpr OUString STR_LOG_CREATED_STATEMENT_ID = u"c$1$: created statement, statement id: s$2$"_ustr;
+inline constexpr OUString STR_LOG_PREPARE_STATEMENT = u"c$1$: preparing statement: $2$"_ustr;
+inline constexpr OUString STR_LOG_PREPARED_STATEMENT_ID = u"c$1$: prepared statement, statement id: s$2$"_ustr;
+inline constexpr OUString STR_LOG_PREPARE_CALL = u"c$1$: preparing call: $2$"_ustr;
+inline constexpr OUString STR_LOG_PREPARED_CALL_ID = u"c$1$: prepared call, statement id: s$2$"_ustr;
+inline constexpr OUString STR_LOG_NATIVE_SQL = u"c$1$: native SQL: $2$ -> $3$"_ustr;
+inline constexpr OUString STR_LOG_LOADING_DRIVER = u"c$1$: attempting to load driver class $2$"_ustr;
+inline constexpr OUString STR_LOG_NO_DRIVER_CLASS = u"c$1$: no Java Driver Class was provided"_ustr;
+inline constexpr OUString STR_LOG_CONN_SUCCESS = u"c$1$: success"_ustr;
+inline constexpr OUString STR_LOG_NO_SYSTEM_CONNECTION = u"c$1$: JDBC driver did not provide a JDBC connection"_ustr;
+inline constexpr OUString STR_LOG_GOT_JDBC_CONNECTION = u"c$1$: obtained a JDBC connection for $2$"_ustr;
+inline constexpr OUString STR_LOG_SHUTDOWN_CONNECTION = u"c$1$: shutting down connection"_ustr;
+inline constexpr OUString STR_LOG_GENERATED_VALUES = u"s$1$: retrieving generated values"_ustr;
+inline constexpr OUString STR_LOG_GENERATED_VALUES_FALLBACK = u"s$1$: getGeneratedValues: falling back to statement: $2$"_ustr;
+inline constexpr OUString STR_LOG_EXECUTE_STATEMENT = u"s$1$: going to execute: $2$"_ustr;
+inline constexpr OUString STR_LOG_EXECUTE_QUERY = u"s$1$: going to execute query: $2$"_ustr;
+inline constexpr OUString STR_LOG_CLOSING_STATEMENT = u"s$1$: closing/disposing statement"_ustr;
+inline constexpr OUString STR_LOG_EXECUTE_UPDATE = u"s$1$: going to execute update: $2$"_ustr;
+inline constexpr OUString STR_LOG_UPDATE_COUNT = u"s$1$: update count: $2$"_ustr;
+inline constexpr OUString STR_LOG_RESULT_SET_CONCURRENCY = u"s$1$: going to set result set concurrency: $2$"_ustr;
+inline constexpr OUString STR_LOG_RESULT_SET_TYPE = u"s$1$: going to set result set type: $2$"_ustr;
+inline constexpr OUString STR_LOG_FETCH_DIRECTION = u"s$1$: fetch direction: $2$"_ustr;
+inline constexpr OUString STR_LOG_FETCH_SIZE = u"s$1$: fetch size: $2$"_ustr;
+inline constexpr OUString STR_LOG_SET_ESCAPE_PROCESSING = u"s$1$: going to set escape processing: $2$"_ustr;
+inline constexpr OUString STR_LOG_EXECUTING_PREPARED = u"s$1$: executing previously prepared statement"_ustr;
+inline constexpr OUString STR_LOG_EXECUTING_PREPARED_UPDATE = u"s$1$: executing previously prepared update statement"_ustr;
+inline constexpr OUString STR_LOG_EXECUTING_PREPARED_QUERY = u"s$1$: executing previously prepared query"_ustr;
+inline constexpr OUString STR_LOG_STRING_PARAMETER = u"s$1$: parameter no. $2$: type: string; value: $3$"_ustr;
+inline constexpr OUString STR_LOG_BOOLEAN_PARAMETER = u"s$1$: parameter no. $2$: type: boolean; value: $3$"_ustr;
+inline constexpr OUString STR_LOG_BYTE_PARAMETER = u"s$1$: parameter no. $2$: type: byte; value: $3$"_ustr;
+inline constexpr OUString STR_LOG_DATE_PARAMETER = u"s$1$: parameter no. $2$: type: date; value: $3$"_ustr;
+inline constexpr OUString STR_LOG_TIME_PARAMETER = u"s$1$: parameter no. $2$: type: time; value: $3$"_ustr;
+inline constexpr OUString STR_LOG_TIMESTAMP_PARAMETER = u"s$1$: parameter no. $2$: type: timestamp; value: $3$"_ustr;
+inline constexpr OUString STR_LOG_DOUBLE_PARAMETER = u"s$1$: parameter no. $2$: type: double; value: $3$"_ustr;
+inline constexpr OUString STR_LOG_FLOAT_PARAMETER = u"s$1$: parameter no. $2$: type: float; value: $3$"_ustr;
+inline constexpr OUString STR_LOG_INT_PARAMETER = u"s$1$: parameter no. $2$: type: int; value: $3$"_ustr;
+inline constexpr OUString STR_LOG_LONG_PARAMETER = u"s$1$: parameter no. $2$: type: long; value: $3$"_ustr;
+inline constexpr OUString STR_LOG_NULL_PARAMETER = u"s$1$: parameter no. $2$: sql-type: $3$; value: null"_ustr;
+inline constexpr OUString STR_LOG_OBJECT_NULL_PARAMETER = u"s$1$: parameter no. $2$: setting to null"_ustr;
+inline constexpr OUString STR_LOG_SHORT_PARAMETER = u"s$1$: parameter no. $2$: type: short; value: $3$"_ustr;
+inline constexpr OUString STR_LOG_BYTES_PARAMETER = u"s$1$: parameter no. $2$: type: byte[]"_ustr;
+inline constexpr OUString STR_LOG_CHARSTREAM_PARAMETER = u"s$1$: parameter no. $2$: type: character stream"_ustr;
+inline constexpr OUString STR_LOG_BINARYSTREAM_PARAMETER = u"s$1$: parameter no. $2$: type: binary stream"_ustr;
+inline constexpr OUString STR_LOG_CLEAR_PARAMETERS = u"s$1$: clearing all parameters"_ustr;
+inline constexpr OUString STR_LOG_META_DATA_METHOD = u"c$1$: entering XDatabaseMetaData::$2$"_ustr;
+inline constexpr OUString STR_LOG_META_DATA_METHOD_ARG1 = u"c$1$: entering XDatabaseMetaData::$2$( '$3$' )"_ustr;
+inline constexpr OUString STR_LOG_META_DATA_METHOD_ARG2 = u"c$1$: entering XDatabaseMetaData::$2$( '$3$', '$4$' )"_ustr;
+inline constexpr OUString STR_LOG_META_DATA_METHOD_ARG3 = u"c$1$: entering XDatabaseMetaData::$2$( '$3$', '$4$', '$5$' )"_ustr;
+inline constexpr OUString STR_LOG_META_DATA_METHOD_ARG4 = u"c$1$: entering XDatabaseMetaData::$2$( '$3$', '$4$', '$5$', '$6$' )"_ustr;
+inline constexpr OUString STR_LOG_META_DATA_RESULT = u"c$1$: leaving XDatabaseMetaData::$2$: success-with-result: $3$"_ustr;
+inline constexpr OUString STR_LOG_META_DATA_SUCCESS = u"c$1$: leaving XDatabaseMetaData::$2$: success"_ustr;
+#define STR_LOG_THROWING_EXCEPTION "SQLException to be thrown: message: '$1$', SQLState: $2$, ErrorCode: $3$"
+inline constexpr OUString STR_LOG_SETTING_SYSTEM_PROPERTY = u"setting system property \"$1$\" to value \"$2$\""_ustr;
+
+inline constexpr OUString STR_DB_NOT_CONNECTED_STATE = u"08003"_ustr;
+inline constexpr OUString STR_DATA_CANNOT_SELECT_UNFILTERED_STATE = u"IM001"_ustr;
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/connectivity/org/hsqldb/lib/FileSystemRuntimeException.java b/connectivity/org/hsqldb/lib/FileSystemRuntimeException.java
new file mode 100644
index 0000000000..b3598ad30a
--- /dev/null
+++ b/connectivity/org/hsqldb/lib/FileSystemRuntimeException.java
@@ -0,0 +1,38 @@
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+// NOTE:
+// This class does not yet exist before 1.8.0.8. When we move our shipped
+// version to 1.8.0.8 or higher, this file here can be removed from CVS.
+
+package org.hsqldb.lib;
+
+/** is a RuntimeException which indicates failure during basic IO
+ * operations in a FileAccess implementation.
+ *
+ * @version 1.8.0.8
+ * @since 1.8.0.8
+ */
+public class FileSystemRuntimeException extends java.lang.RuntimeException {
+
+ public FileSystemRuntimeException(java.lang.Throwable _cause) {
+ super(_cause);
+ }
+
+}
diff --git a/connectivity/qa/complex/connectivity/DBaseDriverTest.java b/connectivity/qa/complex/connectivity/DBaseDriverTest.java
new file mode 100644
index 0000000000..f1c89dc701
--- /dev/null
+++ b/connectivity/qa/complex/connectivity/DBaseDriverTest.java
@@ -0,0 +1,70 @@
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+package complex.connectivity;
+
+import complex.connectivity.dbase.DBaseDateFunctions;
+import complex.connectivity.dbase.DBaseStringFunctions;
+import complex.connectivity.dbase.DBaseSqlTests;
+import complex.connectivity.dbase.DBaseNumericFunctions;
+import complexlib.ComplexTestCase;
+import share.LogWriter;
+
+public class DBaseDriverTest extends ComplexTestCase implements TestCase
+{
+ @Override
+ public String[] getTestMethodNames()
+ {
+ return new String[]
+ {
+ "Functions"
+ };
+ }
+
+ @Override
+ public String getTestObjectName()
+ {
+ return "DBaseDriverTest";
+ }
+
+ @Override
+ public void assure( final String i_message, final boolean i_condition )
+ {
+ super.assure( i_message, i_condition );
+ }
+
+ public LogWriter getLog()
+ {
+ return log;
+ }
+
+ public void Functions() throws com.sun.star.uno.Exception, com.sun.star.beans.UnknownPropertyException
+ {
+ DBaseStringFunctions aStringTest = new DBaseStringFunctions(param.getMSF(), this);
+ aStringTest.testFunctions();
+
+ DBaseNumericFunctions aNumericTest = new DBaseNumericFunctions(param.getMSF(), this);
+ aNumericTest.testFunctions();
+
+ DBaseDateFunctions aDateTest = new DBaseDateFunctions(param.getMSF(), this);
+ aDateTest.testFunctions();
+
+ DBaseSqlTests aSqlTest = new DBaseSqlTests(param.getMSF(), this);
+ aSqlTest.testFunctions();
+ }
+}
diff --git a/connectivity/qa/complex/connectivity/FlatFileAccess.java b/connectivity/qa/complex/connectivity/FlatFileAccess.java
new file mode 100644
index 0000000000..43d0eabef1
--- /dev/null
+++ b/connectivity/qa/complex/connectivity/FlatFileAccess.java
@@ -0,0 +1,245 @@
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+package complex.connectivity;
+
+import com.sun.star.beans.XPropertySet;
+import com.sun.star.sdb.CommandType;
+import com.sun.star.sdbc.SQLException;
+import com.sun.star.util.Date;
+import complexlib.ComplexTestCase;
+import connectivity.tools.CsvDatabase;
+import connectivity.tools.RowSet;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+
+public class FlatFileAccess extends ComplexTestCase
+{
+ @Override
+ public String[] getTestMethodNames()
+ {
+ return new String[] {
+ "testBasicAccess",
+ "testCalendarFunctions",
+ "testSortingByFunction"
+ };
+ }
+
+ @Override
+ public String getTestObjectName()
+ {
+ return "FlatFileAccess";
+ }
+
+ public void before() throws Exception
+ {
+ m_database = new CsvDatabase( param.getMSF() );
+
+ // proper settings
+ final XPropertySet dataSourceSettings = m_database.getDataSource().geSettings();
+ dataSourceSettings.setPropertyValue( "Extension", "csv" );
+ dataSourceSettings.setPropertyValue( "HeaderLine", Boolean.TRUE );
+ dataSourceSettings.setPropertyValue( "FieldDelimiter", " " );
+ m_database.store();
+
+ // write the table(s) for our test
+ final String tableLocation = m_database.getTableFileLocation().getAbsolutePath();
+ final PrintWriter tableWriter = new PrintWriter( new FileOutputStream( tableLocation + File.separatorChar + "dates.csv", false ) );
+ tableWriter.println( "ID date" );
+ tableWriter.println( "1 2013-01-01" );
+ tableWriter.println( "2 2012-02-02" );
+ tableWriter.println( "3 2011-03-03" );
+ tableWriter.close();
+ }
+
+ public void after()
+ {
+ }
+
+ private static class EqualityDate extends Date
+ {
+ EqualityDate( short i_day, short i_month, short i_year )
+ {
+ super( i_day, i_month, i_year );
+ }
+
+ @Override
+ public boolean equals( Object i_compare )
+ {
+ if ( !( i_compare instanceof Date ) )
+ return false;
+ return Day == ((Date)i_compare).Day
+ && Month == ((Date)i_compare).Month
+ && Year == ((Date)i_compare).Year;
+ }
+ }
+
+ /**
+ * ensures simple SELECTs from our table(s) work, and deliver the expected results
+ */
+ public void testBasicAccess()
+ {
+ testRowSetResults(
+ "SELECT * FROM \"dates\"",
+ new RowSetIntGetter(1),
+ new Integer[] { 1, 2, 3 },
+ "simple select", "wrong IDs"
+ );
+
+ testRowSetResults(
+ "SELECT * FROM \"dates\"",
+ new RowSetDateGetter( 2 ),
+ new EqualityDate[] { new EqualityDate( (short)1, (short)1, (short)2013 ),
+ new EqualityDate( (short)2, (short)2, (short)2012 ),
+ new EqualityDate( (short)3, (short)3, (short)2011 )
+ },
+ "simple select", "wrong dates"
+ );
+ testRowSetResults(
+ "SELECT \"date\", \"ID\" FROM \"dates\" ORDER BY \"ID\" DESC",
+ new RowSetIntGetter( 2 ),
+ new Integer[] { 3, 2, 1 },
+ "explicit column selection, sorted by IDs", "wrong IDs"
+ );
+ testRowSetResults(
+ "SELECT * FROM \"dates\" ORDER BY \"date\"",
+ new RowSetIntGetter( 1 ),
+ new Integer[] { 3, 2, 1 },
+ "sorted by date", "wrong IDs"
+ );
+ }
+
+ /**
+ * ensures the basic functionality for selecting calendar functions from a CSV table - this is a prerequisite for
+ * later tests.
+ */
+ public void testCalendarFunctions()
+ {
+ // simple check for proper results of the calendar functions (DATE/MONTH)
+ // The * at the first position is crucial here - there was code which wrongly calculated
+ // column positions of function columns when * was present in the statement
+ testRowSetResults(
+ "SELECT \"dates\".*, YEAR( \"date\" ) FROM \"dates\"",
+ new RowSetIntGetter( 3 ),
+ new Integer[] { 2013, 2012, 2011 },
+ "YEAR function", "wrong calculated years"
+ );
+ testRowSetResults(
+ "SELECT \"dates\".*, MONTH( \"date\" ) FROM \"dates\"",
+ new RowSetIntGetter( 3 ),
+ new Integer[] { 1, 2, 3 },
+ "MONTH function", "wrong calculated months"
+ );
+ }
+
+ /**
+ * ensures that sorting by a function column works
+ */
+ public void testSortingByFunction()
+ {
+ // most simple case: select a function, and sort by it
+ testRowSetResults(
+ "SELECT YEAR( \"date\" ) AS \"year\" FROM \"dates\" ORDER BY \"year\"",
+ new RowSetIntGetter(1),
+ new Integer[] { 2011, 2012, 2013 },
+ "single YEAR selection, sorted by years", "wrong calculated years"
+ );
+ // somewhat more "difficult" (this used to crash): Select all columns, plus a function, so the calculated
+ // column has a position greater than column count
+ testRowSetResults(
+ "SELECT \"dates\".*, YEAR( \"date\" ) AS \"year\" FROM \"dates\" ORDER BY \"year\" DESC",
+ new RowSetIntGetter(3),
+ new Integer[] { 2013, 2012, 2011 },
+ "extended YEAR selection, sorted by years", "wrong calculated years"
+ );
+ }
+
+ private interface RowSetValueGetter
+ {
+ Object getValue( final RowSet i_rowSet ) throws SQLException;
+ }
+
+ private static abstract class RowSetColumnValueGetter implements RowSetValueGetter
+ {
+ RowSetColumnValueGetter( final int i_columnIndex )
+ {
+ m_columnIndex = i_columnIndex;
+ }
+
+ protected final int m_columnIndex;
+ }
+
+ private static class RowSetIntGetter extends RowSetColumnValueGetter
+ {
+ RowSetIntGetter( final int i_columnIndex )
+ {
+ super( i_columnIndex );
+ }
+
+ public Object getValue( final RowSet i_rowSet ) throws SQLException
+ {
+ return i_rowSet.getInt( m_columnIndex );
+ }
+ }
+
+ private static class RowSetDateGetter extends RowSetColumnValueGetter
+ {
+ RowSetDateGetter( final int i_columnIndex )
+ {
+ super( i_columnIndex );
+ }
+
+ public Object getValue( final RowSet i_rowSet ) throws SQLException
+ {
+ return i_rowSet.getDate( m_columnIndex );
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ private <T> void testRowSetResults( String i_command, RowSetValueGetter i_getter,
+ T[] i_expectedValues, String i_context, String i_failureDesc )
+ {
+ RowSet rowSet = null;
+ try
+ {
+ rowSet = m_database.createRowSet( CommandType.COMMAND, i_command );
+ rowSet.execute();
+
+ List< T > values = new ArrayList< T >();
+ while ( rowSet.next() )
+ {
+ values.add( (T)i_getter.getValue( rowSet ) );
+ }
+ assureEquals( i_context + ": " + i_failureDesc, i_expectedValues, values.toArray(), ContinueWithTest.YES );
+ }
+ catch( final SQLException e )
+ {
+ failed( i_context + ": caught an exception: " + e.toString(), ContinueWithTest.NO );
+ }
+ finally
+ {
+ if ( rowSet != null )
+ rowSet.dispose();
+ }
+ }
+
+ private CsvDatabase m_database = null;
+}
diff --git a/connectivity/qa/complex/connectivity/HsqlDriverTest.java b/connectivity/qa/complex/connectivity/HsqlDriverTest.java
new file mode 100644
index 0000000000..aba01fad93
--- /dev/null
+++ b/connectivity/qa/complex/connectivity/HsqlDriverTest.java
@@ -0,0 +1,145 @@
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+package complex.connectivity;
+
+import complex.connectivity.hsqldb.TestCacheSize;
+import com.sun.star.frame.XModel;
+import com.sun.star.frame.XStorable;
+
+import com.sun.star.lang.*;
+import com.sun.star.document.XDocumentSubStorageSupplier;
+import complexlib.ComplexTestCase;
+
+
+import org.hsqldb.lib.StopWatch;
+import com.sun.star.uno.UnoRuntime;
+import com.sun.star.beans.PropertyState;
+import com.sun.star.embed.XStorage;
+import com.sun.star.sdbc.XDataSource;
+import com.sun.star.sdbc.XDriver;
+import connectivity.tools.HsqlDatabase;
+
+public class HsqlDriverTest extends ComplexTestCase {
+
+
+ @Override
+ public String[] getTestMethodNames() {
+ return new String[] { "test" };
+ }
+
+ @Override
+ public String getTestObjectName() {
+ return "DriverTest";
+ }
+
+ public void assurePublic(String sMessage,boolean check){
+ super.assure(sMessage,check);
+ }
+
+ public void test(){
+ XDataSource ds = null;
+ System.gc();
+ try {
+ HsqlDatabase database = new HsqlDatabase( param.getMSF() );
+ ds = database.getDataSource().getXDataSource();
+ } catch(Exception ex) {
+ throw new RuntimeException("factory: unable to construct data source", ex );
+ }
+
+ try{
+ XDocumentSubStorageSupplier doc = UnoRuntime.queryInterface(XDocumentSubStorageSupplier.class,ds);
+ XStorage stor = doc.getDocumentSubStorage("database",4);
+ try{
+ if ( stor.isStreamElement("db.log") )
+ stor.removeElement("db.log");
+ } catch(Exception e){}
+ try{
+ if ( stor.isStreamElement("db.properties") )
+ stor.removeElement("db.properties");
+ } catch(Exception e){}
+ try{
+ if ( stor.isStreamElement("db.script") )
+ stor.removeElement("db.script");
+ } catch(Exception e){}
+ try{
+ if ( stor.isStreamElement("db.script.new") )
+ stor.removeElement("db.script.new");
+ } catch(Exception e){}
+ XStorable mod = UnoRuntime.queryInterface(XStorable.class,ds);
+ mod.store();
+ XComponent xComp = UnoRuntime.queryInterface(XComponent.class,stor);
+ if ( xComp != null )
+ xComp.dispose();
+ } catch(Exception e){}
+
+ try{
+ XDocumentSubStorageSupplier doc = UnoRuntime.queryInterface(XDocumentSubStorageSupplier.class,ds);
+ XModel mod = UnoRuntime.queryInterface(XModel.class,ds);
+ XStorage stor = doc.getDocumentSubStorage("database",4);
+ com.sun.star.beans.PropertyValue[] info = new com.sun.star.beans.PropertyValue[]{
+ new com.sun.star.beans.PropertyValue("Storage",0,stor,PropertyState.DIRECT_VALUE)
+ ,new com.sun.star.beans.PropertyValue("URL",0,mod.getURL(),PropertyState.DIRECT_VALUE)
+ };
+ XDriver drv = UnoRuntime.queryInterface(XDriver.class,param.getMSF().createInstance("com.sun.star.sdbcx.comp.hsqldb.Driver"));
+
+
+ TestCacheSize test = new TestCacheSize(info,drv);
+
+ StopWatch sw = new StopWatch();
+
+ try{
+ test.setUp();
+ test.testFillUp();
+ test.checkResults();
+ test.tearDown();
+ System.out.println("Total Test Time: " + sw.elapsedTime());
+ } catch(Exception e){}
+
+ try{
+ XStorable mod2 = UnoRuntime.queryInterface(XStorable.class,ds);
+ mod2.store();
+ } catch(Exception e){}
+ }catch(Exception e){}
+ }
+
+ public void test2(){
+ System.gc();
+
+ try{
+ com.sun.star.beans.PropertyValue[] info = new com.sun.star.beans.PropertyValue[]{
+ new com.sun.star.beans.PropertyValue("JavaDriverClass",0,"org.hsqldb.jdbcDriver",PropertyState.DIRECT_VALUE)
+ ,new com.sun.star.beans.PropertyValue("ParameterNameSubstitution",0, false,PropertyState.DIRECT_VALUE)
+ };
+ XDriver drv = UnoRuntime.queryInterface(XDriver.class,param.getMSF().createInstance("com.sun.star.comp.sdbc.JDBCDriver"));
+ TestCacheSize test = new TestCacheSize(info,drv);
+ test.setURL("jdbc:hsqldb:g:\\hsql\\db");
+
+
+ StopWatch sw = new StopWatch();
+
+ try{
+ test.setUp();
+ test.testFillUp();
+ test.checkResults();
+ test.tearDown();
+ System.out.println("Total Test Time: " + sw.elapsedTime());
+ } catch(Exception e){}
+ }catch(Exception e){}
+ }
+}
diff --git a/connectivity/qa/complex/connectivity/JdbcLongVarCharTest.java b/connectivity/qa/complex/connectivity/JdbcLongVarCharTest.java
new file mode 100644
index 0000000000..3817add48d
--- /dev/null
+++ b/connectivity/qa/complex/connectivity/JdbcLongVarCharTest.java
@@ -0,0 +1,125 @@
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+package complex.connectivity;
+
+import com.sun.star.beans.PropertyState;
+import com.sun.star.beans.PropertyValue;
+import com.sun.star.lang.XMultiServiceFactory;
+import com.sun.star.sdbc.XResultSet;
+import com.sun.star.sdbc.XClob;
+import com.sun.star.sdbc.XDriverAccess;
+import com.sun.star.sdbc.XParameters;
+import com.sun.star.sdbc.XPreparedStatement;
+import com.sun.star.sdbc.XResultSetMetaData;
+import com.sun.star.sdbc.XResultSetMetaDataSupplier;
+import com.sun.star.sdbc.XRow;
+import com.sun.star.uno.UnoRuntime;
+import complexlib.ComplexTestCase;
+
+public class JdbcLongVarCharTest extends ComplexTestCase
+{
+
+ @Override
+ public String[] getTestMethodNames()
+ {
+ return new String[]
+ {
+ "testLongVarChar"
+ };
+ }
+
+ @Override
+ public String getTestObjectName()
+ {
+ return "LongVarCharTest";
+ }
+
+ public void testLongVarChar()
+ {
+
+ try
+ {
+ System.out.println("== Start testing ==");
+
+ /* Get URL from environment variable.
+ *
+ * Example URL:
+ * jdbc:mysql://localhost:3306/mysql?user=username&password=password
+ */
+ String url = System.getenv("CONNECTIVITY_TEST_MYSQL_DRIVER_JDBC");
+ com.sun.star.beans.PropertyValue prop[] = new PropertyValue[1];
+ prop[0] = new PropertyValue("JavaDriverClass", 0, "com.mysql.jdbc.Driver", PropertyState.DIRECT_VALUE);
+
+ // get the remote office component context
+ XMultiServiceFactory xServiceManager = param.getMSF();
+ Object x = xServiceManager.createInstance("com.sun.star.sdbc.DriverManager");
+ com.sun.star.sdbc.XDriverAccess xDriverAccess = UnoRuntime.queryInterface(XDriverAccess.class, x);
+ com.sun.star.sdbc.XDriver xDriver = xDriverAccess.getDriverByURL(url);
+ com.sun.star.sdbc.XConnection xConnection = xDriver.connect(url, prop);
+
+ Object prepStmnt = xConnection.prepareStatement("SELECT * FROM i90114 WHERE i90114.c1 = ?");
+ UnoRuntime.queryInterface(XParameters.class, prepStmnt).clearParameters();
+ UnoRuntime.queryInterface(XParameters.class, prepStmnt).setInt(1, 1);
+ XResultSet xResultSet = ((XPreparedStatement) prepStmnt).executeQuery();
+ XRow xRow = UnoRuntime.queryInterface(XRow.class, xResultSet);
+
+ XResultSetMetaDataSupplier xRsMetaSup = UnoRuntime.queryInterface(XResultSetMetaDataSupplier.class, xResultSet);
+ XResultSetMetaData xRsMetaData = xRsMetaSup.getMetaData();
+ int nColumnCount = xRsMetaData.getColumnCount();
+
+ System.out.println("== MetaData ==");
+ for (int i = 1; i <= nColumnCount; ++i)
+ {
+ System.out.println("Name: " + xRsMetaData.getColumnName(i) + " Type: " +
+ xRsMetaData.getColumnType(i));
+ }
+
+ System.out.println("== Result ==");
+ while (xResultSet.next())
+ {
+ String str = "not set";
+
+ XClob xClob = xRow.getClob(2);
+ if (xClob != null)
+ {
+ System.out.println("xClob != null");
+ int len = (int) xClob.length();
+ str = xClob.getSubString(1, len);
+ }
+ else
+ {
+ System.out.println("xClob == null");
+ }
+
+ System.out.println("c1 (Int): " + xRow.getInt(1) + " c2 (String): " + xRow.getString(2) + " c3 (Clob): " + str);
+ }
+
+ xConnection.close();
+ }
+ catch (java.lang.Exception e)
+ {
+ System.out.println("== Exception occurred while testing ==");
+ e.printStackTrace();
+ } finally
+ {
+ System.out.println("== End testing ==");
+ System.exit(0);
+ }
+ }
+}
diff --git a/connectivity/qa/complex/connectivity/SubTestCase.java b/connectivity/qa/complex/connectivity/SubTestCase.java
new file mode 100644
index 0000000000..7abffa844e
--- /dev/null
+++ b/connectivity/qa/complex/connectivity/SubTestCase.java
@@ -0,0 +1,41 @@
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+package complex.connectivity;
+
+import share.LogWriter;
+
+public class SubTestCase implements TestCase
+{
+ protected SubTestCase( final TestCase i_parentTestCase )
+ {
+ m_parentTestCase = i_parentTestCase;
+ }
+
+ public void assure( String i_message, boolean i_condition )
+ {
+ m_parentTestCase.assure( i_message, i_condition );
+ }
+
+ public LogWriter getLog()
+ {
+ return m_parentTestCase.getLog();
+ }
+
+ private final TestCase m_parentTestCase;
+}
diff --git a/connectivity/qa/complex/connectivity/TestCase.java b/connectivity/qa/complex/connectivity/TestCase.java
new file mode 100644
index 0000000000..9261499af5
--- /dev/null
+++ b/connectivity/qa/complex/connectivity/TestCase.java
@@ -0,0 +1,27 @@
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+package complex.connectivity;
+
+import share.LogWriter;
+
+public interface TestCase
+{
+ void assure( final String i_message, final boolean i_condition );
+ LogWriter getLog();
+}
diff --git a/connectivity/qa/complex/connectivity/dbase/DBaseDateFunctions.java b/connectivity/qa/complex/connectivity/dbase/DBaseDateFunctions.java
new file mode 100644
index 0000000000..85975b4816
--- /dev/null
+++ b/connectivity/qa/complex/connectivity/dbase/DBaseDateFunctions.java
@@ -0,0 +1,296 @@
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+package complex.connectivity.dbase;
+
+import com.sun.star.uno.UnoRuntime;
+import com.sun.star.sdbc.*;
+import com.sun.star.beans.XPropertySet;
+
+import com.sun.star.lang.XMultiServiceFactory;
+import complex.connectivity.TestCase;
+import complex.connectivity.SubTestCase;
+
+public class DBaseDateFunctions extends SubTestCase
+{
+
+ private static final String where = "FROM \"biblio\" \"biblio\" where \"Identifier\" = 'BOR00'";
+ private final XMultiServiceFactory m_xORB;
+
+ public DBaseDateFunctions(final XMultiServiceFactory _xORB, final TestCase i_testCase)
+ {
+ super( i_testCase );
+ m_xORB = _xORB;
+ }
+
+ public void testFunctions() throws com.sun.star.uno.Exception, com.sun.star.beans.UnknownPropertyException
+ {
+ final XRowSet xRowRes = UnoRuntime.queryInterface(XRowSet.class,
+ m_xORB.createInstance("com.sun.star.sdb.RowSet"));
+
+ getLog().println("starting DateTime function test!");
+ // set the properties needed to connect to a database
+ final XPropertySet xProp = UnoRuntime.queryInterface(XPropertySet.class, xRowRes);
+ xProp.setPropertyValue("DataSourceName", "Bibliography");
+
+ xProp.setPropertyValue("CommandType", Integer.valueOf(com.sun.star.sdb.CommandType.COMMAND));
+
+ try
+ {
+ curdate(xRowRes);
+ }
+ catch (SQLException ex)
+ {
+ assure("upper " + ex.getMessage(), false);
+ throw ex;
+ }
+ try
+ {
+ curtime(xRowRes);
+ }
+ catch (SQLException ex)
+ {
+ assure("lower " + ex.getMessage(), false);
+ throw ex;
+ }
+ try
+ {
+ dayname(xRowRes);
+ }
+ catch (SQLException ex)
+ {
+ assure("ascii " + ex.getMessage(), false);
+ throw ex;
+ }
+ try
+ {
+ dayofmonth(xRowRes);
+ }
+ catch (SQLException ex)
+ {
+ assure("char_len " + ex.getMessage(), false);
+ throw ex;
+ }
+ try
+ {
+ dayofweek(xRowRes);
+ }
+ catch (SQLException ex)
+ {
+ assure("concat " + ex.getMessage(), false);
+ throw ex;
+ }
+ try
+ {
+ dayofyear(xRowRes);
+ }
+ catch (SQLException ex)
+ {
+ assure("locate " + ex.getMessage(), false);
+ throw ex;
+ }
+ try
+ {
+ hour(xRowRes);
+ }
+ catch (SQLException ex)
+ {
+ assure("substr " + ex.getMessage(), false);
+ throw ex;
+ }
+ try
+ {
+ minute(xRowRes);
+ }
+ catch (SQLException ex)
+ {
+ assure("ltrim " + ex.getMessage(), false);
+ throw ex;
+ }
+ try
+ {
+ month(xRowRes);
+ }
+ catch (SQLException ex)
+ {
+ assure("rtrim " + ex.getMessage(), false);
+ throw ex;
+ }
+ try
+ {
+ monthname(xRowRes);
+ }
+ catch (SQLException ex)
+ {
+ assure("space " + ex.getMessage(), false);
+ throw ex;
+ }
+ try
+ {
+ now(xRowRes);
+ }
+ catch (SQLException ex)
+ {
+ assure("replace " + ex.getMessage(), false);
+ throw ex;
+ }
+ try
+ {
+ quarter(xRowRes);
+ }
+ catch (SQLException ex)
+ {
+ assure("repeat " + ex.getMessage(), false);
+ throw ex;
+ }
+ try
+ {
+ second(xRowRes);
+ }
+ catch (SQLException ex)
+ {
+ assure("insert " + ex.getMessage(), false);
+ throw ex;
+ }
+ try
+ {
+ week(xRowRes);
+ }
+ catch (SQLException ex)
+ {
+ assure("left " + ex.getMessage(), false);
+ throw ex;
+ }
+ try
+ {
+ year(xRowRes);
+ }
+ catch (SQLException ex)
+ {
+ assure("right " + ex.getMessage(), false);
+ throw ex;
+ }
+ }
+
+ private XRow execute(final XRowSet xRowRes, final String sql) throws com.sun.star.uno.Exception, com.sun.star.beans.UnknownPropertyException
+ {
+ final XPropertySet xProp = UnoRuntime.queryInterface(XPropertySet.class, xRowRes);
+ xProp.setPropertyValue("Command", "SELECT " + sql + where);
+ xRowRes.execute();
+ final XResultSet xRes = UnoRuntime.queryInterface(XResultSet.class, xRowRes);
+ assure("No valid row! ", xRes.next());
+
+ return UnoRuntime.queryInterface(XRow.class, xRes);
+ }
+
+ private void dayofweek(final XRowSet xRowRes) throws com.sun.star.uno.Exception, com.sun.star.beans.UnknownPropertyException
+ {
+ final XRow row = execute(xRowRes, "DAYOFWEEK('1998-02-03') ");
+ assure("DAYOFWEEK('1998-02-03') failed!", row.getInt(1) == 3);
+ }
+
+ private void dayofmonth(final XRowSet xRowRes) throws com.sun.star.uno.Exception, com.sun.star.beans.UnknownPropertyException
+ {
+ final XRow row = execute(xRowRes, "DAYOFMONTH('1998-02-03') ");
+ assure("DAYOFMONTH('1998-02-03') failed!", row.getInt(1) == 3);
+ }
+
+ private void dayofyear(final XRowSet xRowRes) throws com.sun.star.uno.Exception, com.sun.star.beans.UnknownPropertyException
+ {
+ final XRow row = execute(xRowRes, "DAYOFYEAR('1998-02-03') ");
+ assure("DAYOFYEAR('1998-02-03') failed!", row.getInt(1) == 34);
+ }
+
+ private void month(final XRowSet xRowRes) throws com.sun.star.uno.Exception, com.sun.star.beans.UnknownPropertyException
+ {
+ final XRow row = execute(xRowRes, "month('1998-02-03') ");
+ assure("month('1998-02-03') failed!", row.getInt(1) == 2);
+ }
+
+ private void dayname(final XRowSet xRowRes) throws com.sun.star.uno.Exception, com.sun.star.beans.UnknownPropertyException
+ {
+ final XRow row = execute(xRowRes, "DAYNAME('1998-02-05') ");
+ assure("DAYNAME('1998-02-05') failed!", row.getString(1).equals("Thursday"));
+ }
+
+ private void monthname(final XRowSet xRowRes) throws com.sun.star.uno.Exception, com.sun.star.beans.UnknownPropertyException
+ {
+ final XRow row = execute(xRowRes, "MONTHNAME('1998-02-05') ");
+ assure("MONTHNAME('1998-02-05') failed!", row.getString(1).equals("February"));
+ }
+
+ private void quarter(final XRowSet xRowRes) throws com.sun.star.uno.Exception, com.sun.star.beans.UnknownPropertyException
+ {
+ final XRow row = execute(xRowRes, "QUARTER('98-01-01'),QUARTER('98-04-01'),QUARTER('98-07-01'),QUARTER('98-10-01') ");
+ assure("QUARTER('98-01-01') failed!", row.getInt(1) == 1);
+ assure("QUARTER('98-04-01') failed!", row.getInt(2) == 2);
+ assure("QUARTER('98-07-01') failed!", row.getInt(3) == 3);
+ assure("QUARTER('98-10-01') failed!", row.getInt(4) == 4);
+ }
+
+ private void week(final XRowSet xRowRes) throws com.sun.star.uno.Exception, com.sun.star.beans.UnknownPropertyException
+ {
+ final XRow row = execute(xRowRes, "WEEK('1998-02-20') ");
+ assure("WEEK('1998-02-20') failed!", row.getInt(1) == 7);
+ }
+
+ private void year(final XRowSet xRowRes) throws com.sun.star.uno.Exception, com.sun.star.beans.UnknownPropertyException
+ {
+ final XRow row = execute(xRowRes, "YEAR('98-02-03') ");
+ assure("YEAR('98-02-03') failed!", row.getInt(1) == 98);
+ }
+
+ private void hour(final XRowSet xRowRes) throws com.sun.star.uno.Exception, com.sun.star.beans.UnknownPropertyException
+ {
+ final XRow row = execute(xRowRes, "HOUR('10:05:03') ");
+ assure("HOUR('10:05:03') failed!", row.getInt(1) == 10);
+ }
+
+ private void minute(final XRowSet xRowRes) throws com.sun.star.uno.Exception, com.sun.star.beans.UnknownPropertyException
+ {
+ final XRow row = execute(xRowRes, "MINUTE('98-02-03 10:05:03') ");
+ assure("MINUTE('98-02-03 10:05:03') failed!", row.getInt(1) == 5);
+ }
+
+ private void second(final XRowSet xRowRes) throws com.sun.star.uno.Exception, com.sun.star.beans.UnknownPropertyException
+ {
+ final XRow row = execute(xRowRes, "SECOND('10:05:03') ");
+ assure("SECOND('10:05:03') failed!", row.getInt(1) == 3);
+ }
+
+ private void curdate(final XRowSet xRowRes) throws com.sun.star.uno.Exception, com.sun.star.beans.UnknownPropertyException
+ {
+ final XRow row = execute(xRowRes, "CURDATE() ");
+ final com.sun.star.util.Date aDate = row.getDate(1);
+ getLog().println("CURDATE() is '" + aDate.Year + "-" + aDate.Month + "-" + aDate.Day + "'");
+ }
+
+ private void curtime(final XRowSet xRowRes) throws com.sun.star.uno.Exception, com.sun.star.beans.UnknownPropertyException
+ {
+ final XRow row = execute(xRowRes, "CURTIME() ");
+ final com.sun.star.util.Time aTime = row.getTime(1);
+ getLog().println("CURTIME() is '" + aTime.Hours + ":" + aTime.Minutes + ":" + aTime.Seconds + "'");
+ }
+
+ private void now(final XRowSet xRowRes) throws com.sun.star.uno.Exception, com.sun.star.beans.UnknownPropertyException
+ {
+ final XRow row = execute(xRowRes, "NOW() ");
+ final com.sun.star.util.DateTime aTime = row.getTimestamp(1);
+ getLog().println("NOW() is '" + aTime.Year + "-" + aTime.Month + "-" + aTime.Day + "'");
+ getLog().println("'" + aTime.Hours + ":" + aTime.Minutes + ":" + aTime.Seconds + "'");
+ }
+}
diff --git a/connectivity/qa/complex/connectivity/dbase/DBaseNumericFunctions.java b/connectivity/qa/complex/connectivity/dbase/DBaseNumericFunctions.java
new file mode 100644
index 0000000000..218f02b0af
--- /dev/null
+++ b/connectivity/qa/complex/connectivity/dbase/DBaseNumericFunctions.java
@@ -0,0 +1,388 @@
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+package complex.connectivity.dbase;
+
+import com.sun.star.uno.UnoRuntime;
+import com.sun.star.sdbc.*;
+import com.sun.star.beans.XPropertySet;
+import com.sun.star.lang.XMultiServiceFactory;
+import complex.connectivity.SubTestCase;
+import complex.connectivity.TestCase;
+
+
+public class DBaseNumericFunctions extends SubTestCase
+{
+ private static final String where = "FROM \"biblio\" \"biblio\" where \"Identifier\" = 'BOR00'";
+ private final XMultiServiceFactory m_xORB;
+
+ public DBaseNumericFunctions(final XMultiServiceFactory _xORB, final TestCase i_testCase)
+ {
+ super( i_testCase );
+ m_xORB = _xORB;
+ }
+
+ public void testFunctions() throws com.sun.star.uno.Exception, com.sun.star.beans.UnknownPropertyException
+ {
+ final XRowSet xRowRes = UnoRuntime.queryInterface(XRowSet.class,
+ m_xORB.createInstance("com.sun.star.sdb.RowSet"));
+
+ getLog().println("starting Numeric function test");
+ // set the properties needed to connect to a database
+ final XPropertySet xProp = UnoRuntime.queryInterface(XPropertySet.class, xRowRes);
+ xProp.setPropertyValue("DataSourceName", "Bibliography");
+
+ xProp.setPropertyValue("CommandType", Integer.valueOf(com.sun.star.sdb.CommandType.COMMAND));
+
+ try
+ {
+ abs(xRowRes);
+ }
+ catch (SQLException ex)
+ {
+ assure("abs " + ex.getMessage(), false);
+ throw ex;
+ }
+ try
+ {
+ acos(xRowRes);
+ }
+ catch (SQLException ex)
+ {
+ assure("acos " + ex.getMessage(), false);
+ throw ex;
+ }
+ try
+ {
+ asin(xRowRes);
+ }
+ catch (SQLException ex)
+ {
+ assure("asin " + ex.getMessage(), false);
+ throw ex;
+ }
+ try
+ {
+ atan(xRowRes);
+ }
+ catch (SQLException ex)
+ {
+ assure("atan " + ex.getMessage(), false);
+ throw ex;
+ }
+ try
+ {
+ atan2(xRowRes);
+ }
+ catch (SQLException ex)
+ {
+ assure("atan2 " + ex.getMessage(), false);
+ throw ex;
+ }
+ try
+ {
+ ceiling(xRowRes);
+ }
+ catch (SQLException ex)
+ {
+ assure("ceiling " + ex.getMessage(), false);
+ throw ex;
+ }
+ try
+ {
+ cos(xRowRes);
+ }
+ catch (SQLException ex)
+ {
+ assure("cos " + ex.getMessage(), false);
+ throw ex;
+ }
+ try
+ {
+ degrees(xRowRes);
+ }
+ catch (SQLException ex)
+ {
+ assure("degrees " + ex.getMessage(), false);
+ throw ex;
+ }
+ try
+ {
+ exp(xRowRes);
+ }
+ catch (SQLException ex)
+ {
+ assure("exp " + ex.getMessage(), false);
+ throw ex;
+ }
+ try
+ {
+ floor(xRowRes);
+ }
+ catch (SQLException ex)
+ {
+ assure("floor " + ex.getMessage(), false);
+ throw ex;
+ }
+ try
+ {
+ log(xRowRes);
+ }
+ catch (SQLException ex)
+ {
+ assure("log " + ex.getMessage(), false);
+ throw ex;
+ }
+ try
+ {
+ log10(xRowRes);
+ }
+ catch (SQLException ex)
+ {
+ assure("log10 " + ex.getMessage(), false);
+ throw ex;
+ }
+ try
+ {
+ mod(xRowRes);
+ }
+ catch (SQLException ex)
+ {
+ assure("mod " + ex.getMessage(), false);
+ throw ex;
+ }
+ try
+ {
+ pi(xRowRes);
+ }
+ catch (SQLException ex)
+ {
+ assure("pi " + ex.getMessage(), false);
+ throw ex;
+ }
+ try
+ {
+ pow(xRowRes);
+ }
+ catch (SQLException ex)
+ {
+ assure("pow " + ex.getMessage(), false);
+ throw ex;
+ }
+ try
+ {
+ radians(xRowRes);
+ }
+ catch (SQLException ex)
+ {
+ assure("radians " + ex.getMessage(), false);
+ throw ex;
+ }
+ try
+ {
+ round(xRowRes);
+ }
+ catch (SQLException ex)
+ {
+ assure("round " + ex.getMessage(), false);
+ throw ex;
+ }
+ try
+ {
+ sign(xRowRes);
+ }
+ catch (SQLException ex)
+ {
+ assure("sign " + ex.getMessage(), false);
+ throw ex;
+ }
+ try
+ {
+ sin(xRowRes);
+ }
+ catch (SQLException ex)
+ {
+ assure("sin " + ex.getMessage(), false);
+ throw ex;
+ }
+ try
+ {
+ sqrt(xRowRes);
+ }
+ catch (SQLException ex)
+ {
+ assure("sqrt " + ex.getMessage(), false);
+ throw ex;
+ }
+ try
+ {
+ tan(xRowRes);
+ }
+ catch (SQLException ex)
+ {
+ assure("tan " + ex.getMessage(), false);
+ throw ex;
+ }
+
+ }
+
+ private XRow execute(final XRowSet xRowRes,final String sql) throws com.sun.star.uno.Exception, com.sun.star.beans.UnknownPropertyException
+ {
+ final XPropertySet xProp = UnoRuntime.queryInterface(XPropertySet.class, xRowRes);
+ xProp.setPropertyValue("Command", "SELECT " + sql + where);
+ xRowRes.execute();
+ final XResultSet xRes = UnoRuntime.queryInterface(XResultSet.class, xRowRes);
+ assure("No valid row! ", xRes.next());
+
+ return UnoRuntime.queryInterface(XRow.class, xRes);
+ }
+
+ private void abs(final XRowSet xRowRes) throws com.sun.star.uno.Exception, com.sun.star.beans.UnknownPropertyException
+ {
+ final XRow row = execute(xRowRes, "ABS(2),ABS(-32) ");
+ assure("ABS(2) failed!", row.getInt(1) == 2);
+ assure("ABS(-32) failed!", row.getInt(2) == 32);
+ }
+
+ private void sign(final XRowSet xRowRes) throws com.sun.star.uno.Exception, com.sun.star.beans.UnknownPropertyException
+ {
+ final XRow row = execute(xRowRes, "SIGN(-32),SIGN(0),SIGN(234) ");
+ assure("SIGN(-32)failed!", row.getInt(1) == -1);
+ assure("SIGN(0) failed!", row.getInt(2) == 0);
+ assure("SIGN(234) failed!", row.getInt(3) == 1);
+ }
+
+ private void mod(final XRowSet xRowRes) throws com.sun.star.uno.Exception, com.sun.star.beans.UnknownPropertyException
+ {
+ final XRow row = execute(xRowRes, "MOD(234, 10) ");
+ assure("MOD(234, 10) failed!", row.getInt(1) == 4);
+ }
+
+ private void floor(final XRowSet xRowRes) throws com.sun.star.uno.Exception, com.sun.star.beans.UnknownPropertyException
+ {
+ final XRow row = execute(xRowRes, "FLOOR(1.23),FLOOR(-1.23) ");
+ assure("FLOOR(1.23) failed!", row.getInt(1) == 1);
+ assure("FLOOR(-1.23) failed!", row.getInt(2) == -2);
+ }
+
+ private void ceiling(final XRowSet xRowRes) throws com.sun.star.uno.Exception, com.sun.star.beans.UnknownPropertyException
+ {
+ final XRow row = execute(xRowRes, "CEILING(1.23),CEILING(-1.23) ");
+ assure("CEILING(1.23) failed!", row.getInt(1) == 2);
+ assure("CEILING(-1.23) failed!", row.getInt(2) == -1);
+ }
+
+ private void round(final XRowSet xRowRes) throws com.sun.star.uno.Exception, com.sun.star.beans.UnknownPropertyException
+ {
+ final XRow row = execute(xRowRes, "ROUND(-1.23),ROUND(1.298, 1) ");
+ assure("ROUND(-1.23) failed!", row.getInt(1) == -1);
+ assure("ROUND(1.298, 1) failed!", row.getDouble(2) == 1.3);
+ }
+
+ private void exp(final XRowSet xRowRes) throws com.sun.star.uno.Exception, com.sun.star.beans.UnknownPropertyException
+ {
+ final XRow row = execute(xRowRes, "EXP(2),EXP(-2) ");
+ assure("EXP(2) failed!", (float) row.getDouble(1) == (float) Math.exp(2));
+ assure("EXP(-2) failed!", (float) row.getDouble(2) == (float) Math.exp(-2));
+ }
+
+ private void log(final XRowSet xRowRes) throws com.sun.star.uno.Exception, com.sun.star.beans.UnknownPropertyException
+ {
+ final XRow row = execute(xRowRes, "LOG(2),LOG(-2) ");
+ assure("LOG(2) failed!", (float) row.getDouble(1) == (float) Math.log(2));
+ row.getDouble(2);
+ assure("LOG(-2) failed!", row.wasNull());
+ }
+
+ private void log10(final XRowSet xRowRes) throws com.sun.star.uno.Exception, com.sun.star.beans.UnknownPropertyException
+ {
+ final XRow row = execute(xRowRes, "LOG10(100) ");
+ assure("LOG10(100) failed!", row.getDouble(1) == 2.0);
+ }
+
+ private void pow(final XRowSet xRowRes) throws com.sun.star.uno.Exception, com.sun.star.beans.UnknownPropertyException
+ {
+ final XRow row = execute(xRowRes, "POWER(2,2) ");
+ assure("POWER(2,2) failed!", row.getDouble(1) == 4.0);
+ }
+
+ private void sqrt(final XRowSet xRowRes) throws com.sun.star.uno.Exception, com.sun.star.beans.UnknownPropertyException
+ {
+ final XRow row = execute(xRowRes, "SQRT(4) ");
+ assure("SQRT(4) failed!", row.getDouble(1) == 2.0);
+ }
+
+ private void pi(final XRowSet xRowRes) throws com.sun.star.uno.Exception, com.sun.star.beans.UnknownPropertyException
+ {
+ final XRow row = execute(xRowRes, "PI() ");
+ assure("PI() failed!", (float) row.getDouble(1) == (float) Math.PI);
+ }
+
+ private void cos(final XRowSet xRowRes) throws com.sun.star.uno.Exception, com.sun.star.beans.UnknownPropertyException
+ {
+ final XRow row = execute(xRowRes, "COS(PI()) ");
+ assure("COS(PI()) failed!", row.getDouble(1) == -1.0);
+ }
+
+ private void sin(final XRowSet xRowRes) throws com.sun.star.uno.Exception, com.sun.star.beans.UnknownPropertyException
+ {
+ final XRow row = execute(xRowRes, "SIN(2) ");
+ assure("SIN(PI()) failed!", (float) row.getDouble(1) == (float) Math.sin(2));
+ }
+
+ private void tan(final XRowSet xRowRes) throws com.sun.star.uno.Exception, com.sun.star.beans.UnknownPropertyException
+ {
+ final XRow row = execute(xRowRes, "TAN(PI()+1) ");
+ assure("TAN(PI()+1) failed!", (float) row.getDouble(1) == (float) Math.tan(Math.PI + 1.0));
+ }
+
+ private void acos(final XRowSet xRowRes) throws com.sun.star.uno.Exception, com.sun.star.beans.UnknownPropertyException
+ {
+ final XRow row = execute(xRowRes, "ACOS(1) ");
+ assure("ACOS(1) failed!", (float) row.getDouble(1) == 0.0);
+ }
+
+ private void asin(final XRowSet xRowRes) throws com.sun.star.uno.Exception, com.sun.star.beans.UnknownPropertyException
+ {
+ final XRow row = execute(xRowRes, "ASIN(0) ");
+ assure("ASIN(0) failed!", (float) row.getDouble(1) == 0.0);
+ }
+
+ private void atan(final XRowSet xRowRes) throws com.sun.star.uno.Exception, com.sun.star.beans.UnknownPropertyException
+ {
+ final XRow row = execute(xRowRes, "ATAN(0) ");
+ assure("ATAN(0) failed!", row.getDouble(1) == 0.0);
+ }
+
+ private void atan2(final XRowSet xRowRes) throws com.sun.star.uno.Exception, com.sun.star.beans.UnknownPropertyException
+ {
+ final XRow row = execute(xRowRes, "ATAN2(0,2) ");
+ assure("ATAN2(0,2) failed!", (float) row.getDouble(1) == 0.0);
+ }
+
+ private void degrees(final XRowSet xRowRes) throws com.sun.star.uno.Exception, com.sun.star.beans.UnknownPropertyException
+ {
+ final XRow row = execute(xRowRes, "DEGREES(PI()) ");
+ assure("DEGREES(PI()) failed!", row.getDouble(1) == 180.0);
+ }
+
+ private void radians(final XRowSet xRowRes) throws com.sun.star.uno.Exception, com.sun.star.beans.UnknownPropertyException
+ {
+ final XRow row = execute(xRowRes, "RADIANS(90) ");
+ assure("RADIANS(90) failed!", (float) row.getDouble(1) == (float) (Math.PI / 2.0));
+ }
+}
diff --git a/connectivity/qa/complex/connectivity/dbase/DBaseSqlTests.java b/connectivity/qa/complex/connectivity/dbase/DBaseSqlTests.java
new file mode 100644
index 0000000000..09f7cac227
--- /dev/null
+++ b/connectivity/qa/complex/connectivity/dbase/DBaseSqlTests.java
@@ -0,0 +1,80 @@
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+package complex.connectivity.dbase;
+
+import com.sun.star.uno.UnoRuntime;
+import com.sun.star.sdbc.*;
+import com.sun.star.beans.XPropertySet;
+import com.sun.star.lang.XMultiServiceFactory;
+import complex.connectivity.TestCase;
+import complex.connectivity.SubTestCase;
+
+public class DBaseSqlTests extends SubTestCase
+{
+ private final XMultiServiceFactory m_xORB;
+
+ public DBaseSqlTests(final XMultiServiceFactory _xORB,final TestCase i_testCase)
+ {
+ super( i_testCase );
+ m_xORB = _xORB;
+ }
+
+ public void testFunctions() throws com.sun.star.uno.Exception, com.sun.star.beans.UnknownPropertyException
+ {
+ final XRowSet xRowRes = UnoRuntime.queryInterface(XRowSet.class,
+ m_xORB.createInstance("com.sun.star.sdb.RowSet"));
+
+ getLog().println("starting SQL test");
+ // set the properties needed to connect to a database
+ final XPropertySet xProp = UnoRuntime.queryInterface(XPropertySet.class, xRowRes);
+ xProp.setPropertyValue("DataSourceName", "Bibliography");
+ xProp.setPropertyValue("CommandType", Integer.valueOf(com.sun.star.sdb.CommandType.COMMAND));
+
+ execute(xRowRes,"1 FROM \"biblio\" \"biblio\" where \"Identifier\" like 'B%'");
+ execute(xRowRes,"1 FROM \"biblio\" \"biblio\" where not \"Identifier\" like 'B%'");
+ execute(xRowRes,"1 FROM \"biblio\" \"biblio\" where not \"Identifier\" not like 'B%'");
+ execute(xRowRes,"1 FROM \"biblio\" \"biblio\" where not(0 = 1)");
+ execute(xRowRes,"1 FROM \"biblio\" \"biblio\" where 0 = 0");
+ execute(xRowRes,"1 FROM \"biblio\" \"biblio\" where (0 = 0)");
+ execute(xRowRes,"1 FROM \"biblio\" \"biblio\" where 0 <> 1");
+ execute(xRowRes,"1 FROM \"biblio\" \"biblio\" where 0 < 1");
+ execute(xRowRes,"1 FROM \"biblio\" \"biblio\" where 2 > 1");
+ execute(xRowRes,"1,1+1,'a' + 'b' FROM \"biblio\" \"biblio\" where 2 > 1");
+ execute(xRowRes,"1 FROM \"biblio\" \"biblio\" where not \"Identifier\" is NULL");
+ execute(xRowRes,"1 FROM \"biblio\" \"biblio\" where \"Identifier\" is not NULL");
+ execute(xRowRes,"1 FROM \"biblio\" \"biblio\" where \"Identifier\" = \"Identifier\"");
+ execute(xRowRes,"1 FROM \"biblio\" \"biblio\" where not(not(\"Identifier\" = \"Identifier\"))");
+ execute(xRowRes,"1 FROM \"biblio\" \"biblio\" where (1 = 1 and 2 = 1) or 3 = 33 or 4 = 44 or ('a' = 'a' and 'b' = 'b')");
+ }
+
+ private void execute(final XRowSet xRowRes, String sql) throws com.sun.star.uno.Exception, com.sun.star.beans.UnknownPropertyException
+ {
+ try
+ {
+ final XPropertySet xProp = UnoRuntime.queryInterface(XPropertySet.class, xRowRes);
+ xProp.setPropertyValue("Command", "SELECT " + sql);
+ xRowRes.execute();
+ }
+ catch(SQLException e)
+ {
+ getLog().println(sql + " Error: " + e.getMessage());
+ }
+ }
+
+
+}
diff --git a/connectivity/qa/complex/connectivity/dbase/DBaseStringFunctions.java b/connectivity/qa/complex/connectivity/dbase/DBaseStringFunctions.java
new file mode 100644
index 0000000000..4d5dc2dd62
--- /dev/null
+++ b/connectivity/qa/complex/connectivity/dbase/DBaseStringFunctions.java
@@ -0,0 +1,310 @@
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+package complex.connectivity.dbase;
+
+import com.sun.star.uno.UnoRuntime;
+import com.sun.star.sdbc.*;
+import com.sun.star.beans.XPropertySet;
+import com.sun.star.lang.XMultiServiceFactory;
+import complex.connectivity.SubTestCase;
+import complex.connectivity.TestCase;
+
+public class DBaseStringFunctions extends SubTestCase
+{
+ private String where = "FROM \"biblio\" \"biblio\" where \"Identifier\" = 'BOR00'";
+ private final XMultiServiceFactory m_xORB;
+
+ public DBaseStringFunctions(final XMultiServiceFactory _xORB,final TestCase i_testCase)
+ {
+ super( i_testCase );
+ m_xORB = _xORB;
+ }
+
+ public void testFunctions() throws com.sun.star.uno.Exception, com.sun.star.beans.UnknownPropertyException
+ {
+ final XRowSet xRowRes = UnoRuntime.queryInterface(XRowSet.class,
+ m_xORB.createInstance("com.sun.star.sdb.RowSet"));
+
+ getLog().println("starting String function test");
+ // set the properties needed to connect to a database
+ final XPropertySet xProp = UnoRuntime.queryInterface(XPropertySet.class, xRowRes);
+ xProp.setPropertyValue("DataSourceName", "Bibliography");
+
+ xProp.setPropertyValue("CommandType", Integer.valueOf(com.sun.star.sdb.CommandType.COMMAND));
+
+ try
+ {
+ upper(xRowRes);
+ }
+ catch (SQLException ex)
+ {
+ assure("upper " + ex.getMessage(), false);
+ throw ex;
+ }
+ try
+ {
+ lower(xRowRes);
+ }
+ catch (SQLException ex)
+ {
+ assure("lower " + ex.getMessage(), false);
+ throw ex;
+ }
+ try
+ {
+ ascii(xRowRes);
+ }
+ catch (SQLException ex)
+ {
+ assure("ascii " + ex.getMessage(), false);
+ throw ex;
+ }
+ try
+ {
+ char_length(xRowRes);
+ }
+ catch (SQLException ex)
+ {
+ assure("char_len " + ex.getMessage(), false);
+ throw ex;
+ }
+ try
+ {
+ concat(xRowRes);
+ }
+ catch (SQLException ex)
+ {
+ assure("concat " + ex.getMessage(), false);
+ throw ex;
+ }
+ try
+ {
+ chartest(xRowRes);
+ }
+ catch (SQLException ex)
+ {
+ assure("char " + ex.getMessage(), false);
+ throw ex;
+ }
+ try
+ {
+ locate(xRowRes);
+ }
+ catch (SQLException ex)
+ {
+ assure("locate " + ex.getMessage(), false);
+ throw ex;
+ }
+ try
+ {
+ substring(xRowRes);
+ }
+ catch (SQLException ex)
+ {
+ assure("substr " + ex.getMessage(), false);
+ throw ex;
+ }
+ try
+ {
+ ltrim(xRowRes);
+ }
+ catch (SQLException ex)
+ {
+ assure("ltrim " + ex.getMessage(), false);
+ throw ex;
+ }
+ try
+ {
+ rtrim(xRowRes);
+ }
+ catch (SQLException ex)
+ {
+ assure("rtrim " + ex.getMessage(), false);
+ throw ex;
+ }
+ try
+ {
+ space(xRowRes);
+ }
+ catch (SQLException ex)
+ {
+ assure("space " + ex.getMessage(), false);
+ throw ex;
+ }
+ try
+ {
+ replace(xRowRes);
+ }
+ catch (SQLException ex)
+ {
+ assure("replace " + ex.getMessage(), false);
+ throw ex;
+ }
+ try
+ {
+ repeat(xRowRes);
+ }
+ catch (SQLException ex)
+ {
+ assure("repeat " + ex.getMessage(), false);
+ throw ex;
+ }
+ try
+ {
+ insert(xRowRes);
+ }
+ catch (SQLException ex)
+ {
+ assure("insert " + ex.getMessage(), false);
+ throw ex;
+ }
+ try
+ {
+ left(xRowRes);
+ }
+ catch (SQLException ex)
+ {
+ assure("left " + ex.getMessage(), false);
+ throw ex;
+ }
+ try
+ {
+ right(xRowRes);
+ }
+ catch (SQLException ex)
+ {
+ assure("right " + ex.getMessage(), false);
+ throw ex;
+ }
+ }
+
+ private XRow execute(final XRowSet xRowRes, String sql) throws com.sun.star.uno.Exception, com.sun.star.beans.UnknownPropertyException
+ {
+ final XPropertySet xProp = UnoRuntime.queryInterface(XPropertySet.class, xRowRes);
+ xProp.setPropertyValue("Command", "SELECT " + sql + where);
+ xRowRes.execute();
+ final XResultSet xRes = UnoRuntime.queryInterface(XResultSet.class, xRowRes);
+ assure("No valid row! ", xRes.next());
+
+ return UnoRuntime.queryInterface(XRow.class, xRes);
+ }
+
+ private void upper(final XRowSet xRowRes) throws com.sun.star.uno.Exception, com.sun.star.beans.UnknownPropertyException
+ {
+ final XRow row = execute(xRowRes, "upper('test'),UCASE('test') ");
+ assure("upper('test') failed!", row.getString(1).equals("TEST"));
+ assure("ucase('test') failed!", row.getString(2).equals("TEST"));
+ }
+
+ private void lower(final XRowSet xRowRes) throws com.sun.star.uno.Exception, com.sun.star.beans.UnknownPropertyException
+ {
+ final XRow row = execute(xRowRes, "lower('TEST'),LCASE('TEST') ");
+ assure("lower('TEST') failed!", row.getString(1).equals("test"));
+ assure("lcase('TEST') failed!", row.getString(2).equals("test"));
+ final String temp = where;
+ where = "FROM \"biblio\" \"biblio\" where LOWER(\"Identifier\") like 'bor%'";
+ execute(xRowRes, "lower('TEST'),LCASE('TEST') ");
+ where = temp;
+ }
+
+ private void ascii(final XRowSet xRowRes) throws com.sun.star.uno.Exception, com.sun.star.beans.UnknownPropertyException
+ {
+ final XRow row = execute(xRowRes, "ASCII('2') ");
+ assure("ascii('2') failed!", row.getInt(1) == 50);
+ }
+
+ private void char_length(final XRowSet xRowRes) throws com.sun.star.uno.Exception, com.sun.star.beans.UnknownPropertyException
+ {
+ final XRow row = execute(xRowRes, "char_length('test'),character_length('test'),OCTET_LENGTH('test') ");
+ assure("char_length('test') failed!", row.getInt(1) == 4);
+ assure("character_length('test') failed!", row.getInt(2) == 4);
+ assure("OCTET_LENGTH('test') failed!", row.getInt(3) == 4);
+ }
+
+ private void concat(final XRowSet xRowRes) throws com.sun.star.uno.Exception, com.sun.star.beans.UnknownPropertyException
+ {
+ final XRow row = execute(xRowRes, "CONCAT('Hello',' ','World') ");
+ assure("CONCAT('Hello',' ',,'World') failed!", row.getString(1).equals("Hello World"));
+ }
+
+ private void locate(final XRowSet xRowRes) throws com.sun.star.uno.Exception, com.sun.star.beans.UnknownPropertyException
+ {
+ final XRow row = execute(xRowRes, "LOCATE('bar', 'foobarbar') ");
+ assure("LOCATE('bar', 'foobarbar') failed!", row.getInt(1) == 4);
+ }
+
+ private void substring(final XRowSet xRowRes) throws com.sun.star.uno.Exception, com.sun.star.beans.UnknownPropertyException
+ {
+ final XRow row = execute(xRowRes, "SUBSTRING('Quadratically',5) ");
+ assure("SUBSTRING('Quadratically',5) failed!", row.getString(1).equals("ratically"));
+ }
+
+ private void ltrim(final XRowSet xRowRes) throws com.sun.star.uno.Exception, com.sun.star.beans.UnknownPropertyException
+ {
+ final XRow row = execute(xRowRes, "LTRIM(' barbar') ");
+ assure("LTRIM(' barbar') failed!", row.getString(1).equals("barbar"));
+ }
+
+ private void rtrim(final XRowSet xRowRes) throws com.sun.star.uno.Exception, com.sun.star.beans.UnknownPropertyException
+ {
+ final XRow row = execute(xRowRes, "RTRIM('barbar ') ");
+ assure("RTRIM('barbar ') failed!", row.getString(1).equals("barbar"));
+ }
+
+ private void space(final XRowSet xRowRes) throws com.sun.star.uno.Exception, com.sun.star.beans.UnknownPropertyException
+ {
+ final XRow row = execute(xRowRes, "space(6) ");
+ assure("space(6) failed!", row.getString(1).equals(" "));
+ }
+
+ private void replace(final XRowSet xRowRes) throws com.sun.star.uno.Exception, com.sun.star.beans.UnknownPropertyException
+ {
+ final XRow row = execute(xRowRes, "REPLACE('www.OOo.com', 'w', 'Ww') ");
+ assure("REPLACE('www.OOo.com', 'w', 'Ww') failed!", row.getString(1).equals("WwWwWw.OOo.com"));
+ }
+
+ private void repeat(final XRowSet xRowRes) throws com.sun.star.uno.Exception, com.sun.star.beans.UnknownPropertyException
+ {
+ final XRow row = execute(xRowRes, "REPEAT('OOo', 3) ");
+ assure("REPEAT('OOo', 3) failed!", row.getString(1).equals("OOoOOoOOo"));
+ }
+
+ private void insert(final XRowSet xRowRes) throws com.sun.star.uno.Exception, com.sun.star.beans.UnknownPropertyException
+ {
+ final XRow row = execute(xRowRes, "INSERT('Quadratic', 3, 4, 'What') ");
+ assure("INSERT('Quadratic', 3, 4, 'What') failed!", row.getString(1).equals("QuWhattic"));
+ }
+
+ private void left(final XRowSet xRowRes) throws com.sun.star.uno.Exception, com.sun.star.beans.UnknownPropertyException
+ {
+ final XRow row = execute(xRowRes, "LEFT('foobarbar', 5) ");
+ assure("LEFT('foobarbar', 5) failed!", row.getString(1).equals("fooba"));
+ }
+
+ private void right(final XRowSet xRowRes) throws com.sun.star.uno.Exception, com.sun.star.beans.UnknownPropertyException
+ {
+ final XRow row = execute(xRowRes, "RIGHT('foobarbar', 4) ");
+ assure("RIGHT('foobarbar', 4) failed!", row.getString(1).equals("rbar"));
+ }
+
+ private void chartest(final XRowSet xRowRes) throws com.sun.star.uno.Exception, com.sun.star.beans.UnknownPropertyException
+ {
+ final XRow row = execute(xRowRes, "CHAR(ascii('t'),ascii('e'),ascii('s'),ascii('t')) ");
+ assure("CHAR(ascii('t'),ascii('e'),ascii('s'),ascii('t')) failed!", row.getString(1).equals("test"));
+ }
+}
diff --git a/connectivity/qa/complex/connectivity/hsqldb/TestCacheSize.java b/connectivity/qa/complex/connectivity/hsqldb/TestCacheSize.java
new file mode 100644
index 0000000000..d2ee3c6802
--- /dev/null
+++ b/connectivity/qa/complex/connectivity/hsqldb/TestCacheSize.java
@@ -0,0 +1,591 @@
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * Copyright (c) 2001-2004, The HSQL Development Group
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of the HSQL Development Group nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL HSQL DEVELOPMENT GROUP, HSQLDB.ORG,
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+package complex.connectivity.hsqldb;
+
+
+
+import org.hsqldb.lib.StopWatch;
+
+import java.util.Random;
+import com.sun.star.uno.UnoRuntime;
+import com.sun.star.sdbc.*;
+
+/**
+ * Test large cached tables by setting up a cached table of 100000 records
+ * or more and a much smaller memory table with about 1/100th rows used.
+ * Populate both tables so that an indexed column of the cached table has a
+ * foreign key reference to the main table.
+ *
+ * This database can be used to demonstrate efficient queries to retrieve
+ * the data from the cached table.
+ *
+ * 1.7.1 insert timings for 100000 rows, cache scale 12:
+ * simple table, no extra index: 52 s
+ * with index on lastname only: 56 s
+ * with index on zip only: 211 s
+ * foreign key, referential_integrity true: 216 s
+ *
+ * The above have improved a lot in 1.7.2
+ *
+ * This test now incorporates the defunct TestTextTables
+ *
+ * @version 1.7.2
+ * @since 1.7.0
+ */
+public class TestCacheSize {
+
+ // program can edit the *.properties file to set cache_size
+ private boolean filedb = true;
+
+ // shutdown performed mid operation - not for mem: or hsql: URL's
+ private boolean shutdown = true;
+
+ // fixed
+ private String url = "sdbc:embedded:hsqldb";
+
+ // frequent reporting of progress
+ private boolean reportProgress = false;
+
+ // type of the big table {MEMORY | CACHED | TEXT}
+ private String tableType = "CACHED";
+ private int cacheScale = 17;
+
+ // script format {TEXT, BINARY, COMPRESSED}
+ private String logType = "TEXT";
+ private int writeDelay = 60;
+ private boolean indexZip = true;
+ private boolean indexLastName = false;
+ private boolean addForeignKey = false;
+ private boolean refIntegrity = true;
+
+ // speeds up inserts when tableType=="CACHED"
+ private boolean createTempTable = false;
+
+ // introduces fragmentation to the .data file during insert
+ private boolean deleteWhileInsert = false;
+ private int deleteWhileInsertInterval = 10000;
+
+ // size of the tables used in test
+ private int bigrows = 10000;
+ private int smallrows = 0xfff;
+
+ // if the extra table needs to be created and filled up
+ private boolean multikeytable = false;
+
+
+ private XStatement sStatement;
+ private XConnection cConnection;
+ private XDriver drv;
+ private com.sun.star.beans.PropertyValue[] info;
+
+ public TestCacheSize(com.sun.star.beans.PropertyValue[] _info,XDriver _drv){
+ drv = _drv;
+ info = _info;
+ }
+
+ public void setURL(String _url){
+ url = _url;
+ }
+
+ public void setUp() {
+
+ try {
+ sStatement = null;
+ cConnection = null;
+
+ if (filedb) {
+
+ cConnection = drv.connect(url,info);
+ sStatement = cConnection.createStatement();
+
+ sStatement.execute("SET SCRIPTFORMAT " + logType);
+ sStatement.execute("SET LOGSIZE " + 0);
+ sStatement.execute("SHUTDOWN");
+ cConnection.close();
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ System.out.println("TestSql.setUp() error: " + e.getMessage());
+ }
+ }
+
+ /**
+ * Fill up the cache
+ *
+ *
+ */
+ public void testFillUp() {
+
+ StopWatch sw = new StopWatch();
+ String ddl1 = "DROP TABLE test IF EXISTS;"
+ + "DROP TABLE zip IF EXISTS;";
+ String ddl2 = "CREATE CACHED TABLE zip( zip INT IDENTITY );";
+ String ddl3 = "CREATE " + tableType + " TABLE test( id INT IDENTITY,"
+ + " firstname VARCHAR, " + " lastname VARCHAR, "
+ + " zip INTEGER, " + " filler VARCHAR); ";
+ String ddl31 = "SET TABLE test SOURCE \"test.csv;cache_scale="
+ + cacheScale + "\";";
+
+ // adding extra index will slow down inserts a bit
+ String ddl4 = "CREATE INDEX idx1 ON TEST (lastname);";
+
+ // adding this index will slow down inserts a lot
+ String ddl5 = "CREATE INDEX idx2 ON TEST (zip);";
+
+ // referential integrity checks will slow down inserts a bit
+ String ddl6 =
+ "ALTER TABLE test add constraint c1 FOREIGN KEY (zip) REFERENCES zip(zip);";
+ String ddl7 = "CREATE TEMP TABLE temptest( id INT,"
+ + " firstname VARCHAR, " + " lastname VARCHAR, "
+ + " zip INTEGER, " + " filler VARCHAR); ";
+ String filler =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ + "ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ String mddl1 = "DROP TABLE test2 IF EXISTS;";
+ String mddl2 = "CREATE " + tableType
+ + " TABLE test2( id1 INT, id2 INT,"
+ + " firstname VARCHAR, " + " lastname VARCHAR, "
+ + " zip INTEGER, " + " filler VARCHAR, "
+ + " PRIMARY KEY (id1,id2) ); ";
+ String mdd13 = "SET TABLE test2 SOURCE \"test2.csv;cache_scale="
+ + cacheScale + "\";";
+
+ try {
+ System.out.println("Connecting");
+ sw.zero();
+
+ cConnection = null;
+ sStatement = null;
+ cConnection = drv.connect(url,info);
+
+ System.out.println("connected: " + sw.elapsedTime());
+ sw.zero();
+
+ sStatement = cConnection.createStatement();
+
+ java.util.Random randomgen = new java.util.Random();
+
+ sStatement.execute("SET WRITE_DELAY " + writeDelay);
+ sStatement.execute(ddl1);
+ sStatement.execute(ddl2);
+ sStatement.execute(ddl3);
+
+ if (tableType.equals("TEXT")) {
+ sStatement.execute(ddl31);
+ }
+
+ System.out.println("test table with no index");
+
+ if (indexLastName) {
+ sStatement.execute(ddl4);
+ System.out.println("create index on lastname");
+ }
+
+ if (indexZip) {
+ sStatement.execute(ddl5);
+ System.out.println("create index on zip");
+ }
+
+ if (addForeignKey) {
+ sStatement.execute(ddl6);
+ System.out.println("add foreign key");
+ }
+
+ if (createTempTable) {
+ sStatement.execute(ddl7);
+ System.out.println("temp table");
+ }
+
+ if (multikeytable) {
+ sStatement.execute(mddl1);
+ sStatement.execute(mddl2);
+
+ if (tableType.equals("TEXT")) {
+ sStatement.execute(mdd13);
+ }
+
+ System.out.println("multi key table");
+ }
+
+ System.out.println("Setup time: " + sw.elapsedTime());
+ fillUpBigTable(filler, randomgen);
+
+ if (multikeytable) {
+ fillUpMultiTable(filler, randomgen);
+ }
+
+ sw.zero();
+
+ if (shutdown) {
+ sStatement.execute("SHUTDOWN");
+ System.out.println("Shutdown Time: " + sw.elapsedTime());
+ }
+
+ cConnection.close();
+ } catch (SQLException e) {
+ System.out.println(e.getMessage());
+ }
+ }
+
+ private void fillUpBigTable(String filler,
+ Random randomgen) throws SQLException {
+
+ StopWatch sw = new StopWatch();
+ int i;
+
+ for (i = 0; i <= smallrows; i++) {
+ sStatement.execute("INSERT INTO zip VALUES(null);");
+ }
+
+ sStatement.execute("SET REFERENTIAL_INTEGRITY " + this.refIntegrity
+ + ";");
+
+ XPreparedStatement ps = cConnection.prepareStatement(
+ "INSERT INTO test (firstname,lastname,zip,filler) VALUES (?,?,?,?)");
+
+ XParameters para = UnoRuntime.queryInterface(XParameters.class,ps);
+ para.setString(1, "Julia");
+ para.setString(2, "Clancy");
+
+ for (i = 0; i < bigrows; i++) {
+ para.setInt(3, randomgen.nextInt(smallrows));
+
+ long nextrandom = randomgen.nextLong();
+ int randomlength = (int) nextrandom & 0x7f;
+
+ if (randomlength > filler.length()) {
+ randomlength = filler.length();
+ }
+
+ String varfiller = filler.substring(0, randomlength);
+
+ para.setString(4, nextrandom + varfiller);
+ ps.execute();
+
+ if (reportProgress && (i + 1) % 10000 == 0) {
+ System.out.println("Insert " + (i + 1) + " : "
+ + sw.elapsedTime());
+ }
+
+ // delete and add 4000 rows to introduce fragmentation
+ if (deleteWhileInsert && i != 0
+ && i % deleteWhileInsertInterval == 0) {
+ sStatement.execute("CALL IDENTITY();");
+
+ XMultipleResults mrs = UnoRuntime.queryInterface(XMultipleResults.class,sStatement);
+ XResultSet rs = mrs.getResultSet();
+
+ rs.next();
+
+ XRow row = UnoRuntime.queryInterface(XRow.class,rs);
+ int lastId = row.getInt(1);
+
+ sStatement.execute(
+ "SELECT * INTO TEMP tempt FROM test WHERE id > "
+ + (lastId - 4000) + " ;");
+ sStatement.execute("DELETE FROM test WHERE id > "
+ + (lastId - 4000) + " ;");
+ sStatement.execute("INSERT INTO test SELECT * FROM tempt;");
+ sStatement.execute("DROP TABLE tempt;");
+ }
+ }
+
+ System.out.println("Total insert: " + i);
+ System.out.println("Insert time: " + sw.elapsedTime() + " rps: "
+ + (1000L * i / (sw.elapsedTime() + 1)));
+ }
+
+ private void fillUpMultiTable(String filler,
+ Random randomgen) throws SQLException {
+
+ StopWatch sw = new StopWatch();
+ int i;
+ XPreparedStatement ps = cConnection.prepareStatement(
+ "INSERT INTO test2 (id1, id2, firstname,lastname,zip,filler) VALUES (?,?,?,?,?,?)");
+
+ XParameters para = UnoRuntime.queryInterface(XParameters.class,ps);
+ para.setString(3, "Julia");
+ para.setString(4, "Clancy");
+
+ int id1 = 0;
+
+ for (i = 0; i < bigrows; i++) {
+ int id2 = randomgen.nextInt(Integer.MAX_VALUE);
+
+ if (i % 1000 == 0) {
+ id1 = randomgen.nextInt(Integer.MAX_VALUE);
+ }
+
+ para.setInt(1, id1);
+ para.setInt(2, id2);
+ para.setInt(5, randomgen.nextInt(smallrows));
+
+ long nextrandom = randomgen.nextLong();
+ int randomlength = (int) nextrandom & 0x7f;
+
+ if (randomlength > filler.length()) {
+ randomlength = filler.length();
+ }
+
+ String varfiller = filler.substring(0, randomlength);
+
+ para.setString(6, nextrandom + varfiller);
+
+ try {
+ ps.execute();
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+
+ if (reportProgress && (i + 1) % 10000 == 0) {
+ System.out.println("Insert " + (i + 1) + " : "
+ + sw.elapsedTime());
+ }
+ }
+
+ System.out.println("Multi Key Total insert: " + i);
+ System.out.println("Insert time: " + sw.elapsedTime() + " rps: "
+ + (1000L * i / (sw.elapsedTime() + 1)));
+ }
+
+ public void tearDown() {}
+
+ public void checkResults() {
+
+ try {
+ StopWatch sw = new StopWatch();
+ XResultSet rs;
+
+ cConnection = drv.connect(url,info);
+
+ System.out.println("Reopened database: " + sw.elapsedTime());
+ sw.zero();
+
+ sStatement = cConnection.createStatement();
+
+ sStatement.execute("SET WRITE_DELAY " + writeDelay);
+
+ // the tests use different indexes
+ // use primary index
+ sStatement.execute("SELECT count(*) from TEST");
+
+ XMultipleResults mrs = UnoRuntime.queryInterface(XMultipleResults.class,sStatement);
+ rs = mrs.getResultSet();
+ XRow row = UnoRuntime.queryInterface(XRow.class,rs);
+
+ rs.next();
+ System.out.println("Row Count: " + row.getInt(1));
+ System.out.println("Time to count: " + sw.elapsedTime());
+
+ // use index on zip
+ sw.zero();
+ sStatement.execute("SELECT count(*) from TEST where zip > -1");
+
+ rs = mrs.getResultSet();
+
+ rs.next();
+ System.out.println("Row Count: " + row.getInt(1));
+ System.out.println("Time to count: " + sw.elapsedTime());
+ checkSelects();
+ checkUpdates();
+ checkSelects();
+ sw.zero();
+ sStatement.execute("SELECT count(*) from TEST where zip > -1");
+
+ rs = mrs.getResultSet();
+
+ rs.next();
+ System.out.println("Row Count: " + row.getInt(1));
+ System.out.println("Time to count: " + sw.elapsedTime());
+ sw.zero();
+
+ if (shutdown) {
+ sStatement.execute("SHUTDOWN");
+ System.out.println("Shutdown Time: " + sw.elapsedTime());
+ }
+
+ cConnection.close();
+ System.out.println("Closed database: " + sw.elapsedTime());
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ }
+
+ private void checkSelects() {
+
+ StopWatch sw = new StopWatch();
+ java.util.Random randomgen = new java.util.Random();
+ int i = 0;
+ boolean slow = false;
+
+ try {
+ XPreparedStatement ps = cConnection.prepareStatement(
+ "SELECT TOP 1 firstname,lastname,zip,filler FROM test WHERE zip = ?");
+ XParameters para = UnoRuntime.queryInterface(XParameters.class,ps);
+
+ for (; i < bigrows; i++) {
+ para.setInt(1, randomgen.nextInt(smallrows));
+ ps.execute();
+
+ if ((i + 1) == 100 && sw.elapsedTime() > 5000) {
+ slow = true;
+ }
+
+ if (reportProgress && (i + 1) % 10000 == 0
+ || (slow && (i + 1) % 100 == 0)) {
+ System.out.println("Select " + (i + 1) + " : "
+ + sw.elapsedTime() + " rps: "
+ + (1000 * i / (sw.elapsedTime() + 1)));
+ }
+ }
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+
+ System.out.println("Select random zip " + i + " rows : "
+ + sw.elapsedTime() + " rps: "
+ + (1000 * i / (sw.elapsedTime() + 1)));
+ sw.zero();
+
+ try {
+ XPreparedStatement ps = cConnection.prepareStatement(
+ "SELECT firstname,lastname,zip,filler FROM test WHERE id = ?");
+ XParameters para = UnoRuntime.queryInterface(XParameters.class,ps);
+
+ for (i = 0; i < bigrows; i++) {
+ para.setInt(1, randomgen.nextInt(bigrows - 1));
+ ps.execute();
+
+ if (reportProgress && (i + 1) % 10000 == 0
+ || (slow && (i + 1) % 100 == 0)) {
+ System.out.println("Select " + (i + 1) + " : "
+ + (sw.elapsedTime() + 1));
+ }
+ }
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+
+ System.out.println("Select random id " + i + " rows : "
+ + sw.elapsedTime() + " rps: "
+ + (1000 * i / (sw.elapsedTime() + 1)));
+ sw.zero();
+
+ try {
+ XPreparedStatement ps = cConnection.prepareStatement(
+ "SELECT zip FROM zip WHERE zip = ?");
+ XParameters para = UnoRuntime.queryInterface(XParameters.class,ps);
+
+ for (i = 0; i < bigrows; i++) {
+ para.setInt(1, randomgen.nextInt(smallrows - 1));
+ ps.execute();
+
+ if (reportProgress && (i + 1) % 10000 == 0
+ || (slow && (i + 1) % 100 == 0)) {
+ System.out.println("Select " + (i + 1) + " : "
+ + (sw.elapsedTime() + 1));
+ }
+ }
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+
+ System.out.println("Select random zip from zip table " + i
+ + " rows : " + sw.elapsedTime() + " rps: "
+ + (1000 * i / (sw.elapsedTime() + 1)));
+ }
+
+ private void checkUpdates() {
+
+ StopWatch sw = new StopWatch();
+ java.util.Random randomgen = new java.util.Random();
+ int i = 0;
+ boolean slow = false;
+ int count = 0;
+
+ try {
+ XPreparedStatement ps = cConnection.prepareStatement(
+ "UPDATE test SET filler = filler || zip WHERE zip = ?");
+ XParameters para = UnoRuntime.queryInterface(XParameters.class,ps);
+
+ for (; i < smallrows; i++) {
+ int random = randomgen.nextInt(smallrows - 1);
+
+ para.setInt(1, random);
+
+ count += ps.executeUpdate();
+
+ if (reportProgress && count % 10000 < 20) {
+ System.out.println("Update " + count + " : "
+ + (sw.elapsedTime() + 1));
+ }
+ }
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+
+ System.out.println("Update with random zip " + i
+ + " UPDATE commands, " + count + " rows : "
+ + sw.elapsedTime() + " rps: "
+ + (1000 * count / (sw.elapsedTime() + 1)));
+ sw.zero();
+
+ try {
+ XPreparedStatement ps = cConnection.prepareStatement(
+ "UPDATE test SET zip = zip + 1 WHERE id = ?");
+ XParameters para = UnoRuntime.queryInterface(XParameters.class,ps);
+
+ for (i = 0; i < bigrows; i++) {
+ int random = randomgen.nextInt(bigrows - 1);
+
+ para.setInt(1, random);
+ ps.execute();
+
+ if (reportProgress && (i + 1) % 10000 == 0
+ || (slow && (i + 1) % 100 == 0)) {
+ System.out.println("Update " + (i + 1) + " : "
+ + sw.elapsedTime() + " rps: "
+ + (1000 * i / (sw.elapsedTime() + 1)));
+ }
+ }
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+
+ System.out.println("Update with random id " + i + " rows : "
+ + sw.elapsedTime() + " rps: "
+ + (1000 * i / (sw.elapsedTime() + 1)));
+ }
+}
diff --git a/connectivity/qa/connectivity/ado/DriverTest.cxx b/connectivity/qa/connectivity/ado/DriverTest.cxx
new file mode 100644
index 0000000000..a737387fe0
--- /dev/null
+++ b/connectivity/qa/connectivity/ado/DriverTest.cxx
@@ -0,0 +1,141 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <test/bootstrapfixture.hxx>
+
+#include "ado/AConnection.hxx"
+#include "ado/ADatabaseMetaData.hxx"
+#include "ado/ADriver.hxx"
+#include "ado/AStatement.hxx"
+#include "ado/ACallableStatement.hxx"
+#include "ado/APreparedStatement.hxx"
+#include "ado/ACatalog.hxx"
+#include <com/sun/star/sdbc/ColumnValue.hpp>
+#include <com/sun/star/sdbc/TransactionIsolation.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <cppuhelper/typeprovider.hxx>
+#include <connectivity/dbexception.hxx>
+#include <osl/file.hxx>
+#include "strings.hrc"
+
+
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::uno;
+
+namespace connectivity::ado {
+
+
+class AdoDriverTest: public test::BootstrapFixture
+{
+public:
+ AdoDriverTest() : test::BootstrapFixture(false, false) {};
+
+ void test_metadata();
+ void test_select_default_all();
+
+ virtual void setUp();
+ virtual void tearDown();
+
+ CPPUNIT_TEST_SUITE(AdoDriverTest);
+
+ CPPUNIT_TEST(test_metadata);
+ CPPUNIT_TEST(test_select_default_all);
+ CPPUNIT_TEST_SUITE_END();
+
+private:
+ Reference<XInterface> m_xAdoComponent;
+ Reference<XConnection> m_xConnection;
+};
+
+void AdoDriverTest::setUp()
+{
+ test::BootstrapFixture::setUp();
+ m_xAdoComponent = getMultiServiceFactory()->createInstance("com.sun.star.comp.sdbc.ado.ODriver");
+ CPPUNIT_ASSERT_MESSAGE("no ado component!", m_xAdoComponent.is());
+
+ OUString url = "sdbc:ado:access:PROVIDER=Microsoft.Jet.OLEDB.4.0;DATA SOURCE=" +
+ m_directories.getPathFromWorkdir(u"/CppunitTest/TS001018407.mdb");
+
+ Sequence< PropertyValue > info;
+ Reference< XDriver> xDriver(m_xAdoComponent, UNO_QUERY);
+ if (!xDriver.is())
+ {
+ CPPUNIT_ASSERT_MESSAGE("cannot connect to ado driver!", xDriver.is());
+ }
+
+ m_xConnection = xDriver->connect(url, info);
+ if (!m_xConnection.is())
+ {
+ CPPUNIT_ASSERT_MESSAGE("cannot connect to students data source!", m_xConnection.is());
+ }
+}
+
+void AdoDriverTest::tearDown()
+{
+ m_xAdoComponent = 0;
+ test::BootstrapFixture::tearDown();
+}
+
+void AdoDriverTest::test_metadata()
+{
+ Reference< XDatabaseMetaData > xDatabaseMetaData = m_xConnection->getMetaData();
+ if (!xDatabaseMetaData.is())
+ {
+ CPPUNIT_ASSERT_MESSAGE("cannot retrieve meta data!", xDatabaseMetaData.is());
+ }
+
+ const Any catalog;
+ static constexpr OUStringLiteral schemaPattern = u"%";
+ static constexpr OUStringLiteral tableNamePattern = u"%";
+ const Sequence< OUString > types;
+
+ Reference< XResultSet > xResultSet =
+ xDatabaseMetaData->getTables(catalog, schemaPattern, tableNamePattern, types);
+ if (!xResultSet.is())
+ {
+ CPPUNIT_ASSERT_MESSAGE("cannot retrieve tables!", xResultSet.is());
+ }
+}
+
+void AdoDriverTest::test_select_default_all()
+{
+ static constexpr OUStringLiteral sql = u"select \"FirstName\" from \"Students\" ORDER BY \"FirstName\"";
+ Reference< XPreparedStatement > xStatement = m_xConnection->prepareStatement(sql);
+ if (!xStatement.is())
+ {
+ CPPUNIT_ASSERT_MESSAGE("cannot create prepared statement!", xStatement.is());
+ }
+
+ Reference< XResultSet > xResultSet = xStatement->executeQuery();
+ if (!xResultSet.is())
+ {
+ CPPUNIT_ASSERT_MESSAGE("cannot execute sql statement!", xResultSet.is());
+ }
+
+ Reference< XRow > xDelegatorRow(xResultSet, UNO_QUERY);
+ if (!xDelegatorRow.is())
+ {
+ CPPUNIT_ASSERT_MESSAGE("cannot extract row from result set!", xDelegatorRow.is());
+ }
+
+ sal_Bool result = xResultSet->first();
+ CPPUNIT_ASSERT_MESSAGE("fetch first row failed!", result);
+/*
+ OUString mail = xDelegatorRow->getString(1);
+ CPPUNIT_ASSERT_MESSAGE("first row is not john@doe.org!", mail.equalsAscii("john@doe.org"));
+*/
+}
+
+CPPUNIT_TEST_SUITE_REGISTRATION(AdoDriverTest);
+
+}
+
+CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/connectivity/qa/connectivity/ado/TS001018407.mdb b/connectivity/qa/connectivity/ado/TS001018407.mdb
new file mode 100644
index 0000000000..abe9f5ee33
--- /dev/null
+++ b/connectivity/qa/connectivity/ado/TS001018407.mdb
Binary files differ
diff --git a/connectivity/qa/connectivity/commontools/FValue_test.cxx b/connectivity/qa/connectivity/commontools/FValue_test.cxx
new file mode 100644
index 0000000000..b6f0e36588
--- /dev/null
+++ b/connectivity/qa/connectivity/commontools/FValue_test.cxx
@@ -0,0 +1,366 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <test/bootstrapfixture.hxx>
+
+#include <connectivity/FValue.hxx>
+#include <com/sun/star/sdbc/DataType.hpp>
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::uno;
+
+namespace connectivity::commontools {
+
+class FValueTest: public test::BootstrapFixture
+{
+public:
+ FValueTest() : test::BootstrapFixture(false, false) {};
+
+ void test_Bool();
+
+ void test_Int8();
+
+ void test_Int16();
+ void test_uInt16();
+
+ void test_Int32();
+ void test_uInt32();
+
+ void test_Int64();
+ void test_uInt64();
+
+ void test_float();
+ void test_double();
+
+ void test_bool_getString();
+ void test_bit_getString();
+
+ void test_bool_creation();
+
+ CPPUNIT_TEST_SUITE(FValueTest);
+
+ CPPUNIT_TEST(test_Bool);
+
+ CPPUNIT_TEST(test_Int8);
+
+ CPPUNIT_TEST(test_Int16);
+ CPPUNIT_TEST(test_uInt16);
+
+ CPPUNIT_TEST(test_Int32);
+ CPPUNIT_TEST(test_uInt32);
+
+ CPPUNIT_TEST(test_Int64);
+ CPPUNIT_TEST(test_uInt64);
+
+ CPPUNIT_TEST(test_float);
+ CPPUNIT_TEST(test_double);
+
+ CPPUNIT_TEST(test_bool_getString);
+ CPPUNIT_TEST(test_bit_getString);
+ CPPUNIT_TEST(test_bool_creation);
+ CPPUNIT_TEST_SUITE_END();
+};
+
+void FValueTest::test_Bool()
+{
+ bool src_Bool = true;
+ ORowSetValue v(src_Bool);
+ bool trg_Bool = v.getBool();
+
+ std::cerr << "src_Bool: " << src_Bool << std::endl;
+ std::cerr << "trg_Bool: " << trg_Bool << std::endl;
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("bool conversion to ORowSetValue didn't work", trg_Bool, src_Bool);
+
+ Any any_Bool = v.makeAny();
+ ORowSetValue t;
+ t.fill(any_Bool);
+ trg_Bool = t.getBool();
+
+ std::cerr << "trg_Bool: " << trg_Bool << std::endl;
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("bool conversion from Any didn't work", trg_Bool, src_Bool);
+}
+
+void FValueTest::test_Int8()
+{
+ sal_Int8 src_salInt8 = 127;
+ ORowSetValue v(src_salInt8);
+ sal_Int8 trg_salInt8 = v.getInt8();
+
+ std::cerr << "src_salInt8: " << static_cast<short>(src_salInt8) << std::endl;
+ std::cerr << "trg_salInt8: " << static_cast<short>(trg_salInt8) << std::endl;
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("sal_Int8 conversion to ORowSetValue didn't work", trg_salInt8, src_salInt8);
+
+ Any any_Int8 = v.makeAny();
+ ORowSetValue t;
+ t.fill(any_Int8);
+ trg_salInt8 = t.getInt8();
+
+ std::cerr << "trg_salInt8: " << static_cast<short>(trg_salInt8) << std::endl;
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("sal_Int8 conversion from Any didn't work", trg_salInt8, src_salInt8);
+}
+
+void FValueTest::test_Int16()
+{
+ sal_Int16 src_salInt16 = -10001;
+ ORowSetValue v(src_salInt16);
+ sal_Int16 trg_salInt16 = v.getInt16();
+
+ std::cerr << "src_salInt16: " << src_salInt16 << std::endl;
+ std::cerr << "trg_salInt16: " << trg_salInt16 << std::endl;
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("sal_Int16 conversion to ORowSetValue didn't work", trg_salInt16, src_salInt16);
+
+ Any any_Int16 = v.makeAny();
+ ORowSetValue t;
+ t.fill(any_Int16);
+ trg_salInt16 = t.getInt16();
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("sal_Int16 conversion from Any didn't work", trg_salInt16, src_salInt16);
+}
+
+void FValueTest::test_uInt16()
+{
+ sal_uInt16 src_saluInt16 = 10001;
+ ORowSetValue v(src_saluInt16);
+ sal_uInt16 trg_saluInt16 = v.getUInt16();
+
+ std::cerr << "src_saluInt16: " << src_saluInt16 << std::endl;
+ std::cerr << "trg_saluInt16: " << trg_saluInt16 << std::endl;
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("sal_uInt16 conversion to ORowSetValue didn't work", trg_saluInt16, src_saluInt16);
+
+ Any any_uInt16 = v.makeAny();
+ ORowSetValue t;
+ t.fill(any_uInt16);
+ trg_saluInt16 = t.getUInt16();
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("sal_uInt16 conversion from Any didn't work", trg_saluInt16, src_saluInt16);
+}
+
+void FValueTest::test_Int32()
+{
+ sal_Int32 src_salInt32 = -10000001;
+ ORowSetValue v(src_salInt32);
+ sal_Int32 trg_salInt32 = v.getInt32();
+
+ std::cerr << "src_salInt32: " << src_salInt32 << std::endl;
+ std::cerr << "trg_salInt32: " << trg_salInt32 << std::endl;
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("sal_Int32 conversion to ORowSetValue didn't work", trg_salInt32, src_salInt32);
+
+ Any any_Int32 = v.makeAny();
+ ORowSetValue t;
+ t.fill(any_Int32);
+ trg_salInt32 = t.getInt32();
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("sal_Int32 conversion from Any didn't work", trg_salInt32, src_salInt32);
+}
+
+void FValueTest::test_uInt32()
+{
+ sal_uInt32 src_saluInt32 = 100000001;
+ ORowSetValue v(src_saluInt32);
+ sal_uInt32 trg_saluInt32 = v.getUInt32();
+
+ std::cerr << "src_saluInt32: " << src_saluInt32 << std::endl;
+ std::cerr << "trg_saluInt32: " << trg_saluInt32 << std::endl;
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("sal_uInt32 conversion to ORowSetValue didn't work", trg_saluInt32, src_saluInt32);
+
+ Any any_uInt32 = v.makeAny();
+ ORowSetValue t;
+ t.fill(any_uInt32);
+ trg_saluInt32 = t.getUInt32();
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("sal_uInt32 conversion from Any didn't work", trg_saluInt32, src_saluInt32);
+}
+
+void FValueTest::test_Int64()
+{
+ sal_Int64 src_salInt64 = -1000000000000000001LL;
+ ORowSetValue v(src_salInt64);
+ sal_Int64 trg_salInt64 = v.getLong();
+
+ std::cerr << "src_salInt64: " << src_salInt64 << std::endl;
+ std::cerr << "trg_salInt64: " << trg_salInt64 << std::endl;
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("sal_Int64 conversion to ORowSetValue didn't work", trg_salInt64, src_salInt64);
+
+ Any any_Int64 = v.makeAny();
+ ORowSetValue t;
+ t.fill(any_Int64);
+ trg_salInt64 = t.getLong();
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("sal_Int64 conversion from Any didn't work", trg_salInt64, src_salInt64);
+}
+
+void FValueTest::test_uInt64()
+{
+ sal_uInt64 src_saluInt64 = 10000000000000000001ULL;
+ ORowSetValue v(src_saluInt64);
+ sal_uInt64 trg_saluInt64 = v.getULong();
+
+ std::cerr << "src_saluInt64: " << src_saluInt64 << std::endl;
+ std::cerr << "trg_saluInt64: " << trg_saluInt64 << std::endl;
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("sal_uInt64 conversion to ORowSetValue didn't work", trg_saluInt64, src_saluInt64);
+
+ Any any_uInt64 = v.makeAny();
+ ORowSetValue t;
+ t.fill(any_uInt64);
+ trg_saluInt64 = t.getULong();
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("sal_uInt64 conversion from Any didn't work", trg_saluInt64, src_saluInt64);
+}
+
+void FValueTest::test_float()
+{
+ float src_float = 1.234f;
+ ORowSetValue v(src_float);
+ float trg_float = v.getFloat();
+
+ std::cerr << "src_float: " << src_float << std::endl;
+ std::cerr << "trg_float: " << trg_float << std::endl;
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("float conversion to ORowSetValue didn't work", trg_float, src_float);
+
+ Any any_float = v.makeAny();
+ ORowSetValue t;
+ t.fill(any_float);
+ trg_float = t.getFloat();
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("float conversion from Any didn't work", trg_float, src_float);
+}
+
+void FValueTest::test_double()
+{
+ double src_double = 1.23456789;
+ ORowSetValue v(src_double);
+ double trg_double = v.getDouble();
+
+ std::cerr << "src_double: " << src_double << std::endl;
+ std::cerr << "trg_double: " << trg_double << std::endl;
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("double conversion to ORowSetValue didn't work", trg_double, src_double);
+
+ Any any_double = v.makeAny();
+ ORowSetValue t;
+ t.fill(any_double);
+ trg_double = t.getDouble();
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("double conversion from Any didn't work", trg_double, src_double);
+}
+
+void FValueTest::test_bool_getString()
+{
+ bool src_bool_1 = true;
+ ORowSetValue v_1(src_bool_1);
+ OUString trg_bool_1 = v_1.getString();
+
+ std::cerr << "src_bool_1: " << src_bool_1 << std::endl;
+ std::cerr << "trg_bool_1: " << trg_bool_1 << std::endl;
+
+ CPPUNIT_ASSERT_MESSAGE("ORowSetValue bool to string conversion didn't work", bool(trg_bool_1 == "true"));
+
+ bool src_bool_0 = false;
+ ORowSetValue v_0(src_bool_0);
+ OUString trg_bool_0 = v_0.getString();
+
+ std::cerr << "src_bool_0: " << src_bool_0 << std::endl;
+ std::cerr << "trg_bool_0: " << trg_bool_0 << std::endl;
+
+ CPPUNIT_ASSERT_MESSAGE("ORowSetValue bool to string conversion didn't work", bool(trg_bool_0 == "false"));
+}
+
+void FValueTest::test_bit_getString()
+{
+ bool src_bool_1 = true;
+ ORowSetValue v_1(src_bool_1);
+ v_1.setTypeKind(DataType::BIT);
+ OUString trg_bool_1 = v_1.getString();
+
+ std::cerr << "src_bit_1: " << src_bool_1 << std::endl;
+ std::cerr << "trg_bit_1: " << trg_bool_1 << std::endl;
+
+ CPPUNIT_ASSERT_MESSAGE("ORowSetValue bit to string conversion didn't work", bool(trg_bool_1 == "1"));
+
+ bool src_bool_0 = false;
+ ORowSetValue v_0(src_bool_0);
+ v_0.setTypeKind(DataType::BIT);
+ OUString trg_bool_0 = v_0.getString();
+
+ std::cerr << "src_bit_0: " << src_bool_0 << std::endl;
+ std::cerr << "trg_bit_0: " << trg_bool_0 << std::endl;
+
+ CPPUNIT_ASSERT_MESSAGE("ORowSetValue bit to string conversion didn't work", bool(trg_bool_0 == "0"));
+}
+
+void FValueTest::test_bool_creation()
+{
+ ORowSetValue vTrue(true);
+ ORowSetValue vFalse(false);
+
+ {
+ ORowSetValue v(OUString("1"));
+ v.setTypeKind(DataType::BOOLEAN);
+ CPPUNIT_ASSERT_MESSAGE("ORowSetValue bool creation from string didn't work", bool(v == vTrue));
+ }
+
+ {
+ ORowSetValue v(OUString("0"));
+ v.setTypeKind(DataType::BOOLEAN);
+ CPPUNIT_ASSERT_MESSAGE("ORowSetValue bool creation from string didn't work", bool(v == vFalse));
+ }
+
+ {
+ ORowSetValue v(OUString("true"));
+ v.setTypeKind(DataType::BOOLEAN);
+ CPPUNIT_ASSERT_MESSAGE("ORowSetValue bool creation from string didn't work", bool(v == vTrue));
+ }
+
+ {
+ ORowSetValue v(OUString("tRuE"));
+ v.setTypeKind(DataType::BOOLEAN);
+ CPPUNIT_ASSERT_MESSAGE("ORowSetValue bool creation from string didn't work", bool(v == vTrue));
+ }
+
+ {
+ ORowSetValue v(OUString("false"));
+ v.setTypeKind(DataType::BOOLEAN);
+ CPPUNIT_ASSERT_MESSAGE("ORowSetValue bool creation from string didn't work", bool(v == vFalse));
+ }
+
+ {
+ ORowSetValue v(OUString("0"));
+ v.setTypeKind(DataType::BOOLEAN);
+ CPPUNIT_ASSERT_MESSAGE("ORowSetValue bool creation from string didn't work", bool(v == vFalse));
+ }
+
+}
+
+CPPUNIT_TEST_SUITE_REGISTRATION(FValueTest);
+
+}
+
+CPPUNIT_PLUGIN_IMPLEMENT();
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/qa/connectivity/mysql/mysql.cxx b/connectivity/qa/connectivity/mysql/mysql.cxx
new file mode 100644
index 0000000000..4b1a9a4e4f
--- /dev/null
+++ b/connectivity/qa/connectivity/mysql/mysql.cxx
@@ -0,0 +1,502 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <test/bootstrapfixture.hxx>
+
+#include <com/sun/star/sdb/XOfficeDatabaseDocument.hpp>
+#include <com/sun/star/sdbc/XColumnLocate.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <com/sun/star/sdbc/XResultSet.hpp>
+#include <com/sun/star/sdbc/XResultSetMetaData.hpp>
+#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <com/sun/star/sdbc/XParameters.hpp>
+#include <com/sun/star/sdbc/XStatement.hpp>
+#include <com/sun/star/sdbc/XDriver.hpp>
+
+#include <com/sun/star/util/DateTime.hpp>
+#include <comphelper/propertysequence.hxx>
+#include <svtools/miscopt.hxx>
+#include <osl/process.h>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+
+class MysqlTestDriver : public test::BootstrapFixture
+{
+private:
+ OUString m_sUrl;
+ Reference<XInterface> m_xMysqlcComponent;
+ Reference<XDriver> m_xDriver;
+ Sequence<PropertyValue> m_infos;
+
+public:
+ MysqlTestDriver()
+ : test::BootstrapFixture(false, false)
+ {
+ }
+ virtual void setUp() override;
+ virtual void tearDown() override;
+ void testDBConnection();
+ void testCreateAndDropTable();
+ void testIntegerInsertAndQuery();
+ void testDBPositionChange();
+ void testMultipleResultsets();
+ void testDBMetaData();
+ void testTimestampField();
+ void testNumericConversionPrepared();
+ void testPreparedStmtIsAfterLast();
+ void testGetStringFromBloColumnb();
+
+ CPPUNIT_TEST_SUITE(MysqlTestDriver);
+ CPPUNIT_TEST(testDBConnection);
+ CPPUNIT_TEST(testCreateAndDropTable);
+ CPPUNIT_TEST(testIntegerInsertAndQuery);
+ CPPUNIT_TEST(testMultipleResultsets);
+ CPPUNIT_TEST(testDBMetaData);
+ CPPUNIT_TEST(testTimestampField);
+ CPPUNIT_TEST(testNumericConversionPrepared);
+ CPPUNIT_TEST(testPreparedStmtIsAfterLast);
+ CPPUNIT_TEST(testGetStringFromBloColumnb);
+ CPPUNIT_TEST_SUITE_END();
+};
+
+void MysqlTestDriver::tearDown()
+{
+ Reference<XConnection> xConnection = m_xDriver->connect(m_sUrl, m_infos);
+ if (!xConnection.is())
+ {
+ CPPUNIT_ASSERT_MESSAGE("cannot connect to data source!", xConnection.is());
+ }
+ uno::Reference<XStatement> xStatement = xConnection->createStatement();
+ CPPUNIT_ASSERT(xStatement.is());
+ xStatement->executeUpdate("DROP TABLE IF EXISTS myTestTable");
+ xStatement->executeUpdate("DROP TABLE IF EXISTS otherTable");
+ test::BootstrapFixture::tearDown();
+}
+
+void MysqlTestDriver::setUp()
+{
+ test::BootstrapFixture::setUp();
+
+ /* Get URL from environment variable. This test suite should run only when
+ * there is a URL given. This is because it can be used for testing connection to
+ * external databases as well.
+ *
+ * Example URL:
+ * username/password@sdbc:mysql:mysqlc:localhost:3306/testdatabase
+ */
+ osl_getEnvironment(OUString("CONNECTIVITY_TEST_MYSQL_DRIVER").pData, &m_sUrl.pData);
+ m_xMysqlcComponent
+ = getMultiServiceFactory()->createInstance("com.sun.star.comp.sdbc.mysqlc.MysqlCDriver");
+ CPPUNIT_ASSERT_MESSAGE("no mysqlc component!", m_xMysqlcComponent.is());
+
+ // set user name and password
+ sal_Int32 nPer = m_sUrl.indexOf("/");
+ OUString sUsername = m_sUrl.copy(0, nPer);
+ m_sUrl = m_sUrl.copy(nPer + 1);
+ sal_Int32 nAt = m_sUrl.indexOf("@");
+ OUString sPassword = m_sUrl.copy(0, nAt);
+ m_sUrl = m_sUrl.copy(nAt + 1);
+
+ m_infos = comphelper::InitPropertySequence(
+ { { "user", makeAny(sUsername) }, { "password", makeAny(sPassword) } });
+
+ m_xDriver.set(m_xMysqlcComponent, UNO_QUERY);
+ if (!m_xDriver.is())
+ {
+ CPPUNIT_ASSERT_MESSAGE("cannot connect to mysqlc driver!", m_xDriver.is());
+ }
+}
+
+/**
+ * Test database connection. It is assumed that the given URL is correct and
+ * there is a server running at the location.
+ */
+void MysqlTestDriver::testDBConnection()
+{
+ Reference<XConnection> xConnection = m_xDriver->connect(m_sUrl, m_infos);
+ if (!xConnection.is())
+ {
+ CPPUNIT_ASSERT_MESSAGE("cannot connect to data source!", xConnection.is());
+ }
+
+ uno::Reference<XStatement> xStatement = xConnection->createStatement();
+ CPPUNIT_ASSERT(xStatement.is());
+
+ Reference<XResultSet> xResultSet = xStatement->executeQuery("SELECT 1");
+ CPPUNIT_ASSERT(xResultSet.is());
+ Reference<XRow> xRow(xResultSet, UNO_QUERY);
+ CPPUNIT_ASSERT_MESSAGE("cannot extract row from result set!", xRow.is());
+
+ sal_Bool result = xResultSet->first();
+ CPPUNIT_ASSERT_MESSAGE("fetch first row failed!", result);
+}
+
+/**
+ * Test creation and removal of a table
+ */
+void MysqlTestDriver::testCreateAndDropTable()
+{
+ Reference<XConnection> xConnection = m_xDriver->connect(m_sUrl, m_infos);
+ if (!xConnection.is())
+ {
+ CPPUNIT_ASSERT_MESSAGE("cannot connect to data source!", xConnection.is());
+ }
+
+ uno::Reference<XStatement> xStatement = xConnection->createStatement();
+ CPPUNIT_ASSERT(xStatement.is());
+ xStatement->executeUpdate("DROP TABLE IF EXISTS myTestTable");
+
+ auto nUpdateCount
+ = xStatement->executeUpdate("CREATE TABLE myTestTable (id INTEGER PRIMARY KEY)");
+ CPPUNIT_ASSERT_EQUAL(0, nUpdateCount); // it's a DDL statement
+
+ // we can use the same xStatement instance here
+ nUpdateCount = xStatement->executeUpdate("DROP TABLE myTestTable");
+ CPPUNIT_ASSERT_EQUAL(0, nUpdateCount); // it's a DDL statement
+}
+
+void MysqlTestDriver::testIntegerInsertAndQuery()
+{
+ Reference<XConnection> xConnection = m_xDriver->connect(m_sUrl, m_infos);
+ if (!xConnection.is())
+ {
+ CPPUNIT_ASSERT_MESSAGE("cannot connect to data source!", xConnection.is());
+ }
+
+ Reference<XStatement> xStatement = xConnection->createStatement();
+ CPPUNIT_ASSERT(xStatement.is());
+ xStatement->executeUpdate("DROP TABLE IF EXISTS myTestTable");
+
+ auto nUpdateCount
+ = xStatement->executeUpdate("CREATE TABLE myTestTable (id INTEGER PRIMARY KEY)");
+ CPPUNIT_ASSERT_EQUAL(0, nUpdateCount); // it's a DDL statement
+
+ Reference<XPreparedStatement> xPrepared
+ = xConnection->prepareStatement(OUString{ "INSERT INTO myTestTable VALUES (?)" });
+ Reference<XParameters> xParams(xPrepared, UNO_QUERY);
+ constexpr int ROW_COUNT = 3;
+ for (int i = 0; i < ROW_COUNT; ++i)
+ {
+ xParams->setLong(1, i); // first and only column
+ nUpdateCount = xPrepared->executeUpdate();
+ CPPUNIT_ASSERT_EQUAL(1, nUpdateCount); // one row is inserted at a time
+ }
+
+ // now let's query the existing data
+ Reference<XResultSet> xResultSet = xStatement->executeQuery("SELECT id from myTestTable");
+ CPPUNIT_ASSERT_MESSAGE("result set cannot be instantiated after query", xResultSet.is());
+ Reference<XRow> xRow(xResultSet, UNO_QUERY);
+ Reference<XColumnLocate> xColumnLocate(xResultSet, UNO_QUERY);
+ CPPUNIT_ASSERT_MESSAGE("cannot extract row from result set!", xRow.is());
+
+ for (tools::Long i = 0; i < ROW_COUNT; ++i)
+ {
+ bool hasRow = xResultSet->next();
+ CPPUNIT_ASSERT_MESSAGE("not enough result after query", hasRow);
+ CPPUNIT_ASSERT_EQUAL(i, xRow->getLong(1)); // first and only column
+ CPPUNIT_ASSERT_EQUAL(i, xRow->getLong(xColumnLocate->findColumn("id"))); // test findColumn
+ }
+ CPPUNIT_ASSERT_MESSAGE("Cursor is not on last position.",
+ xResultSet->isLast()); // cursor is on last position
+ CPPUNIT_ASSERT_EQUAL(ROW_COUNT, xResultSet->getRow()); // which is the last position
+
+ bool hasRow = xResultSet->next(); // go to afterlast
+ // no more rows, next should return false
+ CPPUNIT_ASSERT_MESSAGE("next returns true after last row", !hasRow);
+ // cursor should be in afterlast position
+ CPPUNIT_ASSERT_EQUAL(ROW_COUNT + 1, xResultSet->getRow());
+ CPPUNIT_ASSERT_MESSAGE("Cursor is not on after-last position.", xResultSet->isAfterLast());
+
+ nUpdateCount = xStatement->executeUpdate("DROP TABLE myTestTable");
+ CPPUNIT_ASSERT_EQUAL(0, nUpdateCount); // it's a DDL statement
+}
+
+void MysqlTestDriver::testDBPositionChange()
+{
+ Reference<XConnection> xConnection = m_xDriver->connect(m_sUrl, m_infos);
+ if (!xConnection.is())
+ {
+ CPPUNIT_ASSERT_MESSAGE("cannot connect to data source!", xConnection.is());
+ }
+
+ Reference<XStatement> xStatement = xConnection->createStatement();
+ CPPUNIT_ASSERT(xStatement.is());
+ xStatement->executeUpdate("DROP TABLE IF EXISTS myTestTable");
+
+ auto nUpdateCount
+ = xStatement->executeUpdate("CREATE TABLE myTestTable (id INTEGER PRIMARY KEY)");
+ CPPUNIT_ASSERT_EQUAL(0, nUpdateCount); // it's a DDL statement
+ Reference<XPreparedStatement> xPrepared
+ = xConnection->prepareStatement(OUString{ "INSERT INTO myTestTable VALUES (?)" });
+ Reference<XParameters> xParams(xPrepared, UNO_QUERY);
+ constexpr int ROW_COUNT = 3;
+ for (int i = 1; i <= ROW_COUNT; ++i)
+ {
+ xParams->setLong(1, i); // first and only column
+ nUpdateCount = xPrepared->executeUpdate();
+ CPPUNIT_ASSERT_EQUAL(1, nUpdateCount); // one row is inserted at a time
+ }
+ Reference<XResultSet> xResultSet = xStatement->executeQuery("SELECT id from myTestTable");
+ CPPUNIT_ASSERT_MESSAGE("result set cannot be instantiated after query", xResultSet.is());
+ Reference<XRow> xRow(xResultSet, UNO_QUERY);
+ CPPUNIT_ASSERT_MESSAGE("cannot extract row from result set!", xRow.is());
+
+ xResultSet->afterLast();
+ CPPUNIT_ASSERT_EQUAL(ROW_COUNT + 1, xResultSet->getRow());
+ xResultSet->last();
+ CPPUNIT_ASSERT_EQUAL(ROW_COUNT, nUpdateCount);
+ CPPUNIT_ASSERT_EQUAL(ROW_COUNT, xResultSet->getRow());
+ bool successPrevious = xResultSet->previous();
+ CPPUNIT_ASSERT(successPrevious);
+ CPPUNIT_ASSERT_EQUAL(ROW_COUNT - 1, nUpdateCount);
+ xResultSet->beforeFirst();
+ xResultSet->next();
+ CPPUNIT_ASSERT_EQUAL(1, xResultSet->getRow());
+ xResultSet->first();
+ CPPUNIT_ASSERT_EQUAL(1, xResultSet->getRow());
+
+ // Now previous should put the cursor to before-first position, but it
+ // should return with false.
+ successPrevious = xResultSet->previous();
+ CPPUNIT_ASSERT(!successPrevious);
+ CPPUNIT_ASSERT_EQUAL(0, xResultSet->getRow());
+
+ nUpdateCount = xStatement->executeUpdate("DROP TABLE myTestTable");
+ CPPUNIT_ASSERT_EQUAL(0, nUpdateCount); // it's a DDL statement
+}
+
+void MysqlTestDriver::testMultipleResultsets()
+{
+ Reference<XConnection> xConnection = m_xDriver->connect(m_sUrl, m_infos);
+ CPPUNIT_ASSERT(xConnection.is());
+ Reference<XStatement> xStatement = xConnection->createStatement();
+ CPPUNIT_ASSERT(xStatement.is());
+ // create two tables
+ xStatement->executeUpdate("DROP TABLE IF EXISTS myTestTable");
+ xStatement->executeUpdate("DROP TABLE IF EXISTS otherTable");
+ xStatement->executeUpdate("CREATE TABLE myTestTable (id INTEGER PRIMARY KEY)");
+ xStatement->executeUpdate("INSERT INTO myTestTable VALUES (1)");
+ xStatement->executeUpdate("CREATE TABLE otherTable (id INTEGER PRIMARY KEY)");
+ xStatement->executeUpdate("INSERT INTO otherTable VALUES (2)");
+
+ // create first result set
+ Reference<XResultSet> xResultSet = xStatement->executeQuery("SELECT id from myTestTable");
+ CPPUNIT_ASSERT_MESSAGE("result set cannot be instantiated after query", xResultSet.is());
+ // use it
+ xResultSet->next();
+ Reference<XRow> xRowFirst(xResultSet, UNO_QUERY);
+ CPPUNIT_ASSERT_EQUAL(1l, xRowFirst->getLong(1));
+ // create second result set
+ Reference<XResultSet> xResultSet2 = xStatement->executeQuery("SELECT id from otherTable");
+ // use second result set
+ xResultSet2->next();
+ Reference<XRow> xRowSecond(xResultSet2, UNO_QUERY);
+ CPPUNIT_ASSERT_EQUAL(2l, xRowSecond->getLong(1));
+ // now use the first result set again
+#if 0
+ // FIXME this was broken by 86c86719782243275b65f1f7f2cfdcc0e56c8cd4 adding closeResultSet() in execute()
+ CPPUNIT_ASSERT_EQUAL(1l, xRowFirst->getLong(1));
+#endif
+
+ xStatement->executeUpdate("DROP TABLE myTestTable");
+ xStatement->executeUpdate("DROP TABLE otherTable");
+}
+
+void MysqlTestDriver::testDBMetaData()
+{
+ Reference<XConnection> xConnection = m_xDriver->connect(m_sUrl, m_infos);
+ if (!xConnection.is())
+ CPPUNIT_ASSERT_MESSAGE("cannot connect to data source!", xConnection.is());
+ uno::Reference<XStatement> xStatement = xConnection->createStatement();
+ CPPUNIT_ASSERT(xStatement.is());
+ xStatement->executeUpdate("DROP TABLE IF EXISTS myTestTable");
+
+ xStatement->executeUpdate(
+ "CREATE TABLE myTestTable (id INTEGER PRIMARY KEY, name VARCHAR(20))");
+ Reference<XPreparedStatement> xPrepared
+ = xConnection->prepareStatement(OUString{ "INSERT INTO myTestTable VALUES (?, ?)" });
+ Reference<XParameters> xParams(xPrepared, UNO_QUERY);
+ constexpr int ROW_COUNT = 3;
+ for (int i = 0; i < ROW_COUNT; ++i)
+ {
+ xParams->setLong(1, i);
+ xParams->setString(2, "lorem");
+ xPrepared->executeUpdate();
+ }
+
+ Reference<XResultSet> xResultSet = xStatement->executeQuery("SELECT * from myTestTable");
+ Reference<XResultSetMetaDataSupplier> xMetaDataSupplier(xResultSet, UNO_QUERY);
+ Reference<XResultSetMetaData> xMetaData = xMetaDataSupplier->getMetaData();
+ CPPUNIT_ASSERT_EQUAL(OUString{ "id" }, xMetaData->getColumnName(1));
+ CPPUNIT_ASSERT_EQUAL(OUString{ "name" }, xMetaData->getColumnName(2));
+ CPPUNIT_ASSERT(!xMetaData->isAutoIncrement(1));
+ CPPUNIT_ASSERT(!xMetaData->isCaseSensitive(2)); // default collation should be case insensitive
+ xResultSet->next(); // use it
+ // test that meta data is usable even after fetching result set
+ CPPUNIT_ASSERT_EQUAL(OUString{ "name" }, xMetaData->getColumnName(2));
+ CPPUNIT_ASSERT_THROW_MESSAGE("exception expected when indexing out of range",
+ xMetaData->getColumnName(3), sdbc::SQLException);
+ xStatement->executeUpdate("DROP TABLE myTestTable");
+}
+
+void MysqlTestDriver::testTimestampField()
+{
+ Reference<XConnection> xConnection = m_xDriver->connect(m_sUrl, m_infos);
+ if (!xConnection.is())
+ CPPUNIT_ASSERT_MESSAGE("cannot connect to data source!", xConnection.is());
+ uno::Reference<XStatement> xStatement = xConnection->createStatement();
+ CPPUNIT_ASSERT(xStatement.is());
+ xStatement->executeUpdate("DROP TABLE IF EXISTS myTestTable");
+
+ xStatement->executeUpdate(
+ "CREATE TABLE myTestTable (id INTEGER PRIMARY KEY, mytimestamp timestamp)");
+ xStatement->executeUpdate("INSERT INTO myTestTable VALUES (1, '2008-02-16 20:15:03')");
+
+ // now let's query
+ Reference<XResultSet> xResultSet
+ = xStatement->executeQuery("SELECT mytimestamp from myTestTable");
+
+ xResultSet->next(); // use it
+ Reference<XRow> xRow(xResultSet, UNO_QUERY);
+ CPPUNIT_ASSERT_MESSAGE("cannot extract row from result set!", xRow.is());
+ util::DateTime dt = xRow->getTimestamp(1);
+ CPPUNIT_ASSERT_EQUAL(static_cast<short>(2008), dt.Year);
+ CPPUNIT_ASSERT_EQUAL(static_cast<unsigned short>(2), dt.Month);
+ CPPUNIT_ASSERT_EQUAL(static_cast<unsigned short>(16), dt.Day);
+
+ CPPUNIT_ASSERT_EQUAL(static_cast<unsigned short>(20), dt.Hours);
+ CPPUNIT_ASSERT_EQUAL(static_cast<unsigned short>(15), dt.Minutes);
+ CPPUNIT_ASSERT_EQUAL(static_cast<unsigned short>(3), dt.Seconds);
+
+ xStatement->executeUpdate("DROP TABLE myTestTable");
+}
+
+/**
+ * Test getting value from a decimal type column from a result set of a
+ * prepared statement, getting as a tinyint, string, short, int, long.
+ */
+void MysqlTestDriver::testNumericConversionPrepared()
+{
+ Reference<XConnection> xConnection = m_xDriver->connect(m_sUrl, m_infos);
+ if (!xConnection.is())
+ CPPUNIT_ASSERT_MESSAGE("cannot connect to data source!", xConnection.is());
+ uno::Reference<XStatement> xStatement = xConnection->createStatement();
+ CPPUNIT_ASSERT(xStatement.is());
+ xStatement->executeUpdate("DROP TABLE IF EXISTS myTestTable");
+
+ xStatement->executeUpdate("CREATE TABLE myTestTable (myDecimal DECIMAL(4,2))");
+ xStatement->executeUpdate("INSERT INTO myTestTable VALUES (11.22)");
+ Reference<XPreparedStatement> xPrepared
+ = xConnection->prepareStatement("SELECT * from myTestTable");
+ Reference<XResultSet> xResultSet = xPrepared->executeQuery();
+ xResultSet->next(); // use it
+ Reference<XRow> xRow(xResultSet, UNO_QUERY);
+ CPPUNIT_ASSERT_EQUAL(OUString("11.22"), xRow->getString(1));
+ // converting to integer types results in rounding down the number
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int8>(11), xRow->getByte(1));
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int16>(11), xRow->getShort(1));
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(11), xRow->getInt(1));
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int64>(11), xRow->getLong(1));
+
+ xStatement->executeUpdate("DROP TABLE myTestTable");
+}
+
+/**
+ * Test cursor positioning method isAfterLast in case of using prepared
+ * statement.
+ */
+void MysqlTestDriver::testPreparedStmtIsAfterLast()
+{
+ Reference<XConnection> xConnection = m_xDriver->connect(m_sUrl, m_infos);
+ if (!xConnection.is())
+ CPPUNIT_ASSERT_MESSAGE("cannot connect to data source!", xConnection.is());
+ uno::Reference<XStatement> xStatement = xConnection->createStatement();
+ CPPUNIT_ASSERT(xStatement.is());
+ xStatement->executeUpdate("DROP TABLE IF EXISTS myTestTable");
+
+ // create test table
+ xStatement->executeUpdate("CREATE TABLE myTestTable (id INTEGER PRIMARY KEY)");
+ Reference<XPreparedStatement> xPrepared
+ = xConnection->prepareStatement(OUString{ "INSERT INTO myTestTable VALUES (?)" });
+ Reference<XParameters> xParams(xPrepared, UNO_QUERY);
+ constexpr int ROW_COUNT = 6;
+ for (int i = 0; i < ROW_COUNT; ++i)
+ {
+ xParams->setShort(1, i);
+ xPrepared->executeUpdate();
+ }
+
+ // query test table
+ xPrepared = xConnection->prepareStatement("SELECT id from myTestTable where id = 3");
+ Reference<XResultSet> xResultSet = xPrepared->executeQuery();
+
+ // There should be exactly one row, therefore IsAfterLast is false at first.
+ xResultSet->next();
+ CPPUNIT_ASSERT(!xResultSet->isAfterLast());
+
+ // attempt to fetch more data
+ bool hasData = xResultSet->next();
+ CPPUNIT_ASSERT(!hasData); // now we are on "AfterLast"
+ CPPUNIT_ASSERT(xResultSet->isAfterLast());
+ xStatement->executeUpdate("DROP TABLE IF EXISTS myTestTable");
+}
+
+void MysqlTestDriver::testGetStringFromBloColumnb()
+{
+ Reference<XConnection> xConnection = m_xDriver->connect(m_sUrl, m_infos);
+ if (!xConnection.is())
+ CPPUNIT_ASSERT_MESSAGE("cannot connect to data source!", xConnection.is());
+ uno::Reference<XStatement> xStatement = xConnection->createStatement();
+ CPPUNIT_ASSERT(xStatement.is());
+ xStatement->executeUpdate("DROP TABLE IF EXISTS myTestTable");
+
+ // create test table
+ xStatement->executeUpdate("CREATE TABLE myTestTable (id INTEGER PRIMARY KEY, tinytexty "
+ "TINYTEXT, texty TEXT, mediumTexty MEDIUMTEXT, longtexty LONGTEXT)");
+ Reference<XPreparedStatement> xPrepared = xConnection->prepareStatement(
+ OUString{ "INSERT INTO myTestTable VALUES (?, ?, ?, ?, ?)" });
+ Reference<XParameters> xParams(xPrepared, UNO_QUERY);
+ constexpr int ROW_COUNT = 6;
+ for (int i = 0; i < ROW_COUNT; ++i)
+ {
+ xParams->setShort(1, i);
+ xParams->setString(2, OUString::number(i));
+ xParams->setString(3, OUString::number(i));
+ xParams->setString(4, OUString::number(i));
+ xParams->setString(5, OUString::number(i));
+ xPrepared->executeUpdate();
+ }
+
+ // query test table
+ xPrepared = xConnection->prepareStatement(
+ "SELECT tinytexty, texty, mediumtexty, longtexty from myTestTable where texty LIKE '3'");
+ Reference<XResultSet> xResultSet = xPrepared->executeQuery();
+ xResultSet->next();
+ Reference<XRow> xRow(xResultSet, UNO_QUERY);
+
+ // all the textual blob types should be able to be queried via getString().
+ CPPUNIT_ASSERT_EQUAL(OUString("3"), xRow->getString(1));
+ CPPUNIT_ASSERT_EQUAL(OUString("3"), xRow->getString(2));
+ CPPUNIT_ASSERT_EQUAL(OUString("3"), xRow->getString(3));
+ CPPUNIT_ASSERT_EQUAL(OUString("3"), xRow->getString(4));
+
+ xStatement->executeUpdate("DROP TABLE IF EXISTS myTestTable");
+}
+
+CPPUNIT_TEST_SUITE_REGISTRATION(MysqlTestDriver);
+
+CPPUNIT_PLUGIN_IMPLEMENT();
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/qa/connectivity/resource/sharedresources_test.cxx b/connectivity/qa/connectivity/resource/sharedresources_test.cxx
new file mode 100644
index 0000000000..9c8f4e4396
--- /dev/null
+++ b/connectivity/qa/connectivity/resource/sharedresources_test.cxx
@@ -0,0 +1,106 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <test/bootstrapfixture.hxx>
+#include <rtl/ustring.hxx>
+#include <sal/types.h>
+
+#include <resource/sharedresources.hxx>
+#include <strings.hrc>
+
+#include <utility>
+#include <vector>
+
+using namespace css;
+
+namespace connectivity_test
+{
+#define TEST_SOURCE_STRING NC_("TEST_SOURCE_STRING", "UnitTest")
+#define TEST_SOURCE_ONE_SUBSTITUTION NC_("TEST_SOURCE_ONE_SUBSTITUTION", "One substitution $sub$")
+#define TEST_SOURCE_TWO_SUBSTITUTION \
+ NC_("TEST_SOURCE_TWO_SUBSTITUTION", "Two substitution $sub0$ $sub1$")
+#define TEST_SOURCE_THREE_SUBSTITUTION \
+ NC_("TEST_SOURCE_THREE_SUBSTITUTION", "Three substitution $sub0$ $sub1$ $sub2$")
+
+class SharedResourcesTest : public test::BootstrapFixture
+{
+public:
+ SharedResourcesTest();
+
+ void testGetSourceString();
+ void testGetSourceStringWithSubstitutionOne();
+ void testGetSourceStringWithSubstitutionTwo();
+ void testGetSourceStringWithSubstitutionThree();
+ void testGetSourceStringWithSubstitutionVector();
+
+ CPPUNIT_TEST_SUITE(SharedResourcesTest);
+
+ CPPUNIT_TEST(testGetSourceString);
+ CPPUNIT_TEST(testGetSourceStringWithSubstitutionOne);
+ CPPUNIT_TEST(testGetSourceStringWithSubstitutionTwo);
+ CPPUNIT_TEST(testGetSourceStringWithSubstitutionThree);
+ CPPUNIT_TEST(testGetSourceStringWithSubstitutionVector);
+
+ CPPUNIT_TEST_SUITE_END();
+
+private:
+ ::connectivity::SharedResources m_aResource;
+};
+
+SharedResourcesTest::SharedResourcesTest()
+ : test::BootstrapFixture(false, false)
+{
+}
+
+void SharedResourcesTest::testGetSourceString()
+{
+ CPPUNIT_ASSERT_EQUAL(OUString("UnitTest"), m_aResource.getResourceString(TEST_SOURCE_STRING));
+}
+
+void SharedResourcesTest::testGetSourceStringWithSubstitutionOne()
+{
+ CPPUNIT_ASSERT_EQUAL(OUString("One substitution UnitTest"),
+ m_aResource.getResourceStringWithSubstitution(TEST_SOURCE_ONE_SUBSTITUTION,
+ "$sub$", "UnitTest"));
+}
+
+void SharedResourcesTest::testGetSourceStringWithSubstitutionTwo()
+{
+ CPPUNIT_ASSERT_EQUAL(OUString("Two substitution UnitTest1 UnitTest2"),
+ m_aResource.getResourceStringWithSubstitution(TEST_SOURCE_TWO_SUBSTITUTION,
+ "$sub0$", "UnitTest1",
+ "$sub1$", "UnitTest2"));
+}
+
+void SharedResourcesTest::testGetSourceStringWithSubstitutionThree()
+{
+ CPPUNIT_ASSERT_EQUAL(OUString("Three substitution UnitTest1 UnitTest2 UnitTest3"),
+ m_aResource.getResourceStringWithSubstitution(
+ TEST_SOURCE_THREE_SUBSTITUTION, "$sub0$", "UnitTest1", "$sub1$",
+ "UnitTest2", "$sub2$", "UnitTest3"));
+}
+
+void SharedResourcesTest::testGetSourceStringWithSubstitutionVector()
+{
+ std::vector<std::pair<const char*, OUString>> aStringToSubstitutes{ { "$sub0$", "vector0" },
+ { "$sub1$", "vector1" },
+ { "$sub2$", "vector2" } };
+
+ CPPUNIT_ASSERT_EQUAL(OUString("Three substitution vector0 vector1 vector2"),
+ m_aResource.getResourceStringWithSubstitution(
+ TEST_SOURCE_THREE_SUBSTITUTION, aStringToSubstitutes));
+}
+
+CPPUNIT_TEST_SUITE_REGISTRATION(SharedResourcesTest);
+
+} // namespace connectivity_test
+
+CPPUNIT_PLUGIN_IMPLEMENT();
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/connectivity/qa/connectivity/tools/AbstractDatabase.java b/connectivity/qa/connectivity/tools/AbstractDatabase.java
new file mode 100644
index 0000000000..d34b39066e
--- /dev/null
+++ b/connectivity/qa/connectivity/tools/AbstractDatabase.java
@@ -0,0 +1,207 @@
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+package connectivity.tools;
+
+import com.sun.star.container.XNameAccess;
+import com.sun.star.frame.XModel;
+import com.sun.star.frame.XStorable;
+import com.sun.star.io.IOException;
+import com.sun.star.lang.XMultiServiceFactory;
+import com.sun.star.sdb.XDocumentDataSource;
+import com.sun.star.sdb.XOfficeDatabaseDocument;
+import com.sun.star.sdbc.SQLException;
+import com.sun.star.sdbc.XCloseable;
+import com.sun.star.sdbc.XStatement;
+import com.sun.star.uno.UnoRuntime;
+import com.sun.star.util.CloseVetoException;
+import connectivity.tools.sdb.Connection;
+import static org.junit.Assert.*;
+
+public abstract class AbstractDatabase implements DatabaseAccess
+{
+ public AbstractDatabase(final XMultiServiceFactory orb) throws Exception
+ {
+ m_orb = orb;
+ }
+
+
+ public AbstractDatabase(final XMultiServiceFactory orb, final String _existingDocumentURL ) throws Exception
+ {
+ m_orb = orb;
+ createDBDocument( _existingDocumentURL );
+ }
+
+ /** returns a connection to the database
+ *
+ * Multiple calls to this method return the same connection. The DbaseDatabase object keeps
+ * the ownership of the connection, so you don't need to (and should not) dispose/close it.
+ */
+ public Connection defaultConnection() throws SQLException
+ {
+ if ( m_connection == null )
+ m_connection = new Connection( m_databaseDocument.getDataSource().getConnection("", "") );
+
+ return m_connection;
+ }
+
+ /** executes the given SQL statement via the defaultConnection
+ */
+ public void executeSQL(final String statementString) throws SQLException
+ {
+ final XStatement statement = defaultConnection().createStatement();
+ statement.execute(statementString);
+ }
+
+ /** stores the database document
+ */
+ public void store() throws IOException
+ {
+ if (m_databaseDocument != null)
+ {
+ final XStorable storeDoc = UnoRuntime.queryInterface(XStorable.class, m_databaseDocument);
+ storeDoc.store();
+ }
+ }
+
+ /** closes the database document
+ *
+ * Any CloseVetoExceptions fired by third parties are ignored, and any reference to the
+ * database document is released.
+ */
+ public void close()
+ {
+ // close connection
+ final XCloseable closeConn = UnoRuntime.queryInterface( XCloseable.class,
+ m_connection != null ? m_connection.getXConnection() : null );
+ if (closeConn != null)
+ {
+ try
+ {
+ closeConn.close();
+ }
+ catch (SQLException e)
+ {
+ }
+ }
+ m_connection = null;
+
+ // close document
+ final com.sun.star.util.XCloseable closeDoc = UnoRuntime.queryInterface( com.sun.star.util.XCloseable.class, m_databaseDocument );
+ if (closeDoc != null)
+ {
+ try
+ {
+ closeDoc.close(true);
+ }
+ catch (CloseVetoException e)
+ {
+ }
+ }
+ m_databaseDocument = null;
+ }
+
+ /** closes the document, and deletes the underlying file
+ */
+ public void closeAndDelete()
+ {
+ close();
+ delete();
+ }
+
+ protected void delete() {}
+
+ /** returns the underlying database document
+ */
+ public XOfficeDatabaseDocument getDatabaseDocument()
+ {
+ return m_databaseDocument;
+ }
+
+ /** returns the model interface of the underlying database document
+ */
+ public XModel getModel()
+ {
+ return UnoRuntime.queryInterface( XModel.class, m_databaseDocument );
+ }
+
+ public XMultiServiceFactory getORB()
+ {
+ return m_orb;
+ }
+
+
+ final private void createDBDocument(final String _docURL) throws Exception
+ {
+ m_databaseDocumentFile = _docURL;
+
+ final XNameAccess dbContext = UnoRuntime.queryInterface( XNameAccess.class,
+ m_orb.createInstance( "com.sun.star.sdb.DatabaseContext" ) );
+ final XDocumentDataSource dataSource = UnoRuntime.queryInterface( XDocumentDataSource.class, dbContext.getByName( _docURL ) );
+
+ m_databaseDocument = dataSource.getDatabaseDocument();
+ m_dataSource = new DataSource(m_databaseDocument.getDataSource());
+ }
+
+ /** returns the URL of the ODB document represented by this instance
+ */
+ public String getDocumentURL()
+ {
+ return m_databaseDocumentFile;
+ }
+
+ /** returns the data source belonging to this database
+ */
+ public DataSource getDataSource()
+ {
+ return m_dataSource;
+ }
+
+ /** creates a row set operating the database, with a given command/type
+ */
+ public RowSet createRowSet(final int _commandType, final String _command)
+ {
+ return new RowSet(m_orb, getDocumentURL(), _commandType, _command);
+ }
+
+ @Override
+ protected void finalize() throws Throwable
+ {
+ // Cannot call close() here, as it accesses UNO objects (that may
+ // already have been finalized):
+ assertNull(
+ "missing call to connectivity.tools.AbstractDatabase.close",
+ m_connection);
+ assertNull(
+ "missing call to connectivity.tools.AbstractDatabase.close",
+ m_databaseDocument);
+
+ delete();
+ super.finalize();
+ }
+
+ // the service factory
+ protected final XMultiServiceFactory m_orb;
+ // the URL of the temporary file used for the database document
+ protected String m_databaseDocumentFile;
+ // the database document
+ protected XOfficeDatabaseDocument m_databaseDocument;
+ // the data source belonging to the database document
+ protected DataSource m_dataSource;
+ // the default connection
+ private Connection m_connection;
+}
diff --git a/connectivity/qa/connectivity/tools/CRMDatabase.java b/connectivity/qa/connectivity/tools/CRMDatabase.java
new file mode 100644
index 0000000000..3d33926280
--- /dev/null
+++ b/connectivity/qa/connectivity/tools/CRMDatabase.java
@@ -0,0 +1,277 @@
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+package connectivity.tools;
+
+import com.sun.star.beans.PropertyValue;
+import com.sun.star.beans.PropertyState;
+import com.sun.star.container.ElementExistException;
+import com.sun.star.container.NoSuchElementException;
+import com.sun.star.frame.XComponentLoader;
+import com.sun.star.frame.XController;
+import com.sun.star.frame.XModel;
+import com.sun.star.io.IOException;
+import com.sun.star.lang.IllegalArgumentException;
+import com.sun.star.lang.WrappedTargetException;
+import com.sun.star.lang.XComponent;
+import com.sun.star.lang.XMultiServiceFactory;
+import com.sun.star.sdb.application.XDatabaseDocumentUI;
+import com.sun.star.sdbc.SQLException;
+import com.sun.star.uno.UnoRuntime;
+import connectivity.tools.sdb.Connection;
+
+/** implements a small Customer Relationship Management database
+ *
+ * Not finished, by far. Feel free to add features as you need them.
+ */
+public class CRMDatabase
+{
+ private static final String INTEGER = "INTEGER";
+ private static final String VARCHAR50 = "VARCHAR(50)";
+ private final XMultiServiceFactory m_orb;
+ private final HsqlDatabase m_database;
+ private final Connection m_connection;
+
+ /** constructs the CRM database
+ */
+ public CRMDatabase( XMultiServiceFactory _orb, boolean _withUI ) throws Exception
+ {
+ m_orb = _orb;
+
+ m_database = new HsqlDatabase( m_orb );
+
+ if ( _withUI )
+ {
+ final XComponentLoader loader = UnoRuntime.queryInterface( XComponentLoader.class,
+ m_orb.createInstance( "com.sun.star.frame.Desktop" ) );
+ PropertyValue[] loadArgs = new PropertyValue[] {
+ new PropertyValue( "PickListEntry", 0, false, PropertyState.DIRECT_VALUE )
+ };
+ loader.loadComponentFromURL( m_database.getDocumentURL(), "_blank", 0, loadArgs );
+ getDocumentUI().connect();
+ m_connection = new Connection( getDocumentUI().getActiveConnection() );
+ }
+ else
+ {
+ m_connection = m_database.defaultConnection();
+ }
+
+ createTables();
+ createQueries();
+ }
+
+ /**
+ * creates a CRMDatabase from an existing document, given by URL
+ */
+ public CRMDatabase( XMultiServiceFactory _orb, final String _existingDocumentURL ) throws Exception
+ {
+ m_orb = _orb;
+
+ m_database = new HsqlDatabase( m_orb, _existingDocumentURL );
+ m_connection = m_database.defaultConnection();
+ }
+
+
+ /** returns the database document underlying the CRM database
+ */
+ public final HsqlDatabase getDatabase()
+ {
+ return m_database;
+ }
+
+
+ /** returns the default connection to the database
+ */
+ public final Connection getConnection()
+ {
+ return m_connection;
+ }
+
+
+ public void saveAndClose() throws IOException
+ {
+ XDatabaseDocumentUI ui = getDocumentUI();
+ if ( ui != null )
+ ui.closeSubComponents();
+ m_database.store();
+ m_database.closeAndDelete();
+ }
+
+
+ private XDatabaseDocumentUI getDocumentUI()
+ {
+ XModel docModel = UnoRuntime.queryInterface( XModel.class, m_database.getDatabaseDocument() );
+ return UnoRuntime.queryInterface( XDatabaseDocumentUI.class, docModel.getCurrentController() );
+ }
+
+
+ public XController loadSubComponent( final int _objectType, final String _name ) throws IllegalArgumentException, SQLException, NoSuchElementException
+ {
+ XDatabaseDocumentUI docUI = getDocumentUI();
+ if ( !docUI.isConnected() )
+ docUI.connect();
+
+ XComponent subComponent = docUI.loadComponent( _objectType, _name, false );
+ XController controller = UnoRuntime.queryInterface( XController.class, subComponent );
+ if ( controller != null )
+ return controller;
+ XModel document = UnoRuntime.queryInterface( XModel.class, subComponent );
+ return document.getCurrentController();
+ }
+
+
+ private void createTables() throws SQLException
+ {
+ HsqlTableDescriptor table = new HsqlTableDescriptor( "categories",
+ new HsqlColumnDescriptor[] {
+ new HsqlColumnDescriptor( "ID",INTEGER, HsqlColumnDescriptor.PRIMARY ),
+ new HsqlColumnDescriptor( "Name",VARCHAR50),
+ new HsqlColumnDescriptor( "Description", "VARCHAR(1024)" ),
+ new HsqlColumnDescriptor( "Image", "LONGVARBINARY" ) } );
+ m_database.createTable( table, true );
+
+ m_database.executeSQL( "INSERT INTO \"categories\" ( \"ID\", \"Name\" ) VALUES ( 1, 'Food' )" );
+ m_database.executeSQL( "INSERT INTO \"categories\" ( \"ID\", \"Name\" ) VALUES ( 2, 'Furniture' )" );
+
+ table = new HsqlTableDescriptor( "products",
+ new HsqlColumnDescriptor[] {
+ new HsqlColumnDescriptor( "ID",INTEGER, HsqlColumnDescriptor.PRIMARY ),
+ new HsqlColumnDescriptor( "Name",VARCHAR50),
+ new HsqlColumnDescriptor( "CategoryID",INTEGER, HsqlColumnDescriptor.REQUIRED, "categories", "ID" ) } );
+ m_database.createTable( table, true );
+
+ m_database.executeSQL( "INSERT INTO \"products\" VALUES ( 1, 'Oranges', 1 )" );
+ m_database.executeSQL( "INSERT INTO \"products\" VALUES ( 2, 'Apples', 1 )" );
+ m_database.executeSQL( "INSERT INTO \"products\" VALUES ( 3, 'Pears', 1 )" );
+ m_database.executeSQL( "INSERT INTO \"products\" VALUES ( 4, 'Strawberries', 1 )" );
+
+ table = new HsqlTableDescriptor( "customers",
+ new HsqlColumnDescriptor[] {
+ new HsqlColumnDescriptor( "ID",INTEGER, HsqlColumnDescriptor.PRIMARY ),
+ new HsqlColumnDescriptor( "Name",VARCHAR50),
+ new HsqlColumnDescriptor( "Address",VARCHAR50),
+ new HsqlColumnDescriptor( "City",VARCHAR50),
+ new HsqlColumnDescriptor( "Postal",VARCHAR50),
+ new HsqlColumnDescriptor( "Comment","LONGVARCHAR")} );
+ m_database.createTable( table, true );
+
+ m_database.executeSQL( "INSERT INTO \"customers\" VALUES(1,'Food, Inc.','Down Under','Melbourne','509','Preferred') " );
+ m_database.executeSQL( "INSERT INTO \"customers\" VALUES(2,'Simply Delicious','Down Under','Melbourne','518',null) " );
+ m_database.executeSQL( "INSERT INTO \"customers\" VALUES(3,'Pure Health','10 Fish St.','San Francisco','94107',null) " );
+ m_database.executeSQL( "INSERT INTO \"customers\" VALUES(4,'Milk And More','Arlington Road 21','Dublin','31021','Good one.') " );
+
+ table = new HsqlTableDescriptor( "orders",
+ new HsqlColumnDescriptor[] {
+ new HsqlColumnDescriptor( "ID",INTEGER, HsqlColumnDescriptor.PRIMARY ),
+ new HsqlColumnDescriptor( "CustomerID",INTEGER, HsqlColumnDescriptor.REQUIRED, "customers", "ID" ),
+ new HsqlColumnDescriptor( "OrderDate", "DATE" ),
+ new HsqlColumnDescriptor( "ShipDate", "DATE" ) } );
+ m_database.createTable( table, true );
+
+ m_database.executeSQL( "INSERT INTO \"orders\" (\"ID\", \"CustomerID\", \"OrderDate\") VALUES(1, 1, {D '2009-01-01'})" );
+ m_database.executeSQL( "INSERT INTO \"orders\" VALUES(2, 2, {D '2009-01-01'}, {D '2009-01-23'})" );
+
+ table = new HsqlTableDescriptor( "orders_details",
+ new HsqlColumnDescriptor[] {
+ new HsqlColumnDescriptor( "OrderID",INTEGER, HsqlColumnDescriptor.PRIMARY, "orders", "ID" ),
+ new HsqlColumnDescriptor( "ProductID",INTEGER, HsqlColumnDescriptor.PRIMARY, "products", "ID" ),
+ new HsqlColumnDescriptor( "Quantity",INTEGER) } );
+ m_database.createTable( table, true );
+
+ m_database.executeSQL( "INSERT INTO \"orders_details\" VALUES(1, 1, 100)" );
+ m_database.executeSQL( "INSERT INTO \"orders_details\" VALUES(1, 2, 100)" );
+ m_database.executeSQL( "INSERT INTO \"orders_details\" VALUES(2, 2, 2000)" );
+ m_database.executeSQL( "INSERT INTO \"orders_details\" VALUES(2, 3, 2000)" );
+ m_database.executeSQL( "INSERT INTO \"orders_details\" VALUES(2, 4, 2000)" );
+
+ // since we created the tables by directly executing the SQL statements, we need to refresh
+ // the tables container
+ m_connection.refreshTables();
+ }
+
+
+ private void validateUnparseable()
+ {
+ /*
+ // The "unparseable" query should be indeed be unparseable by OOo (though a valid HSQL query)
+ XSingleSelectQueryComposer composer;
+ QueryDefinition unparseableQuery;
+ try
+ {
+ final XMultiServiceFactory factory = UnoRuntime.queryInterface(
+ XMultiServiceFactory.class, m_database.defaultConnection().getXConnection() );
+ composer = UnoRuntime.queryInterface(
+ XSingleSelectQueryComposer.class, factory.createInstance( "com.sun.star.sdb.SingleSelectQueryComposer" ) );
+ unparseableQuery = m_dataSource.getQueryDefinition( "unparseable" );
+ }
+ catch( Exception e )
+ {
+ throw new RuntimeException( "caught an unexpected exception: " + e.getMessage() );
+ }
+
+ boolean caughtExpected = false;
+ try
+ {
+ composer.setQuery( unparseableQuery.getCommand() );
+ }
+ catch (WrappedTargetException e) { }
+ catch( SQLException e )
+ {
+ caughtExpected = true;
+ }
+
+ if ( !caughtExpected )
+ throw new RuntimeException( "Somebody improved the parser! This is bad :), since we need an unparsable query here!" );
+ */
+ }
+
+
+ private void createQueries() throws ElementExistException, WrappedTargetException, com.sun.star.lang.IllegalArgumentException
+ {
+ m_database.getDataSource().createQuery(
+ "all orders",
+ "SELECT \"orders\".\"ID\" AS \"Order No.\", " +
+ "\"customers\".\"Name\" AS \"Customer Name\", " +
+ "\"orders\".\"OrderDate\" AS \"Order Date\", " +
+ "\"orders\".\"ShipDate\" AS \"Ship Date\", " +
+ "\"orders_details\".\"Quantity\", " +
+ "\"products\".\"Name\" AS \"Product Name\" " +
+ "FROM \"orders_details\" AS \"orders_details\", " +
+ "\"orders\" AS \"orders\", " +
+ "\"products\" AS \"products\", " +
+ "\"customers\" AS \"customers\" " +
+ "WHERE ( \"orders_details\".\"OrderID\" = \"orders\".\"ID\" " +
+ "AND \"orders_details\".\"ProductID\" = \"products\".\"ID\" " +
+ "AND \"orders\".\"CustomerID\" = \"customers\".\"ID\" )"
+ );
+
+ m_database.getDataSource().createQuery(
+ "unshipped orders",
+ "SELECT * " +
+ "FROM \"all orders\"" +
+ "WHERE ( \"ShipDate\" IS NULL )"
+ );
+
+ m_database.getDataSource().createQuery( "parseable", "SELECT * FROM \"customers\"" );
+ m_database.getDataSource().createQuery( "parseable native", "SELECT * FROM INFORMATION_SCHEMA.SYSTEM_VIEWS", false );
+/*
+ m_database.getDataSource().createQuery( "unparseable",
+ "SELECT {fn DAYOFMONTH ('2001-01-01')} AS \"ID_VARCHAR\" FROM \"products\"", false );
+*/
+ validateUnparseable();
+ }
+}
diff --git a/connectivity/qa/connectivity/tools/CsvDatabase.java b/connectivity/qa/connectivity/tools/CsvDatabase.java
new file mode 100644
index 0000000000..abb016c90a
--- /dev/null
+++ b/connectivity/qa/connectivity/tools/CsvDatabase.java
@@ -0,0 +1,31 @@
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+package connectivity.tools;
+
+import com.sun.star.lang.XMultiServiceFactory;
+
+public class CsvDatabase extends FlatFileDatabase
+{
+
+ public CsvDatabase( final XMultiServiceFactory i_orb ) throws Exception
+ {
+ super( i_orb, "flat" );
+ }
+
+}
diff --git a/connectivity/qa/connectivity/tools/DataSource.java b/connectivity/qa/connectivity/tools/DataSource.java
new file mode 100644
index 0000000000..844c4488f8
--- /dev/null
+++ b/connectivity/qa/connectivity/tools/DataSource.java
@@ -0,0 +1,150 @@
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+package connectivity.tools;
+
+import com.sun.star.container.ElementExistException;
+import com.sun.star.container.NoSuchElementException;
+import com.sun.star.container.XNameAccess;
+import com.sun.star.container.XNameContainer;
+import com.sun.star.lang.WrappedTargetException;
+import com.sun.star.lang.XSingleServiceFactory;
+import com.sun.star.lang.XMultiServiceFactory;
+import com.sun.star.beans.XPropertySet;
+import com.sun.star.sdb.XQueryDefinitionsSupplier;
+import com.sun.star.sdbc.XDataSource;
+import com.sun.star.uno.Exception;
+import com.sun.star.uno.UnoRuntime;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+public class DataSource
+{
+ // the service factory
+
+ private final XDataSource m_dataSource;
+
+ public DataSource(final XMultiServiceFactory _orb, final String _registeredName) throws Exception
+ {
+ final XNameAccess dbContext = UnoRuntime.queryInterface(
+ XNameAccess.class, _orb.createInstance( "com.sun.star.sdb.DatabaseContext" ) );
+
+ m_dataSource = UnoRuntime.queryInterface( XDataSource.class, dbContext.getByName( _registeredName ) );
+ }
+
+ public DataSource(final XDataSource _dataSource)
+ {
+ m_dataSource = _dataSource;
+ }
+
+ final public XDataSource getXDataSource()
+ {
+ return m_dataSource;
+ }
+
+ /**
+ * retrieves the data source's settings
+ */
+ public XPropertySet geSettings()
+ {
+ return UnoRuntime.queryInterface( XPropertySet.class, impl_getPropertyValue( "Settings" ) );
+ }
+
+ /** creates a query with a given name and SQL command
+ */
+ public void createQuery(final String _name, final String _sqlCommand) throws ElementExistException, WrappedTargetException, com.sun.star.lang.IllegalArgumentException
+ {
+ createQuery(_name, _sqlCommand, true);
+ }
+
+ /** creates a query with a given name, SQL command, and EscapeProcessing flag
+ */
+ public void createQuery(final String _name, final String _sqlCommand, final boolean _escapeProcessing) throws ElementExistException, WrappedTargetException, com.sun.star.lang.IllegalArgumentException
+ {
+ final XSingleServiceFactory queryDefsFac = UnoRuntime.queryInterface( XSingleServiceFactory.class, getQueryDefinitions() );
+ XPropertySet queryDef = null;
+ try
+ {
+ queryDef = UnoRuntime.queryInterface( XPropertySet.class, queryDefsFac.createInstance() );
+ queryDef.setPropertyValue("Command", _sqlCommand);
+ queryDef.setPropertyValue("EscapeProcessing", Boolean.valueOf(_escapeProcessing));
+ }
+ catch (com.sun.star.uno.Exception e)
+ {
+ e.printStackTrace(System.err);
+ }
+
+ final XNameContainer queryDefsContainer = UnoRuntime.queryInterface( XNameContainer.class, getQueryDefinitions() );
+ queryDefsContainer.insertByName(_name, queryDef);
+ }
+
+ /** provides the query definition with the given name
+ */
+ public QueryDefinition getQueryDefinition(final String _name) throws NoSuchElementException
+ {
+ final XNameAccess allDefs = getQueryDefinitions();
+ try
+ {
+ return new QueryDefinition( UnoRuntime.queryInterface( XPropertySet.class, allDefs.getByName( _name) ) );
+ }
+ catch (WrappedTargetException e)
+ {
+ }
+ throw new NoSuchElementException();
+ }
+
+ /** provides the container of query definitions of the data source
+ */
+ private XNameAccess getQueryDefinitions()
+ {
+ final XQueryDefinitionsSupplier suppQueries = UnoRuntime.queryInterface(
+ XQueryDefinitionsSupplier.class, m_dataSource);
+ return suppQueries.getQueryDefinitions();
+ }
+
+ /**
+ * retrieves a property value from the data source
+ * @param i_propertyName
+ * the name of the property whose value is to be returned.
+ */
+ private Object impl_getPropertyValue( final String i_propertyName )
+ {
+ Object propertyValue = null;
+ try
+ {
+ final XPropertySet dataSourceProps = UnoRuntime.queryInterface( XPropertySet.class, m_dataSource );
+ propertyValue = dataSourceProps.getPropertyValue( i_propertyName );
+ }
+ catch (Exception ex)
+ {
+ Logger.getLogger(DataSource.class.getName()).log(Level.SEVERE, null, ex);
+ }
+ return propertyValue;
+ }
+
+ /** returns the name of the data source
+ *
+ * If a data source is registered at the database context, the name is the registration
+ * name. Otherwise, it's the URL which the respective database document is based on.
+ *
+ * Note that the above definition is from the UNO API, not from this wrapper here.
+ */
+ public String getName()
+ {
+ return (String)impl_getPropertyValue( "Name" );
+ }
+}
diff --git a/connectivity/qa/connectivity/tools/DatabaseAccess.java b/connectivity/qa/connectivity/tools/DatabaseAccess.java
new file mode 100644
index 0000000000..347faa46e2
--- /dev/null
+++ b/connectivity/qa/connectivity/tools/DatabaseAccess.java
@@ -0,0 +1,50 @@
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+package connectivity.tools;
+
+import com.sun.star.frame.XModel;
+import com.sun.star.io.IOException;
+import com.sun.star.lang.XMultiServiceFactory;
+import com.sun.star.sdb.XOfficeDatabaseDocument;
+import com.sun.star.sdbc.SQLException;
+import connectivity.tools.sdb.Connection;
+
+public interface DatabaseAccess
+{
+ Connection defaultConnection() throws SQLException;
+
+ void executeSQL(final String statementString) throws SQLException;
+
+ void store() throws IOException;
+
+ void close();
+
+ void closeAndDelete();
+
+ XOfficeDatabaseDocument getDatabaseDocument();
+
+ XModel getModel();
+
+ String getDocumentURL();
+
+ DataSource getDataSource();
+
+ RowSet createRowSet(final int _commandType, final String _command);
+
+ XMultiServiceFactory getORB();
+}
diff --git a/connectivity/qa/connectivity/tools/DbaseDatabase.java b/connectivity/qa/connectivity/tools/DbaseDatabase.java
new file mode 100644
index 0000000000..9a1dc84481
--- /dev/null
+++ b/connectivity/qa/connectivity/tools/DbaseDatabase.java
@@ -0,0 +1,32 @@
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+package connectivity.tools;
+
+import com.sun.star.lang.XMultiServiceFactory;
+
+public class DbaseDatabase extends FlatFileDatabase
+{
+
+ public DbaseDatabase( final XMultiServiceFactory i_orb ) throws Exception
+ {
+ super( i_orb, "dbase" );
+ }
+
+
+}
diff --git a/connectivity/qa/connectivity/tools/FlatFileDatabase.java b/connectivity/qa/connectivity/tools/FlatFileDatabase.java
new file mode 100644
index 0000000000..5351ba953c
--- /dev/null
+++ b/connectivity/qa/connectivity/tools/FlatFileDatabase.java
@@ -0,0 +1,74 @@
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+package connectivity.tools;
+
+import com.sun.star.beans.PropertyValue;
+import com.sun.star.beans.XPropertySet;
+import com.sun.star.frame.XStorable;
+import com.sun.star.lang.XMultiServiceFactory;
+import com.sun.star.sdb.XOfficeDatabaseDocument;
+import com.sun.star.uno.UnoRuntime;
+
+import helper.URLHelper;
+import java.io.File;
+
+class FlatFileDatabase extends AbstractDatabase
+{
+
+ protected FlatFileDatabase( final XMultiServiceFactory i_orb, final String i_urlSubScheme ) throws Exception
+ {
+ super(i_orb);
+ m_urlSubScheme = i_urlSubScheme;
+ createDBDocument();
+ }
+
+
+ /**
+ * returns a {@link File} which represents the folder where the database's table files reside.
+ */
+ public File getTableFileLocation()
+ {
+ return m_tableFileLocation;
+ }
+
+ /** creates an empty database document in a temporary location
+ */
+ private void createDBDocument() throws Exception
+ {
+ final File documentFile = File.createTempFile( m_urlSubScheme, ".odb" );
+ if ( documentFile.exists() )
+ documentFile.delete();
+ m_tableFileLocation = new File(documentFile.getParent() + File.separator + documentFile.getName().replace(".odb", "") + File.separator );
+ m_tableFileLocation.mkdir();
+ m_databaseDocumentFile = URLHelper.getFileURLFromSystemPath(documentFile);
+ final String path = URLHelper.getFileURLFromSystemPath( m_tableFileLocation.getPath() );
+
+ m_databaseDocument = UnoRuntime.queryInterface( XOfficeDatabaseDocument.class,
+ m_orb.createInstance("com.sun.star.sdb.OfficeDatabaseDocument"));
+ m_dataSource = new DataSource(m_databaseDocument.getDataSource());
+
+ final XPropertySet dsProperties = UnoRuntime.queryInterface(XPropertySet.class, m_databaseDocument.getDataSource());
+ dsProperties.setPropertyValue("URL", "sdbc:" + m_urlSubScheme + ":" + path);
+
+ final XStorable storable = UnoRuntime.queryInterface( XStorable.class, m_databaseDocument );
+ storable.storeAsURL( m_databaseDocumentFile, new PropertyValue[] { } );
+ }
+
+ private final String m_urlSubScheme;
+ private File m_tableFileLocation = null;
+}
diff --git a/connectivity/qa/connectivity/tools/HsqlColumnDescriptor.java b/connectivity/qa/connectivity/tools/HsqlColumnDescriptor.java
new file mode 100644
index 0000000000..12330ff709
--- /dev/null
+++ b/connectivity/qa/connectivity/tools/HsqlColumnDescriptor.java
@@ -0,0 +1,75 @@
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+package connectivity.tools;
+
+/** is a very simply and rudimentary descriptor of table columns, for creating HSQLDB tables
+ */
+public class HsqlColumnDescriptor
+{
+ private final String Name;
+ private final String TypeName;
+ private final boolean Required;
+ private final boolean PrimaryKey;
+ private final String ForeignTable;
+ private final String ForeignColumn;
+
+ public final String getName() { return Name; }
+ public final String getTypeName() { return TypeName; }
+ public final boolean isRequired() { return Required; }
+ public final boolean isPrimaryKey() { return PrimaryKey; }
+
+ public final boolean isForeignKey() { return ( ForeignTable.length() != 0 ) && ( ForeignColumn.length() != 0 ); }
+ public final String getForeignTable() { return ForeignTable; }
+ public final String getForeignColumn() { return ForeignColumn; }
+
+ /// determines that a column is required, i.e. not nullable
+ public static final int REQUIRED = 1;
+ /// determines that a column is part of the primary key of its table
+ public static final int PRIMARY = 2;
+
+ public HsqlColumnDescriptor( String _Name, String _TypeName )
+ {
+ Name = _Name;
+ TypeName = _TypeName;
+ Required = false;
+ PrimaryKey = false;
+ ForeignTable = "";
+ ForeignColumn = "";
+ }
+
+ public HsqlColumnDescriptor( String _Name, String _TypeName, int _Flags )
+ {
+ Name = _Name;
+ TypeName = _TypeName;
+ Required = ( _Flags & REQUIRED ) != 0;
+ PrimaryKey = ( _Flags & PRIMARY ) != 0;
+ ForeignTable = "";
+ ForeignColumn = "";
+ }
+
+ public HsqlColumnDescriptor( String _Name, String _TypeName, int _Flags, String _ForeignTable, String _ForeignColumn )
+ {
+ Name = _Name;
+ TypeName = _TypeName;
+ Required = ( _Flags & REQUIRED ) != 0;
+ PrimaryKey = ( _Flags & PRIMARY ) != 0;
+ ForeignTable = _ForeignTable;
+ ForeignColumn = _ForeignColumn;
+ }
+}
diff --git a/connectivity/qa/connectivity/tools/HsqlDatabase.java b/connectivity/qa/connectivity/tools/HsqlDatabase.java
new file mode 100644
index 0000000000..0d2ab4af96
--- /dev/null
+++ b/connectivity/qa/connectivity/tools/HsqlDatabase.java
@@ -0,0 +1,202 @@
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+package connectivity.tools;
+
+import com.sun.star.beans.PropertyValue;
+import com.sun.star.beans.PropertyState;
+import com.sun.star.beans.XPropertySet;
+import com.sun.star.container.ElementExistException;
+import com.sun.star.frame.XStorable;
+import com.sun.star.lang.XMultiServiceFactory;
+import com.sun.star.sdb.XOfficeDatabaseDocument;
+import com.sun.star.sdbc.SQLException;
+import com.sun.star.sdbcx.XAppend;
+import com.sun.star.sdbcx.XTablesSupplier;
+import com.sun.star.uno.UnoRuntime;
+
+import helper.URLHelper;
+import java.io.File;
+import java.util.HashMap;
+import java.util.Map;
+import org.junit.Assert;
+
+public class HsqlDatabase extends AbstractDatabase
+{
+
+
+ public HsqlDatabase(final XMultiServiceFactory orb) throws Exception
+ {
+ super(orb);
+ createDBDocument();
+ }
+
+
+ public HsqlDatabase(final XMultiServiceFactory orb, final String _existingDocumentURL) throws Exception
+ {
+ super(orb, _existingDocumentURL);
+ }
+
+ /** creates an empty database document in a temporary location
+ */
+ private void createDBDocument() throws Exception
+ {
+ Assert.assertNull(m_documentFile);
+ m_documentFile = File.createTempFile("testdb", ".odb");
+ if ( m_documentFile.exists() )
+ m_documentFile.delete();
+ m_databaseDocumentFile = URLHelper.getFileURLFromSystemPath(m_documentFile);
+
+ m_databaseDocument = UnoRuntime.queryInterface(
+ XOfficeDatabaseDocument.class, m_orb.createInstance("com.sun.star.sdb.OfficeDatabaseDocument"));
+ m_dataSource = new DataSource(m_databaseDocument.getDataSource());
+
+ final XPropertySet dsProperties = UnoRuntime.queryInterface(XPropertySet.class, m_databaseDocument.getDataSource());
+ dsProperties.setPropertyValue("URL", "sdbc:embedded:hsqldb");
+
+ final XStorable storable = UnoRuntime.queryInterface(XStorable.class, m_databaseDocument);
+ storable.storeAsURL( m_databaseDocumentFile, new PropertyValue[]
+ { new PropertyValue( "PickListEntry", 0, false, PropertyState.DIRECT_VALUE )
+ } );
+ }
+
+ @Override protected final void delete() {
+ if (m_documentFile != null) {
+ boolean ok = m_documentFile.delete();
+ //TODO: fails on Windows: Assert.assertTrue("delete " + m_documentFile.getPath(), ok);
+ }
+ }
+
+ /** drops the table with a given name
+
+ @param _name
+ the name of the table to drop
+ */
+ private void dropTable(final String _name) throws SQLException
+ {
+ final StringBuffer dropStatement = new StringBuffer("DROP TABLE \"");
+ dropStatement.append(_name);
+ dropStatement.append("\" IF EXISTS");
+ executeSQL(dropStatement.toString());
+ }
+
+ public void createTable(final HsqlTableDescriptor _tableDesc, final boolean _dropIfExists) throws SQLException
+ {
+ if (_dropIfExists)
+ {
+ dropTable(_tableDesc.getName());
+ }
+ createTable(_tableDesc);
+ }
+
+ /** creates a table
+ */
+ public void createTable(final HsqlTableDescriptor _tableDesc) throws SQLException
+ {
+ StringBuffer createStatement = new StringBuffer("CREATE CACHED TABLE \"");
+ createStatement.append(_tableDesc.getName());
+ createStatement.append("\" ( ");
+
+ String primaryKeyList = "";
+
+ final HashMap<String, String> foreignKeys = new HashMap<String, String>();
+ final HashMap<String, String> foreignKeyRefs = new HashMap<String, String>();
+
+ final HsqlColumnDescriptor[] columns = _tableDesc.getColumns();
+ for (int i = 0; i < columns.length; ++i)
+ {
+ if (i > 0)
+ {
+ createStatement.append(", ");
+ }
+
+ createStatement.append("\"").append(columns[i].getName());
+ createStatement.append("\" ").append(columns[i].getTypeName());
+
+ if (columns[i].isRequired())
+ {
+ createStatement.append(" NOT NULL");
+ }
+
+ if (columns[i].isPrimaryKey())
+ {
+ if (primaryKeyList.length() > 0)
+ {
+ primaryKeyList += ", ";
+ }
+ primaryKeyList += "\"" + columns[i].getName() + "\"";
+ }
+
+ if (columns[i].isForeignKey())
+ {
+ final String foreignTable = columns[i].getForeignTable();
+
+ String foreignKeysForTable = foreignKeys.containsKey(foreignTable) ? foreignKeys.get(foreignTable) : "";
+ if (foreignKeysForTable.length() > 0)
+ {
+ foreignKeysForTable += ", ";
+ }
+ foreignKeysForTable += "\"" + columns[i].getName() + "\"";
+ foreignKeys.put(foreignTable, foreignKeysForTable);
+
+ final StringBuffer foreignKeyRefsForTable = new StringBuffer(foreignKeyRefs.containsKey(foreignTable) ? foreignKeyRefs.get(foreignTable) : "");
+ if (foreignKeyRefsForTable.length() > 0)
+ {
+ foreignKeyRefsForTable.append(", ");
+ }
+ foreignKeyRefsForTable.append("\"").append(columns[i].getForeignColumn()).append("\"");
+ foreignKeyRefs.put(foreignTable, foreignKeyRefsForTable.toString());
+ }
+ }
+
+ if (primaryKeyList.length() > 0)
+ {
+ createStatement.append(", PRIMARY KEY (");
+ createStatement.append(primaryKeyList);
+ createStatement.append(')');
+ }
+
+ for (Map.Entry<String, String> foreignKey : foreignKeys.entrySet())
+ {
+ final String foreignTable = foreignKey.getKey();
+
+ createStatement.append(", FOREIGN KEY (");
+ createStatement.append(foreignKey.getValue());
+ createStatement.append(") REFERENCES \"");
+ createStatement.append(foreignTable);
+ createStatement.append("\"(");
+ createStatement.append(foreignKeyRefs.get(foreignTable));
+ createStatement.append(')');
+ }
+
+ createStatement.append(')');
+
+ executeSQL(createStatement.toString());
+ }
+
+ /** creates a table in the database. using the SDBCX-API
+ */
+ public void createTableInSDBCX(final HsqlTableDescriptor _tableDesc) throws SQLException, ElementExistException
+ {
+ final XPropertySet sdbcxDescriptor = _tableDesc.createSdbcxDescriptor(defaultConnection());
+ final XTablesSupplier suppTables = UnoRuntime.queryInterface( XTablesSupplier.class, defaultConnection().getXConnection() );
+ final XAppend appendTable = UnoRuntime.queryInterface( XAppend.class, suppTables.getTables() );
+ appendTable.appendByDescriptor(sdbcxDescriptor);
+ }
+
+ private File m_documentFile;
+}
diff --git a/connectivity/qa/connectivity/tools/HsqlTableDescriptor.java b/connectivity/qa/connectivity/tools/HsqlTableDescriptor.java
new file mode 100644
index 0000000000..626f62eb83
--- /dev/null
+++ b/connectivity/qa/connectivity/tools/HsqlTableDescriptor.java
@@ -0,0 +1,93 @@
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+package connectivity.tools;
+
+import com.sun.star.beans.XPropertySet;
+import com.sun.star.container.XNameAccess;
+import com.sun.star.sdbc.ColumnValue;
+import com.sun.star.sdbcx.XColumnsSupplier;
+import com.sun.star.sdbcx.XDataDescriptorFactory;
+import com.sun.star.sdbcx.XTablesSupplier;
+import com.sun.star.uno.UnoRuntime;
+import connectivity.tools.sdb.Connection;
+
+/** is a very simply descriptor of a HSQL table, to be used with a HsqlDatabase.createTable method
+ */
+public class HsqlTableDescriptor
+{
+ private final String m_name;
+ private final HsqlColumnDescriptor[] m_columns;
+
+ /** Creates a new instance of HsqlTableDescriptor */
+ public HsqlTableDescriptor( String _name, HsqlColumnDescriptor[] _columns )
+ {
+ m_name = _name;
+ m_columns = _columns;
+ }
+
+ /** returns the name of the table
+ */
+ public String getName()
+ {
+ return m_name;
+ }
+
+ /** returns the set of column descriptors for the table
+ */
+ public HsqlColumnDescriptor[] getColumns()
+ {
+ return m_columns;
+ }
+
+ public XPropertySet createSdbcxDescriptor( Connection _forConnection )
+ {
+ XTablesSupplier suppTables = UnoRuntime.queryInterface( XTablesSupplier.class, _forConnection.getXConnection() );
+ XDataDescriptorFactory tableDescFac = UnoRuntime.queryInterface( XDataDescriptorFactory.class, suppTables.getTables() );
+ XPropertySet tableDesc = tableDescFac.createDataDescriptor();
+
+ try
+ {
+ tableDesc.setPropertyValue( "Name", getName() );
+ }
+ catch ( Exception e ) { e.printStackTrace( System.err ); }
+
+ XColumnsSupplier suppDescCols = UnoRuntime.queryInterface( XColumnsSupplier.class, tableDesc );
+
+ XNameAccess descColumns = suppDescCols.getColumns();
+ XDataDescriptorFactory columnDescFac = UnoRuntime.queryInterface( XDataDescriptorFactory.class, descColumns );
+
+ HsqlColumnDescriptor[] myColumns = getColumns();
+ for ( int i = 0; i < myColumns.length; ++i )
+ {
+ XPropertySet columnDesc = columnDescFac.createDataDescriptor();
+ try
+ {
+ columnDesc.setPropertyValue( "Name", myColumns[i].getName() );
+ columnDesc.setPropertyValue( "IsNullable", Integer.valueOf( myColumns[i].isRequired() ? ColumnValue.NO_NULLS : ColumnValue.NULLABLE) );
+ columnDesc.setPropertyValue( "TypeName", myColumns[i].getTypeName() );
+ if ( myColumns[i].isPrimaryKey() || myColumns[i].isForeignKey() )
+ // not yet implemented
+ throw new java.lang.UnsupportedOperationException("creating a primary or foreign key via SDBCX not yet implemented" );
+ }
+ catch( com.sun.star.uno.Exception e ) { e.printStackTrace( System.err ); }
+ }
+
+ return tableDesc;
+ }
+}
diff --git a/connectivity/qa/connectivity/tools/QueryDefinition.java b/connectivity/qa/connectivity/tools/QueryDefinition.java
new file mode 100644
index 0000000000..fc3cba3820
--- /dev/null
+++ b/connectivity/qa/connectivity/tools/QueryDefinition.java
@@ -0,0 +1,49 @@
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+package connectivity.tools;
+
+import com.sun.star.beans.UnknownPropertyException;
+import com.sun.star.beans.XPropertySet;
+import com.sun.star.lang.WrappedTargetException;
+
+public class QueryDefinition
+{
+ private final XPropertySet m_queryDef;
+
+ public QueryDefinition( XPropertySet _queryDef )
+ {
+ m_queryDef = _queryDef;
+ }
+
+ /** retrieves the command underlying the query definition
+ *
+ * This method is a mere wrapped around the <code>getPropertyValue( "Command" )</code> call
+ */
+ public final String getCommand() throws WrappedTargetException
+ {
+ String command = null;
+ try {
+ command = (String)m_queryDef.getPropertyValue( "Command" );
+ }
+ catch (UnknownPropertyException e) { }
+
+ return command;
+ }
+
+}
diff --git a/connectivity/qa/connectivity/tools/RowSet.java b/connectivity/qa/connectivity/tools/RowSet.java
new file mode 100644
index 0000000000..22b52156fa
--- /dev/null
+++ b/connectivity/qa/connectivity/tools/RowSet.java
@@ -0,0 +1,288 @@
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+package connectivity.tools;
+
+import com.sun.star.beans.XPropertySet;
+import com.sun.star.container.XIndexAccess;
+import com.sun.star.container.XNameAccess;
+import com.sun.star.io.XInputStream;
+import com.sun.star.lang.XComponent;
+import com.sun.star.lang.XMultiServiceFactory;
+import com.sun.star.sdbc.SQLException;
+import com.sun.star.sdbc.XArray;
+import com.sun.star.sdbc.XBlob;
+import com.sun.star.sdbc.XClob;
+import com.sun.star.sdbc.XRef;
+import com.sun.star.sdbc.XRow;
+import com.sun.star.sdbc.XRowSet;
+import com.sun.star.sdbc.XRowSetListener;
+import com.sun.star.sdbcx.XColumnsSupplier;
+import com.sun.star.uno.UnoRuntime;
+import com.sun.star.util.Date;
+import com.sun.star.util.DateTime;
+import com.sun.star.util.Time;
+
+public class RowSet implements XRowSet, XRow
+{
+ private XRowSet m_rowSet;
+ private XRow m_row;
+
+ public RowSet( XMultiServiceFactory _orb, String _dataSource, int _commandType, String _command )
+ {
+ try
+ {
+ XPropertySet rowSetProps = UnoRuntime.queryInterface( XPropertySet.class, _orb.createInstance( "com.sun.star.sdb.RowSet" ) );
+ rowSetProps.setPropertyValue( "DataSourceName", _dataSource );
+ rowSetProps.setPropertyValue( "CommandType", Integer.valueOf( _commandType ) );
+ rowSetProps.setPropertyValue( "Command", _command );
+
+ m_rowSet = UnoRuntime.queryInterface( XRowSet.class, rowSetProps );
+ m_row = UnoRuntime.queryInterface( XRow.class, rowSetProps );
+ }
+ catch ( Exception e )
+ {
+ throw new java.lang.RuntimeException(e);
+ }
+ }
+
+ // misc
+ public int getColumnCount()
+ {
+ XColumnsSupplier suppCols = UnoRuntime.queryInterface(
+ XColumnsSupplier.class, m_rowSet );
+ XIndexAccess columns = UnoRuntime.queryInterface(
+ XIndexAccess.class, suppCols.getColumns() );
+ return columns.getCount();
+ }
+
+ // XRowSet
+ public void execute() throws SQLException
+ {
+ m_rowSet.execute();
+ }
+
+ public void addRowSetListener( XRowSetListener _listener )
+ {
+ m_rowSet.addRowSetListener( _listener );
+ }
+
+ public void removeRowSetListener( XRowSetListener _listener )
+ {
+ m_rowSet.removeRowSetListener( _listener );
+ }
+
+ public boolean next() throws SQLException
+ {
+ return m_rowSet.next();
+ }
+
+ public boolean isBeforeFirst() throws SQLException
+ {
+ return m_rowSet.isBeforeFirst();
+ }
+
+ public boolean isAfterLast() throws SQLException
+ {
+ return m_rowSet.isAfterLast();
+ }
+
+ public boolean isFirst() throws SQLException
+ {
+ return m_rowSet.isFirst();
+ }
+
+ public boolean isLast() throws SQLException
+ {
+ return m_rowSet.isLast();
+ }
+
+ public void beforeFirst() throws SQLException
+ {
+ m_rowSet.beforeFirst();
+ }
+
+ public void afterLast() throws SQLException
+ {
+ m_rowSet.afterLast();
+ }
+
+ public boolean first() throws SQLException
+ {
+ return m_rowSet.first();
+ }
+
+ public boolean last() throws SQLException
+ {
+ return m_rowSet.last();
+ }
+
+ public int getRow() throws SQLException
+ {
+ return m_rowSet.getRow();
+ }
+
+ public boolean absolute(int i) throws SQLException
+ {
+ return m_rowSet.absolute(i);
+ }
+
+ public boolean relative(int i) throws SQLException
+ {
+ return m_rowSet.relative(i);
+ }
+
+ public boolean previous() throws SQLException
+ {
+ return m_rowSet.previous();
+ }
+
+ public void refreshRow() throws SQLException
+ {
+ m_rowSet.refreshRow();
+ }
+
+ public boolean rowUpdated() throws SQLException
+ {
+ return m_rowSet.rowUpdated();
+ }
+
+ public boolean rowInserted() throws SQLException
+ {
+ return m_rowSet.rowInserted();
+ }
+
+ public boolean rowDeleted() throws SQLException
+ {
+ return m_rowSet.rowDeleted();
+ }
+
+ // XRow
+ public Object getStatement() throws SQLException
+ {
+ return m_rowSet.getStatement();
+ }
+
+ public boolean wasNull() throws SQLException
+ {
+ return m_row.wasNull();
+ }
+
+ public String getString(int i) throws SQLException
+ {
+ return m_row.getString(i);
+ }
+
+ public boolean getBoolean(int i) throws SQLException
+ {
+ return m_row.getBoolean(i);
+ }
+
+ public byte getByte(int i) throws SQLException
+ {
+ return m_row.getByte(i);
+ }
+
+ public short getShort(int i) throws SQLException
+ {
+ return m_row.getShort(i);
+ }
+
+ public int getInt(int i) throws SQLException
+ {
+ return m_row.getInt(i);
+ }
+
+ public long getLong(int i) throws SQLException
+ {
+ return m_row.getLong(i);
+ }
+
+ public float getFloat(int i) throws SQLException
+ {
+ return m_row.getFloat(i);
+ }
+
+ public double getDouble(int i) throws SQLException
+ {
+ return m_row.getDouble(i);
+ }
+
+ public byte[] getBytes(int i) throws SQLException
+ {
+ return m_row.getBytes(i);
+ }
+
+ public Date getDate(int i) throws SQLException
+ {
+ return m_row.getDate(i);
+ }
+
+ public Time getTime(int i) throws SQLException
+ {
+ return m_row.getTime(i);
+ }
+
+ public DateTime getTimestamp(int i) throws SQLException
+ {
+ return m_row.getTimestamp(i);
+ }
+
+ public XInputStream getBinaryStream(int i) throws SQLException
+ {
+ return m_row.getBinaryStream(i);
+ }
+
+ public XInputStream getCharacterStream(int i) throws SQLException
+ {
+ return m_row.getCharacterStream(i);
+ }
+
+ public Object getObject(int i, XNameAccess xNameAccess) throws SQLException
+ {
+ return m_row.getObject(i, xNameAccess);
+ }
+
+ public XRef getRef(int i) throws SQLException
+ {
+ return m_row.getRef(i);
+ }
+
+ public XBlob getBlob(int i) throws SQLException
+ {
+ return m_row.getBlob(i);
+ }
+
+ public XClob getClob(int i) throws SQLException
+ {
+ return m_row.getClob(i);
+ }
+
+ public XArray getArray(int i) throws SQLException
+ {
+ return m_row.getArray(i);
+ }
+
+ public void dispose()
+ {
+ if ( m_rowSet == null )
+ return;
+ XComponent rowSetComp = UnoRuntime.queryInterface( XComponent.class, m_rowSet );
+ rowSetComp.dispose();
+ }
+}
diff --git a/connectivity/qa/connectivity/tools/sdb/Connection.java b/connectivity/qa/connectivity/tools/sdb/Connection.java
new file mode 100644
index 0000000000..d713de3792
--- /dev/null
+++ b/connectivity/qa/connectivity/tools/sdb/Connection.java
@@ -0,0 +1,80 @@
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+package connectivity.tools.sdb;
+
+import com.sun.star.lang.XMultiServiceFactory;
+import com.sun.star.sdb.XSingleSelectQueryComposer;
+import com.sun.star.sdbc.SQLException;
+import com.sun.star.sdbc.XConnection;
+import com.sun.star.sdbc.XPreparedStatement;
+import com.sun.star.sdbc.XStatement;
+import com.sun.star.sdbcx.XTablesSupplier;
+import com.sun.star.uno.Exception;
+import com.sun.star.uno.UnoRuntime;
+import com.sun.star.util.XRefreshable;
+
+/**
+ * is a convenience wrapper around a SDB-level connection object
+ */
+public class Connection
+{
+ private final XConnection m_connection;
+
+ public Connection( final XConnection _connection )
+ {
+ m_connection = _connection;
+ }
+
+ public XConnection getXConnection()
+ {
+ return m_connection;
+ }
+
+ public void refreshTables()
+ {
+ final XTablesSupplier suppTables = UnoRuntime.queryInterface(XTablesSupplier.class, m_connection);
+ final XRefreshable refresh = UnoRuntime.queryInterface( XRefreshable.class, suppTables.getTables() );
+ refresh.refresh();
+ }
+
+ public XSingleSelectQueryComposer createSingleSelectQueryComposer() throws Exception
+ {
+ final XMultiServiceFactory connectionFactory = UnoRuntime.queryInterface( XMultiServiceFactory.class, m_connection );
+ return UnoRuntime.queryInterface(
+ XSingleSelectQueryComposer.class, connectionFactory.createInstance( "com.sun.star.sdb.SingleSelectQueryComposer" ) );
+ }
+
+ public
+ XStatement createStatement() throws SQLException
+ {
+ return m_connection.createStatement();
+ }
+
+ public
+ XPreparedStatement prepareStatement( String _sql ) throws SQLException
+ {
+ return m_connection.prepareStatement( _sql );
+ }
+
+ public
+ void close() throws SQLException
+ {
+ m_connection.close();
+ }
+}
diff --git a/connectivity/qa/scenarios.sce b/connectivity/qa/scenarios.sce
new file mode 100644
index 0000000000..4f366945ef
--- /dev/null
+++ b/connectivity/qa/scenarios.sce
@@ -0,0 +1,21 @@
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# This file incorporates work covered by the following license notice:
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed
+# with this work for additional information regarding copyright
+# ownership. The ASF licenses this file to you under the Apache
+# License, Version 2.0 (the "License"); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.apache.org/licenses/LICENSE-2.0 .
+#
+-o complex.connectivity.DBaseDriverTest
+-o complex.connectivity.HsqlDriverTest
+#-o complex.connectivity.JdbcLongVarCharTest
+-o complex.connectivity.FlatFileAccess
diff --git a/connectivity/registry/README b/connectivity/registry/README
new file mode 100644
index 0000000000..18842b7b0a
--- /dev/null
+++ b/connectivity/registry/README
@@ -0,0 +1,25 @@
+xcu files are made from several sections, the main ones are: Properties and Features
+
+Property: actual setting with its underlying type and its default value
+
+Feature: a boolean that says "let the user change that setting in the Advanced Settings UI"
+
+This is checked by using officecfg/registry/schema/org/openoffice/Office/DataAccess/Drivers.xcs
+and configmgr mechanism
+There are two kinds of properties named "Value":
+- first one is in "Property" groups and has a static oor:type="any" (can take on boolean, int and other types of values)
+- second one is in "Feature" groups and has a static oor:type="boolean" so can take on only boolean values.
+
+Each node in Feature section must have an equivalent in Property section
+Most of the time the node name of both sections should be equal,
+however there are 5 known exceptions (more?):
+- "UseBracketedOuterJoinSyntax" feature => "EnableOuterJoinEscape" property
+- "UseDOSLineEnds" feature => "PreferDosLikeLineEnds" property
+- "UseSQL92NamingConstraints" feature => "EnableSQL92Check" property
+- "AppendTableAliasInSelect" feature => "AppendTableAliasName" property
+- "UseKeywordAsBeforeAlias" feature => "GenerateASBeforeCorrelationName"
+
+See dbaccess/source/ui/dlg/DbAdminImpl.cxx, ODbDataSourceAdministrationHelper constructor, eg:
+m_aIndirectPropTranslator.emplace( <ID>, <property> )
+and dbaccess/source/ui/misc/dsmeta.cxx, lcl_getFeatureMappings() function, eg:
+{ <ID>, <feature> } \ No newline at end of file
diff --git a/connectivity/registry/ado/org/openoffice/Office/DataAccess/Drivers.xcu b/connectivity/registry/ado/org/openoffice/Office/DataAccess/Drivers.xcu
new file mode 100644
index 0000000000..288c23e2e4
--- /dev/null
+++ b/connectivity/registry/ado/org/openoffice/Office/DataAccess/Drivers.xcu
@@ -0,0 +1,369 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ -->
+<oor:component-data oor:name="Drivers" oor:package="org.openoffice.Office.DataAccess" xmlns:install="http://openoffice.org/2004/installation" xmlns:oor="http://openoffice.org/2001/registry" xmlns:xs="http://www.w3.org/2001/XMLSchema">
+<node oor:name="Installed" install:module="ado">
+ <node oor:name="sdbc:ado:*" oor:op="replace">
+ <prop oor:name="Driver">
+ <value>com.sun.star.comp.sdbc.ado.ODriver</value>
+ </prop>
+ <prop oor:name="DriverTypeDisplayName" oor:type="xs:string">
+ <value xml:lang="en-US">ADO</value>
+ </prop>
+ <node oor:name="Properties">
+ <node oor:name="CharSet" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:string">
+ <value></value>
+ </prop>
+ </node>
+ <node oor:name="GeneratedValues" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="EnableSQL92Check" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>false</value>
+ </prop>
+ </node>
+ <node oor:name="AppendTableAliasName" oor:op="replace">
+ <!-- Corresponds to AppendTableAliasInSelect in Features - see connectivity/registry/README -->
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>false</value>
+ </prop>
+ </node>
+ <node oor:name="GenerateASBeforeCorrelationName" oor:op="replace">
+ <!-- Corresponds to UseKeywordAsBeforeAlias in Features - see connectivity/registry/README -->
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>false</value>
+ </prop>
+ </node>
+ <node oor:name="PreferDosLikeLineEnds" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>false</value>
+ </prop>
+ </node>
+ <node oor:name="IgnoreDriverPrivileges" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="DisplayVersionColumns" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="UseCatalogInSelect" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="UseSchemaInSelect" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="UseIndexDirectionKeyword" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="BooleanComparisonMode" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:int">
+ <value>0</value>
+ </prop>
+ </node>
+ <node oor:name="FormsCheckRequiredFields" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="EscapeDateTime" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="PrimaryKeySupport" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean"/>
+ </node>
+ <node oor:name="RespectDriverResultSetType" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>false</value>
+ </prop>
+ </node>
+ </node>
+ <node oor:name="Features">
+ <node oor:name="GeneratedValues" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="UseSQL92NamingConstraints" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="AppendTableAliasInSelect" oor:op="replace">
+ <!-- Corresponds to AppendTableAliasName in Properties - see connectivity/registry/README -->
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="UseKeywordAsBeforeAlias" oor:op="replace">
+ <!-- Corresponds to GenerateASBeforeCorrelationName in Properties - see connectivity/registry/README -->
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="UseBracketedOuterJoinSyntax" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="IgnoreDriverPrivileges" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="DisplayVersionColumns" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="UseCatalogInSelect" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="UseSchemaInSelect" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="UseIndexDirectionKeyword" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="UseDOSLineEnds" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="BooleanComparisonMode" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="FormsCheckRequiredFields" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="EscapeDateTime" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="PrimaryKeySupport" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="RespectDriverResultSetType" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ </node>
+ <node oor:name="MetaData">
+ <node oor:name="SupportsTableCreation" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="SupportsBrowsing" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="Authentication" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:string">
+ <value>UserPassword</value>
+ </prop>
+ </node>
+ <node oor:name="SupportsColumnDescription" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ </node>
+ </node>
+ <node oor:name="sdbc:ado:access:PROVIDER=Microsoft.Jet.OLEDB.4.0;DATA SOURCE=*" oor:op="replace">
+ <prop oor:name="Driver">
+ <value>com.sun.star.comp.sdbc.ado.ODriver</value>
+ </prop>
+ <prop oor:name="DriverTypeDisplayName" oor:type="xs:string">
+ <value xml:lang="en-US">Microsoft Access</value>
+ </prop>
+ <node oor:name="Properties">
+ <node oor:name="CharSet" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:string">
+ <value></value>
+ </prop>
+ </node>
+ <node oor:name="BooleanComparisonMode" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:int">
+ <value>3</value>
+ </prop>
+ </node>
+ <node oor:name="ColumnAliasInOrderBy" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>false</value>
+ </prop>
+ </node>
+ <node oor:name="TypeInfoSettings" oor:op="replace">
+ <prop oor:name="Value" oor:type="oor:string-list">
+ <value oor:separator=",">Column(2) = 16,Column(3) = 1</value>
+ </prop>
+ </node>
+ <node oor:name="EnableSQL92Check" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>false</value>
+ </prop>
+ </node>
+ <node oor:name="AppendTableAliasName" oor:op="replace">
+ <!-- Corresponds to AppendTableAliasInSelect in Features - see connectivity/registry/README -->
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>false</value>
+ </prop>
+ </node>
+ <node oor:name="EnableOuterJoinEscape" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="PreferDosLikeLineEnds" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>false</value>
+ </prop>
+ </node>
+ <node oor:name="FormsCheckRequiredFields" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="EscapeDateTime" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ </node>
+ <node oor:name="Features">
+ <node oor:name="UseSQL92NamingConstraints" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="AppendTableAliasInSelect" oor:op="replace">
+ <!-- Corresponds to AppendTableAliasName in Properties - see connectivity/registry/README -->
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="UseBracketedOuterJoinSyntax" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="UseDOSLineEnds" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="BooleanComparisonMode" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="FormsCheckRequiredFields" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="EscapeDateTime" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ </node>
+ <node oor:name="MetaData">
+ <node oor:name="ColumnAliasInOrderBy" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>false</value>
+ </prop>
+ </node>
+ <node oor:name="SupportsTableCreation" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="SupportsBrowsing" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="FileSystemBased" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="MediaType" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:string">
+ <value>application/msaccess</value>
+ </prop>
+ </node>
+ <node oor:name="Extension" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:string">
+ <value>mdb</value>
+ </prop>
+ </node>
+ <node oor:name="SupportsColumnDescription" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ </node>
+ </node>
+ <node oor:name="sdbc:ado:access:Provider=Microsoft.ACE.OLEDB.12.0;DATA SOURCE=*" oor:op="replace">
+ <prop oor:name="ParentURLPattern">
+ <value>sdbc:ado:access:PROVIDER=Microsoft.Jet.OLEDB.4.0;DATA SOURCE=*</value>
+ </prop>
+ <prop oor:name="DriverTypeDisplayName" oor:type="xs:string">
+ <value xml:lang="en-US">Microsoft Access 2007</value>
+ </prop>
+ <node oor:name="MetaData">
+ <node oor:name="Extension" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:string">
+ <value></value>
+ </prop>
+ </node>
+ </node>
+ </node>
+ </node>
+</oor:component-data>
diff --git a/connectivity/registry/calc/org/openoffice/Office/DataAccess/Drivers.xcu b/connectivity/registry/calc/org/openoffice/Office/DataAccess/Drivers.xcu
new file mode 100644
index 0000000000..8fe901b0fe
--- /dev/null
+++ b/connectivity/registry/calc/org/openoffice/Office/DataAccess/Drivers.xcu
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ -->
+<oor:component-data oor:name="Drivers" oor:package="org.openoffice.Office.DataAccess" xmlns:install="http://openoffice.org/2004/installation" xmlns:oor="http://openoffice.org/2001/registry" xmlns:xs="http://www.w3.org/2001/XMLSchema">
+ <node oor:name="Installed" install:module="calc">
+ <node oor:name="sdbc:calc:*" oor:op="replace">
+ <prop oor:name="Driver">
+ <value>com.sun.star.comp.sdbc.calc.ODriver</value>
+ </prop>
+ <prop oor:name="DriverTypeDisplayName" oor:type="xs:string">
+ <value xml:lang="en-US">Spreadsheet</value>
+ </prop>
+ <node oor:name="Properties">
+ <node oor:name="EscapeDateTime" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ </node>
+ <node oor:name="Features">
+ <node oor:name="EscapeDateTime" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ </node>
+ <node oor:name="MetaData">
+ <node oor:name="SupportsBrowsing" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="FileSystemBased" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="MediaType" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:string">
+ <value>application/vnd.oasis.opendocument.spreadsheet</value>
+ </prop>
+ </node>
+ </node>
+ </node>
+ </node>
+</oor:component-data>
diff --git a/connectivity/registry/dbase/org/openoffice/Office/DataAccess/Drivers.xcu b/connectivity/registry/dbase/org/openoffice/Office/DataAccess/Drivers.xcu
new file mode 100644
index 0000000000..2de29af9d4
--- /dev/null
+++ b/connectivity/registry/dbase/org/openoffice/Office/DataAccess/Drivers.xcu
@@ -0,0 +1,101 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ -->
+<oor:component-data oor:name="Drivers" oor:package="org.openoffice.Office.DataAccess" xmlns:install="http://openoffice.org/2004/installation" xmlns:oor="http://openoffice.org/2001/registry" xmlns:xs="http://www.w3.org/2001/XMLSchema">
+ <node oor:name="Installed" install:module="dbase">
+ <node oor:name="sdbc:dbase:*" oor:op="replace">
+ <prop oor:name="Driver">
+ <value>com.sun.star.comp.sdbc.dbase.ODriver</value>
+ </prop>
+ <prop oor:name="DriverTypeDisplayName" oor:type="xs:string">
+ <value xml:lang="en-US">dBASE</value>
+ </prop>
+ <node oor:name="Properties">
+ <node oor:name="CharSet" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:string">
+ <value></value>
+ </prop>
+ </node>
+ <node oor:name="ShowDeleted" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>false</value>
+ </prop>
+ </node>
+ <node oor:name="EnableSQL92Check" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>false</value>
+ </prop>
+ </node>
+ <node oor:name="AddIndexAppendix" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>false</value>
+ </prop>
+ </node>
+ <node oor:name="PreferDosLikeLineEnds" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>false</value>
+ </prop>
+ </node>
+ <node oor:name="EscapeDateTime" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ </node>
+ <node oor:name="Features">
+ <node oor:name="UseSQL92NamingConstraints" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="UseDOSLineEnds" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="EscapeDateTime" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ </node>
+ <node oor:name="MetaData">
+ <node oor:name="SupportsTableCreation" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="SupportsBrowsing" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="FileSystemBased" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="MediaType" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:string">
+ <value>application/dbase</value>
+ </prop>
+ </node>
+ </node>
+ </node>
+ </node>
+</oor:component-data>
diff --git a/connectivity/registry/evoab2/org/openoffice/Office/DataAccess/Drivers.xcu b/connectivity/registry/evoab2/org/openoffice/Office/DataAccess/Drivers.xcu
new file mode 100644
index 0000000000..152d29e8fe
--- /dev/null
+++ b/connectivity/registry/evoab2/org/openoffice/Office/DataAccess/Drivers.xcu
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ -->
+<oor:component-data oor:name="Drivers" oor:package="org.openoffice.Office.DataAccess" xmlns:install="http://openoffice.org/2004/installation" xmlns:oor="http://openoffice.org/2001/registry" xmlns:xs="http://www.w3.org/2001/XMLSchema">
+ <node oor:name="Installed" install:module="evoab2">
+ <node oor:name="sdbc:address:evolution:local" oor:op="replace">
+ <prop oor:name="Driver">
+ <value>com.sun.star.comp.sdbc.evoab.OEvoabDriver</value>
+ </prop>
+ <prop oor:name="DriverTypeDisplayName" oor:type="xs:string">
+ <value xml:lang="en-US">Evolution Local</value>
+ </prop>
+ <node oor:name="Properties">
+ <node oor:name="EscapeDateTime" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ </node>
+ <node oor:name="Features">
+ <node oor:name="EscapeDateTime" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ </node>
+ </node>
+ <node oor:name="sdbc:address:evolution:ldap" oor:op="replace">
+ <prop oor:name="Driver">
+ <value>com.sun.star.comp.sdbc.evoab.OEvoabDriver</value>
+ </prop>
+ <prop oor:name="DriverTypeDisplayName" oor:type="xs:string">
+ <value xml:lang="en-US">Evolution LDAP</value>
+ </prop>
+ <node oor:name="Properties">
+ <node oor:name="EscapeDateTime" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ </node>
+ <node oor:name="Features">
+ <node oor:name="EscapeDateTime" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ </node>
+ </node>
+ <node oor:name="sdbc:address:evolution:groupwise" oor:op="replace">
+ <prop oor:name="Driver">
+ <value>com.sun.star.comp.sdbc.evoab.OEvoabDriver</value>
+ </prop>
+ <prop oor:name="DriverTypeDisplayName" oor:type="xs:string">
+ <value xml:lang="en-US">Groupwise</value>
+ </prop>
+ <node oor:name="Properties">
+ <node oor:name="EscapeDateTime" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ </node>
+ <node oor:name="Features">
+ <node oor:name="EscapeDateTime" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ </node>
+ </node>
+ </node>
+</oor:component-data>
diff --git a/connectivity/registry/firebird/org/openoffice/Office/DataAccess/Drivers.xcu b/connectivity/registry/firebird/org/openoffice/Office/DataAccess/Drivers.xcu
new file mode 100644
index 0000000000..11b214855b
--- /dev/null
+++ b/connectivity/registry/firebird/org/openoffice/Office/DataAccess/Drivers.xcu
@@ -0,0 +1,135 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--***********************************************************************
+ *
+ * Effective License of whole file:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 3, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011:
+ *
+ * The Contents of this file are made available subject to the terms of
+ * the GNU Lesser General Public License Version 3
+ *
+ * Copyright: 2008 by Sun Microsystems, Inc.
+ *
+ * All parts contributed on or after August 2011:
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ ************************************************************************ -->
+<oor:component-data oor:name="Drivers" oor:package="org.openoffice.Office.DataAccess" xmlns:install="http://openoffice.org/2004/installation" xmlns:oor="http://openoffice.org/2001/registry" xmlns:xs="http://www.w3.org/2001/XMLSchema">
+ <node oor:name="Installed" install:module="firebird">
+ <!-- Firebird EMBEDDED Driver -->
+ <node oor:name="sdbc:embedded:firebird" oor:op="replace">
+ <prop oor:name="Driver">
+ <value>com.sun.star.comp.sdbc.firebird.Driver</value>
+ </prop>
+ <prop oor:name="DriverTypeDisplayName" oor:type="xs:string">
+ <value xml:lang="en-US">Firebird Embedded</value>
+ </prop>
+ <node oor:name="Properties">
+ <!-- Don't use ODBC syntax for date&time literals and (full) outer joins,
+ as PostgreSQL does not support it,
+ but supports the _interior_ of these escapes just fine. -->
+ <node oor:name="EscapeDateTime" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>false</value>
+ </prop>
+ </node>
+ <!-- Confusingly, this corresponds to "UseBracketedOuterJoinSyntax" in the Features -->
+ <node oor:name="EnableOuterJoinEscape" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>false</value>
+ </prop>
+ </node>
+ <node oor:name="UseCatalog" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>false</value>
+ </prop>
+ </node>
+ <node oor:name="ParameterNameSubstitution" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="BooleanComparisonMode" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:int">
+ <value>2</value>
+ </prop>
+ </node>
+ </node><!--Properties-->
+ <node oor:name="Features">
+ </node><!--Features-->
+ <node oor:name="MetaData">
+ </node>
+ </node>
+ <!-- Firebird EXTERNAL Driver -->
+ <node oor:name="sdbc:firebird:*" oor:op="replace">
+ <prop oor:name="Driver">
+ <value>com.sun.star.comp.sdbc.firebird.Driver</value>
+ </prop>
+ <prop oor:name="DriverTypeDisplayName" oor:type="xs:string">
+ <value xml:lang="en-US">Firebird External</value>
+ </prop>
+ <node oor:name="Properties">
+ <!-- Don't use ODBC syntax for date&time literals and (full) outer joins,
+ as PostgreSQL does not support it,
+ but supports the _interior_ of these escapes just fine. -->
+ <node oor:name="EscapeDateTime" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>false</value>
+ </prop>
+ </node>
+ <!-- Confusingly, this corresponds to "UseBracketedOuterJoinSyntax" in the Features -->
+ <node oor:name="EnableOuterJoinEscape" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>false</value>
+ </prop>
+ </node>
+ <node oor:name="UseCatalog" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>false</value>
+ </prop>
+ </node>
+ <node oor:name="ParameterNameSubstitution" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ </node>
+ <node oor:name="Features">
+ </node>
+ <node oor:name="MetaData">
+ <node oor:name="SupportsBrowsing" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="SupportsDBCreation" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="Authentication" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:string">
+ <value>UserPassword</value>
+ </prop>
+ </node>
+ </node>
+ </node>
+ </node>
+</oor:component-data>
diff --git a/connectivity/registry/flat/org/openoffice/Office/DataAccess/Drivers.xcu b/connectivity/registry/flat/org/openoffice/Office/DataAccess/Drivers.xcu
new file mode 100644
index 0000000000..a0f69df291
--- /dev/null
+++ b/connectivity/registry/flat/org/openoffice/Office/DataAccess/Drivers.xcu
@@ -0,0 +1,116 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ -->
+<oor:component-data oor:name="Drivers" oor:package="org.openoffice.Office.DataAccess" xmlns:install="http://openoffice.org/2004/installation" xmlns:oor="http://openoffice.org/2001/registry" xmlns:xs="http://www.w3.org/2001/XMLSchema">
+ <node oor:name="Installed" install:module="flat">
+ <node oor:name="sdbc:flat:*" oor:op="replace">
+ <prop oor:name="Driver">
+ <value>com.sun.star.comp.sdbc.flat.ODriver</value>
+ </prop>
+ <prop oor:name="DriverTypeDisplayName" oor:type="xs:string">
+ <value xml:lang="en-US">Text/CSV</value>
+ </prop>
+ <node oor:name="Properties">
+ <node oor:name="CharSet" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:string">
+ <value></value>
+ </prop>
+ </node>
+ <node oor:name="Extension" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:string">
+ <value></value>
+ </prop>
+ </node>
+ <node oor:name="HeaderLine" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="FieldDelimiter" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:string">
+ <value>,</value>
+ </prop>
+ </node>
+ <node oor:name="StringDelimiter" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:string">
+ <value>"</value>
+ </prop>
+ </node>
+ <node oor:name="DecimalDelimiter" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:string">
+ <value>.</value>
+ </prop>
+ </node>
+ <node oor:name="ThousandDelimiter" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:string">
+ <value></value>
+ </prop>
+ </node>
+ <node oor:name="EnableSQL92Check" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>false</value>
+ </prop>
+ </node>
+ <node oor:name="MaxRowScan" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:int">
+ <value>100</value>
+ </prop>
+ </node>
+ <node oor:name="EscapeDateTime" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ </node>
+ <node oor:name="Features">
+ <node oor:name="MaxRowScan" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="UseSQL92NamingConstraints" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="EscapeDateTime" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ </node>
+ <node oor:name="MetaData">
+ <node oor:name="SupportsBrowsing" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="FileSystemBased" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="MediaType" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:string">
+ <value>text/csv</value>
+ </prop>
+ </node>
+ </node>
+ </node>
+ </node>
+</oor:component-data>
diff --git a/connectivity/registry/hsqldb/org/openoffice/Office/DataAccess/Drivers.xcu b/connectivity/registry/hsqldb/org/openoffice/Office/DataAccess/Drivers.xcu
new file mode 100644
index 0000000000..c224b51b16
--- /dev/null
+++ b/connectivity/registry/hsqldb/org/openoffice/Office/DataAccess/Drivers.xcu
@@ -0,0 +1,103 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+-->
+<oor:component-data oor:name="Drivers" oor:package="org.openoffice.Office.DataAccess" xmlns:install="http://openoffice.org/2004/installation" xmlns:oor="http://openoffice.org/2001/registry" xmlns:xs="http://www.w3.org/2001/XMLSchema">
+ <node oor:name="Installed" install:module="hsqldb">
+ <node oor:name="sdbc:embedded:hsqldb" oor:op="replace">
+ <prop oor:name="Driver">
+ <value>com.sun.star.sdbcx.comp.hsqldb.Driver</value>
+ </prop>
+ <prop oor:name="DriverTypeDisplayName" oor:type="xs:string">
+ <value xml:lang="en-US">HSQLDB Embedded</value>
+ </prop>
+ <node oor:name="Properties">
+ <node oor:name="PreferDosLikeLineEnds" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>false</value>
+ </prop>
+ </node>
+ <node oor:name="FormsCheckRequiredFields" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="EscapeDateTime" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="AddIndexAppendix" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="GenerateASBeforeCorrelationName" oor:op="replace">
+ <!-- Corresponds to UseKeywordAsBeforeAlias in Features - see connectivity/registry/README -->
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ </node>
+ <node oor:name="Features">
+ <node oor:name="UseDOSLineEnds" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="FormsCheckRequiredFields" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="EscapeDateTime" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="AddIndexAppendix" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="UseKeywordAsBeforeAlias" oor:op="replace">
+ <!-- Corresponds to GenerateASBeforeCorrelationName in Properties - see connectivity/registry/README -->
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ </node>
+ <node oor:name="MetaData">
+ <node oor:name="SupportsTableCreation" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="UseJava" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="AutoIncrementIsPrimaryKey" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ </node>
+ </node>
+ </node>
+</oor:component-data>
diff --git a/connectivity/registry/jdbc/org/openoffice/Office/DataAccess/Drivers.xcu b/connectivity/registry/jdbc/org/openoffice/Office/DataAccess/Drivers.xcu
new file mode 100644
index 0000000000..698393b108
--- /dev/null
+++ b/connectivity/registry/jdbc/org/openoffice/Office/DataAccess/Drivers.xcu
@@ -0,0 +1,297 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ -->
+<oor:component-data oor:name="Drivers" oor:package="org.openoffice.Office.DataAccess" xmlns:install="http://openoffice.org/2004/installation" xmlns:oor="http://openoffice.org/2001/registry" xmlns:xs="http://www.w3.org/2001/XMLSchema">
+ <node oor:name="Installed" install:module="jdbc">
+ <node oor:name="jdbc:*" oor:op="replace">
+ <prop oor:name="Driver">
+ <value>com.sun.star.comp.sdbc.JDBCDriver</value>
+ </prop>
+ <prop oor:name="DriverTypeDisplayName" oor:type="xs:string">
+ <value xml:lang="en-US">JDBC</value>
+ </prop>
+ <node oor:name="Properties">
+ <node oor:name="JavaDriverClass" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:string">
+ <value></value>
+ </prop>
+ </node>
+ <node oor:name="JavaDriverClassPath" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:string">
+ <value></value>
+ </prop>
+ </node>
+ <node oor:name="AutoIncrementCreation" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:string">
+ <value></value>
+ </prop>
+ </node>
+ <node oor:name="AutoRetrievingStatement" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:string">
+ <value></value>
+ </prop>
+ </node>
+ <node oor:name="IsAutoRetrievingEnabled" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>false</value>
+ </prop>
+ </node>
+ <node oor:name="AddIndexAppendix" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="GeneratedValues" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="EnableSQL92Check" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>false</value>
+ </prop>
+ </node>
+ <node oor:name="AppendTableAliasName" oor:op="replace">
+ <!-- Corresponds to AppendTableAliasInSelect in Features - see connectivity/registry/README -->
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>false</value>
+ </prop>
+ </node>
+ <node oor:name="GenerateASBeforeCorrelationName" oor:op="replace">
+ <!-- Corresponds to UseKeywordAsBeforeAlias in Features - see connectivity/registry/README -->
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>false</value>
+ </prop>
+ </node>
+ <node oor:name="EnableOuterJoinEscape" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="IgnoreDriverPrivileges" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="ParameterNameSubstitution" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="DisplayVersionColumns" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="UseCatalogInSelect" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="UseSchemaInSelect" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="UseIndexDirectionKeyword" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="PreferDosLikeLineEnds" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>false</value>
+ </prop>
+ </node>
+ <node oor:name="BooleanComparisonMode" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:int">
+ <value>0</value>
+ </prop>
+ </node>
+ <node oor:name="FormsCheckRequiredFields" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="EscapeDateTime" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="PrimaryKeySupport" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean"/>
+ </node>
+ <node oor:name="RespectDriverResultSetType" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>false</value>
+ </prop>
+ </node>
+ </node>
+ <node oor:name="Features">
+ <node oor:name="GeneratedValues" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="UseSQL92NamingConstraints" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="AppendTableAliasInSelect" oor:op="replace">
+ <!-- Corresponds to AppendTableAliasName in Properties - see connectivity/registry/README -->
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="UseKeywordAsBeforeAlias" oor:op="replace">
+ <!-- Corresponds to GenerateASBeforeCorrelationName in Properties - see connectivity/registry/README -->
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="UseBracketedOuterJoinSyntax" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="IgnoreDriverPrivileges" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="ParameterNameSubstitution" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="DisplayVersionColumns" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="UseCatalogInSelect" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="UseSchemaInSelect" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="UseIndexDirectionKeyword" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="UseDOSLineEnds" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="BooleanComparisonMode" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="FormsCheckRequiredFields" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="EscapeDateTime" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="PrimaryKeySupport" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="RespectDriverResultSetType" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ </node>
+ <node oor:name="MetaData">
+ <node oor:name="SupportsTableCreation" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="UseJava" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="Authentication" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:string">
+ <value>UserPassword</value>
+ </prop>
+ </node>
+ </node>
+ </node>
+ <node oor:name="jdbc:oracle:thin:*" oor:op="replace">
+ <prop oor:name="ParentURLPattern">
+ <value>jdbc:*</value>
+ </prop>
+ <prop oor:name="DriverTypeDisplayName" oor:type="xs:string">
+ <value xml:lang="en-US">Oracle JDBC</value>
+ </prop>
+ <node oor:name="Properties">
+ <node oor:name="IgnoreCurrency" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="TypeInfoSettings" oor:op="replace">
+ <prop oor:name="Value" oor:type="oor:string-list">
+ <value oor:separator=",">Column(2) = -5,Column(6) = PRECISION,Column(2) = -4,Column(6) = PRECISION,Column(2) = -3,Column(6) = PRECISION,Column(2) = -2,Column(6) = PRECISION,Column(2) = -1,Column(6) = PRECISION,Column(2) = -1,Column(6) = PRECISION,Column(2) = 2,Column(6) = PRECISION,Column(2) = 12,Column(6) = PRECISION</value>
+ </prop>
+ </node>
+ <node oor:name="JavaDriverClass" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:string">
+ <value>oracle.jdbc.driver.OracleDriver</value>
+ </prop>
+ </node>
+ <node oor:name="AddIndexAppendix" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>false</value>
+ </prop>
+ </node>
+ </node>
+ <node oor:name="Features">
+ <node oor:name="IgnoreCurrency" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ </node>
+ <node oor:name="MetaData">
+ <node oor:name="Authentication" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:string">
+ <value>UserPassword</value>
+ </prop>
+ </node>
+ </node>
+ </node>
+ </node>
+</oor:component-data>
diff --git a/connectivity/registry/macab/org/openoffice/Office/DataAccess/Drivers.xcu b/connectivity/registry/macab/org/openoffice/Office/DataAccess/Drivers.xcu
new file mode 100644
index 0000000000..027b648253
--- /dev/null
+++ b/connectivity/registry/macab/org/openoffice/Office/DataAccess/Drivers.xcu
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ -->
+<oor:component-data oor:name="Drivers" oor:package="org.openoffice.Office.DataAccess" xmlns:install="http://openoffice.org/2004/installation" xmlns:oor="http://openoffice.org/2001/registry" xmlns:xs="http://www.w3.org/2001/XMLSchema">
+ <node oor:name="Installed" install:module="macab">
+ <node oor:name="sdbc:address:macab" oor:op="replace">
+ <prop oor:name="Driver">
+ <value>com.sun.star.comp.sdbc.macab.Driver</value>
+ </prop>
+ <prop oor:name="DriverTypeDisplayName" oor:type="xs:string">
+ <value xml:lang="en-US">macOS Address Book</value>
+ </prop>
+ <node oor:name="Properties">
+ <node oor:name="EscapeDateTime" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ </node>
+ <node oor:name="Features">
+ <node oor:name="EscapeDateTime" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ </node>
+ </node>
+ </node>
+</oor:component-data>
diff --git a/connectivity/registry/mysql_jdbc/org/openoffice/Office/DataAccess/Drivers.xcu b/connectivity/registry/mysql_jdbc/org/openoffice/Office/DataAccess/Drivers.xcu
new file mode 100644
index 0000000000..38be69b48a
--- /dev/null
+++ b/connectivity/registry/mysql_jdbc/org/openoffice/Office/DataAccess/Drivers.xcu
@@ -0,0 +1,180 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ -->
+<oor:component-data oor:name="Drivers" oor:package="org.openoffice.Office.DataAccess" xmlns:install="http://openoffice.org/2004/installation" xmlns:oor="http://openoffice.org/2001/registry" xmlns:xs="http://www.w3.org/2001/XMLSchema">
+ <node oor:name="Installed" install:module="mysql_jdbc">
+ <node oor:name="sdbc:mysql:jdbc:*" oor:op="replace">
+ <prop oor:name="Driver">
+ <value>org.openoffice.comp.drivers.MySQL.Driver</value>
+ </prop>
+ <prop oor:name="DriverTypeDisplayName" oor:type="xs:string">
+ <value xml:lang="en-US">MySQL (JDBC)</value>
+ </prop>
+ <node oor:name="Properties">
+ <node oor:name="CharSet" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:string">
+ <value></value>
+ </prop>
+ </node>
+ <node oor:name="JavaDriverClass" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:string">
+ <value>com.mysql.jdbc.Driver</value>
+ </prop>
+ </node>
+ <node oor:name="AddIndexAppendix" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="ParameterNameSubstitution" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ </node>
+ <node oor:name="Features">
+ <node oor:name="UseKeywordAsBeforeAlias" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="IgnoreDriverPrivileges" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="DisplayVersionColumns" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="UseDOSLineEnds" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="BooleanComparisonMode" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="FormsCheckRequiredFields" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ </node>
+ <node oor:name="MetaData">
+ <node oor:name="SupportsTableCreation" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="UseJava" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="Authentication" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:string">
+ <value>UserPassword</value>
+ </prop>
+ </node>
+ <node oor:name="SupportsColumnDescription" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ </node>
+ </node>
+ <node oor:name="sdbc:mysql:odbc:*" oor:op="replace">
+ <prop oor:name="Driver">
+ <value>org.openoffice.comp.drivers.MySQL.Driver</value>
+ </prop>
+ <prop oor:name="DriverTypeDisplayName" oor:type="xs:string">
+ <value xml:lang="en-US">MySQL (ODBC)</value>
+ </prop>
+ <node oor:name="Properties">
+ <node oor:name="CharSet" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:string">
+ <value></value>
+ </prop>
+ </node>
+ <node oor:name="AddIndexAppendix" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="ParameterNameSubstitution" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ </node>
+ <node oor:name="Features">
+ <node oor:name="UseKeywordAsBeforeAlias" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="IgnoreDriverPrivileges" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="DisplayVersionColumns" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="UseDOSLineEnds" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="BooleanComparisonMode" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="FormsCheckRequiredFields" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ </node>
+ <node oor:name="MetaData">
+ <node oor:name="SupportsTableCreation" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="SupportsBrowsing" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="Authentication" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:string">
+ <value>UserPassword</value>
+ </prop>
+ </node>
+ </node>
+ </node>
+ </node>
+</oor:component-data>
diff --git a/connectivity/registry/mysqlc/org/openoffice/Office/DataAccess/Drivers.xcu b/connectivity/registry/mysqlc/org/openoffice/Office/DataAccess/Drivers.xcu
new file mode 100644
index 0000000000..13ed25f95e
--- /dev/null
+++ b/connectivity/registry/mysqlc/org/openoffice/Office/DataAccess/Drivers.xcu
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ -->
+<oor:component-data oor:name="Drivers" oor:package="org.openoffice.Office.DataAccess" xmlns:install="http://openoffice.org/2004/installation" xmlns:oor="http://openoffice.org/2001/registry" xmlns:xs="http://www.w3.org/2001/XMLSchema">
+ <node oor:name="Installed" install:module="mysqlc">
+ <node oor:name="sdbc:mysql:mysqlc:*" oor:op="replace">
+ <prop oor:name="Driver">
+ <value>com.sun.star.comp.sdbc.mysqlc.MysqlCDriver</value>
+ </prop>
+ <prop oor:name="DriverTypeDisplayName" oor:type="xs:string">
+ <value xml:lang="en-US">MySQL/MariaDB Connector</value>
+ </prop>
+ <node oor:name="Properties">
+ <node oor:name="CharSet" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:string">
+ <value></value>
+ </prop>
+ </node>
+ <node oor:name="LocalSocket" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:string">
+ <value></value>
+ </prop>
+ </node>
+ <node oor:name="NamedPipe" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:string">
+ <value></value>
+ </prop>
+ </node>
+ <node oor:name="AddIndexAppendix" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="GenerateASBeforeCorrelationName" oor:op="replace">
+ <!-- Corresponds to UseKeywordAsBeforeAlias in Features - see connectivity/registry/README -->
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="IgnoreDriverPrivileges" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="ParameterNameSubstitution" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="DisplayVersionColumns" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="PreferDosLikeLineEnds" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="BooleanComparisonMode" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:int">
+ <value>0</value>
+ </prop>
+ </node>
+ <node oor:name="FormsCheckRequiredFields" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ </node>
+ <node oor:name="Features">
+ <node oor:name="UseKeywordAsBeforeAlias" oor:op="replace">
+ <!-- Corresponds to GenerateASBeforeCorrelationName in Properties - see connectivity/registry/README -->
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="IgnoreDriverPrivileges" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="DisplayVersionColumns" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="UseDOSLineEnds" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="BooleanComparisonMode" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="FormsCheckRequiredFields" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ </node>
+ <node oor:name="MetaData">
+ <node oor:name="SupportsTableCreation" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="Authentication" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:string">
+ <value>UserPassword</value>
+ </prop>
+ </node>
+ <node oor:name="SupportsColumnDescription" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ </node>
+ </node>
+ </node>
+</oor:component-data>
diff --git a/connectivity/registry/odbc/org/openoffice/Office/DataAccess/Drivers.xcu b/connectivity/registry/odbc/org/openoffice/Office/DataAccess/Drivers.xcu
new file mode 100644
index 0000000000..f2dbd91c8e
--- /dev/null
+++ b/connectivity/registry/odbc/org/openoffice/Office/DataAccess/Drivers.xcu
@@ -0,0 +1,261 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ -->
+<oor:component-data oor:name="Drivers" oor:package="org.openoffice.Office.DataAccess" xmlns:install="http://openoffice.org/2004/installation" xmlns:oor="http://openoffice.org/2001/registry" xmlns:xs="http://www.w3.org/2001/XMLSchema">
+ <node oor:name="Installed" install:module="odbc">
+ <node oor:name="sdbc:odbc:*" oor:op="replace">
+ <prop oor:name="Driver">
+ <value>com.sun.star.comp.sdbc.ODBCDriver</value>
+ </prop>
+ <prop oor:name="DriverTypeDisplayName" oor:type="xs:string">
+ <value xml:lang="en-US">ODBC</value>
+ </prop>
+ <node oor:name="Properties">
+ <node oor:name="CharSet" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:string">
+ <value></value>
+ </prop>
+ </node>
+ <node oor:name="SystemDriverSettings" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:string">
+ <value></value>
+ </prop>
+ </node>
+ <node oor:name="UseCatalog" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>false</value>
+ </prop>
+ </node>
+ <node oor:name="AutoIncrementCreation" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:string">
+ <value></value>
+ </prop>
+ </node>
+ <node oor:name="AutoRetrievingStatement" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:string">
+ <value></value>
+ </prop>
+ </node>
+ <node oor:name="IsAutoRetrievingEnabled" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>false</value>
+ </prop>
+ </node>
+ <node oor:name="AddIndexAppendix" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="GeneratedValues" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="EnableSQL92Check" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <!-- must be synchronized with ODatabaseModelImpl::getDefaultDataSourceSettings -->
+ <value>false</value>
+ </prop>
+ </node>
+ <node oor:name="AppendTableAliasName" oor:op="replace">
+ <!-- Corresponds to AppendTableAliasInSelect in Features - see connectivity/registry/README -->
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>false</value>
+ </prop>
+ </node>
+ <node oor:name="GenerateASBeforeCorrelationName" oor:op="replace">
+ <!-- Corresponds to UseKeywordAsBeforeAlias in Features - see connectivity/registry/README -->
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>false</value>
+ </prop>
+ </node>
+ <node oor:name="EnableOuterJoinEscape" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="IgnoreDriverPrivileges" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="ParameterNameSubstitution" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="DisplayVersionColumns" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="UseCatalogInSelect" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="UseSchemaInSelect" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="UseIndexDirectionKeyword" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="PreferDosLikeLineEnds" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <!-- must be synchronized with ODatabaseModelImpl::getDefaultDataSourceSettings -->
+ <value>false</value>
+ </prop>
+ </node>
+ <node oor:name="BooleanComparisonMode" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:int">
+ <value>0</value>
+ </prop>
+ </node>
+ <node oor:name="FormsCheckRequiredFields" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="EscapeDateTime" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="PrimaryKeySupport" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean"/>
+ </node>
+ <node oor:name="RespectDriverResultSetType" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <!-- must be synchronized with ODatabaseModelImpl::getDefaultDataSourceSettings -->
+ <value>false</value>
+ </prop>
+ </node>
+ </node>
+ <node oor:name="Features">
+ <node oor:name="GeneratedValues" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="UseSQL92NamingConstraints" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="AppendTableAliasInSelect" oor:op="replace">
+ <!-- Corresponds to AppendTableAliasName in Properties - see connectivity/registry/README -->
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="UseKeywordAsBeforeAlias" oor:op="replace">
+ <!-- Corresponds to GenerateASBeforeCorrelationName in Properties - see connectivity/registry/README -->
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="UseBracketedOuterJoinSyntax" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="IgnoreDriverPrivileges" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="ParameterNameSubstitution" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="DisplayVersionColumns" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="UseCatalogInSelect" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="UseSchemaInSelect" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="UseIndexDirectionKeyword" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="UseDOSLineEnds" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="BooleanComparisonMode" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="FormsCheckRequiredFields" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="EscapeDateTime" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="PrimaryKeySupport" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="RespectDriverResultSetType" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ </node>
+ <node oor:name="MetaData">
+ <node oor:name="SupportsTableCreation" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="SupportsBrowsing" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="Authentication" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:string">
+ <value>UserPassword</value>
+ </prop>
+ </node>
+ </node>
+ </node>
+ </node>
+</oor:component-data>
diff --git a/connectivity/registry/postgresql/org/openoffice/Office/DataAccess/Drivers.xcu b/connectivity/registry/postgresql/org/openoffice/Office/DataAccess/Drivers.xcu
new file mode 100644
index 0000000000..63757e3ec7
--- /dev/null
+++ b/connectivity/registry/postgresql/org/openoffice/Office/DataAccess/Drivers.xcu
@@ -0,0 +1,94 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--***********************************************************************
+ *
+ * Effective License of whole file:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 3, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011:
+ *
+ * The Contents of this file are made available subject to the terms of
+ * the GNU Lesser General Public License Version 3
+ *
+ * Copyright: 2008 by Sun Microsystems, Inc.
+ *
+ * All parts contributed on or after August 2011:
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ ************************************************************************ -->
+<oor:component-data oor:name="Drivers" oor:package="org.openoffice.Office.DataAccess" xmlns:install="http://openoffice.org/2004/installation" xmlns:oor="http://openoffice.org/2001/registry" xmlns:xs="http://www.w3.org/2001/XMLSchema">
+ <node oor:name="Installed" install:module="postgresql">
+ <node oor:name="sdbc:postgresql:*" oor:op="replace">
+ <prop oor:name="Driver">
+ <value>org.openoffice.comp.connectivity.pq.Driver.noext</value>
+ </prop>
+ <prop oor:name="DriverTypeDisplayName" oor:type="xs:string">
+ <value xml:lang="en-US">PostgreSQL</value>
+ </prop>
+ <node oor:name="Properties">
+ <!-- Don't use ODBC syntax for date&time literals and (full) outer joins,
+ as PostgreSQL does not support it,
+ but supports the _interior_ of these escapes just fine. -->
+ <node oor:name="EscapeDateTime" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>false</value>
+ </prop>
+ </node>
+ <!-- Confusingly, this corresponds to "UseBracketedOuterJoinSyntax" in the Features -->
+ <node oor:name="EnableOuterJoinEscape" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>false</value>
+ </prop>
+ </node>
+ <node oor:name="BooleanComparisonMode" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:int">
+ <value>2</value>
+ </prop>
+ </node>
+ </node>
+ <node oor:name="Features">
+ <!-- These entries enable the "Advanced Settings" UI to change the settings
+ whose default is set in node "Properties" above;
+ as this is guaranteed not to work with PostgreSQL,
+ we don't let people shoot themselves in the foot and don't enable the UI. -->
+ <!-- <node oor:name="EscapeDateTime" oor:op="replace"> -->
+ <!-- <prop oor:name="Value" oor:type="xs:boolean"> -->
+ <!-- <value>false</value> -->
+ <!-- </prop> -->
+ <!-- </node> -->
+ <!-- Confusingly, this corresponds to "EnableOuterJoinEscape" in the Properties -->
+ <!-- <node oor:name="UseBracketedOuterJoinSyntax" oor:op="replace"> -->
+ <!-- <prop oor:name="Value" oor:type="xs:boolean"> -->
+ <!-- <value>false</value> -->
+ <!-- </prop> -->
+ <!-- </node> -->
+ </node>
+ <node oor:name="MetaData">
+ <node oor:name="Authentication" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:string">
+ <value>UserPassword</value>
+ </prop>
+ </node>
+ </node>
+ </node>
+ </node>
+</oor:component-data>
+
+<!-- Local Variables: -->
+<!-- indent-tabs-mode: nil -->
+<!-- End: -->
diff --git a/connectivity/registry/writer/org/openoffice/Office/DataAccess/Drivers.xcu b/connectivity/registry/writer/org/openoffice/Office/DataAccess/Drivers.xcu
new file mode 100644
index 0000000000..a4624a6e8c
--- /dev/null
+++ b/connectivity/registry/writer/org/openoffice/Office/DataAccess/Drivers.xcu
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ -->
+<oor:component-data oor:name="Drivers" oor:package="org.openoffice.Office.DataAccess" xmlns:install="http://openoffice.org/2004/installation" xmlns:oor="http://openoffice.org/2001/registry" xmlns:xs="http://www.w3.org/2001/XMLSchema">
+ <node oor:name="Installed" install:module="writer">
+ <node oor:name="sdbc:writer:*" oor:op="replace">
+ <prop oor:name="Driver">
+ <value>com.sun.star.comp.sdbc.writer.ODriver</value>
+ </prop>
+ <prop oor:name="DriverTypeDisplayName" oor:type="xs:string">
+ <value xml:lang="en-US">Writer Document</value>
+ </prop>
+ <node oor:name="Properties">
+ <node oor:name="EscapeDateTime" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ </node>
+ <node oor:name="Features">
+ <node oor:name="EscapeDateTime" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ </node>
+ <node oor:name="MetaData">
+ <node oor:name="SupportsBrowsing" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="FileSystemBased" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:boolean">
+ <value>true</value>
+ </prop>
+ </node>
+ <node oor:name="MediaType" oor:op="replace">
+ <prop oor:name="Value" oor:type="xs:string">
+ <value>application/vnd.oasis.opendocument.text</value>
+ </prop>
+ </node>
+ </node>
+ </node>
+ </node>
+</oor:component-data>
diff --git a/connectivity/source/commontools/AutoRetrievingBase.cxx b/connectivity/source/commontools/AutoRetrievingBase.cxx
new file mode 100644
index 0000000000..99327f27ee
--- /dev/null
+++ b/connectivity/source/commontools/AutoRetrievingBase.cxx
@@ -0,0 +1,52 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <AutoRetrievingBase.hxx>
+
+#include <osl/diagnose.h>
+#include <o3tl/string_view.hxx>
+
+namespace connectivity
+{
+ OUString OAutoRetrievingBase::getTransformedGeneratedStatement(const OUString& _sInsertStatement) const
+ {
+ OSL_ENSURE( m_bAutoRetrievingEnabled,"Illegal call here. isAutoRetrievingEnabled is false!");
+ OUString sStmt = _sInsertStatement.toAsciiUpperCase();
+ if ( sStmt.startsWith("INSERT") )
+ {
+ static const char sTable[] = "$table";
+ const sal_Int32 nColumnIndex {m_sGeneratedValueStatement.indexOf("$column")};
+ if ( nColumnIndex>=0 )
+ { // we need a column
+ }
+ const sal_Int32 nTableIndex {m_sGeneratedValueStatement.indexOf(sTable)};
+ if ( nTableIndex>=0 )
+ { // we need a table name
+ sal_Int32 nIntoIndex = sStmt.indexOf("INTO ") + 5;
+ while (nIntoIndex<sStmt.getLength() && sStmt[nIntoIndex]==' ') ++nIntoIndex;
+ const std::u16string_view sTableName = o3tl::getToken(sStmt, 0, ' ', nIntoIndex);
+ return m_sGeneratedValueStatement.replaceAt(nTableIndex, strlen(sTable), sTableName);
+ }
+ return m_sGeneratedValueStatement;
+ }
+ return OUString();
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/commontools/BlobHelper.cxx b/connectivity/source/commontools/BlobHelper.cxx
new file mode 100644
index 0000000000..f1f048a731
--- /dev/null
+++ b/connectivity/source/commontools/BlobHelper.cxx
@@ -0,0 +1,63 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#include <connectivity/BlobHelper.hxx>
+#include <comphelper/seqstream.hxx>
+#include <connectivity/dbexception.hxx>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <o3tl/unreachable.hxx>
+
+using namespace connectivity;
+using namespace dbtools;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::uno;
+
+BlobHelper::BlobHelper(const css::uno::Sequence< sal_Int8 >& _val) : m_aValue(_val)
+{
+}
+
+::sal_Int64 SAL_CALL BlobHelper::length( )
+{
+ return m_aValue.getLength();
+}
+
+css::uno::Sequence< ::sal_Int8 > SAL_CALL BlobHelper::getBytes( ::sal_Int64 pos, ::sal_Int32 _length )
+{
+ if ( sal_Int32(pos + _length) > m_aValue.getLength() )
+ throw css::sdbc::SQLException();
+ return css::uno::Sequence< ::sal_Int8 >(m_aValue.getConstArray() + sal_Int32(pos),_length);
+}
+
+css::uno::Reference< css::io::XInputStream > SAL_CALL BlobHelper::getBinaryStream( )
+{
+ return new ::comphelper::SequenceInputStream(m_aValue);
+}
+
+::sal_Int64 SAL_CALL BlobHelper::position( const css::uno::Sequence< ::sal_Int8 >& /*pattern*/, ::sal_Int64 /*start*/ )
+{
+ ::dbtools::throwFeatureNotImplementedSQLException( "XBlob::position", *this );
+ O3TL_UNREACHABLE;
+}
+
+::sal_Int64 SAL_CALL BlobHelper::positionOfBlob( const css::uno::Reference< css::sdbc::XBlob >& /*pattern*/, ::sal_Int64 /*start*/ )
+{
+ ::dbtools::throwFeatureNotImplementedSQLException( "XBlob::positionOfBlob", *this );
+ O3TL_UNREACHABLE;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/commontools/CommonTools.cxx b/connectivity/source/commontools/CommonTools.cxx
new file mode 100644
index 0000000000..596be7097d
--- /dev/null
+++ b/connectivity/source/commontools/CommonTools.cxx
@@ -0,0 +1,235 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <config_java.h>
+
+#include <connectivity/CommonTools.hxx>
+#include <connectivity/dbtools.hxx>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/java/JavaVirtualMachine.hpp>
+#if HAVE_FEATURE_JAVA
+#include <jvmaccess/virtualmachine.hxx>
+#endif
+#include <osl/diagnose.h>
+#include <rtl/character.hxx>
+#include <rtl/process.h>
+#include <comphelper/diagnose_ex.hxx>
+
+using namespace ::comphelper;
+static sal_Unicode rtl_ascii_toUpperCase( sal_Unicode ch )
+{
+ return ch >= 0x0061 && ch <= 0x007a ? ch + 0x20 : ch;
+}
+
+namespace connectivity
+{
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::beans;
+ using namespace ::com::sun::star::java;
+ using namespace dbtools;
+
+ const sal_Unicode CHAR_PLACE = '_';
+ const sal_Unicode CHAR_WILD = '%';
+
+ bool match(const sal_Unicode* pWild, const sal_Unicode* pStr, const sal_Unicode cEscape)
+ {
+ int pos=0;
+ int flag=0;
+
+ while ( *pWild || flag )
+ {
+ switch (*pWild)
+ {
+ case CHAR_PLACE:
+ if ( *pStr == 0 )
+ return false;
+ break;
+ default:
+ if (*pWild && (*pWild == cEscape) && ((*(pWild+1)== CHAR_PLACE) || (*(pWild+1) == CHAR_WILD)) )
+ pWild++;
+ if ( rtl_ascii_toUpperCase(*pWild) != rtl_ascii_toUpperCase(*pStr) )
+ if ( !pos )
+ return false;
+ else
+ pWild += pos;
+ else
+ break;
+ // WARNING/TODO: in certain circumstances it will run into
+ // the next 'case'!
+ [[fallthrough]];
+ case CHAR_WILD:
+ while ( *pWild == CHAR_WILD )
+ pWild++;
+ if ( *pWild == 0 )
+ return true;
+ flag = 1;
+ pos = 0;
+ if ( *pStr == 0 )
+ return ( *pWild == 0 );
+ while ( *pStr && *pStr != *pWild )
+ {
+ if ( *pWild == CHAR_PLACE ) {
+ pWild++;
+ while ( *pWild == CHAR_WILD )
+ pWild++;
+ }
+ pStr++;
+ if ( *pStr == 0 )
+ return ( *pWild == 0 );
+ }
+ break;
+ }
+ if ( *pWild != 0 )
+ pWild++;
+ if ( *pStr != 0 )
+ pStr++;
+ else
+ flag = 0;
+ if ( flag )
+ pos--;
+ }
+ return ( *pStr == 0 ) && ( *pWild == 0 );
+ }
+
+#if HAVE_FEATURE_JAVA
+ ::rtl::Reference< jvmaccess::VirtualMachine > getJavaVM(const Reference<XComponentContext >& _rxContext)
+ {
+ ::rtl::Reference< jvmaccess::VirtualMachine > aRet;
+ OSL_ENSURE(_rxContext.is(),"No XMultiServiceFactory a.v.!");
+ if(!_rxContext.is())
+ return aRet;
+
+ try
+ {
+ Reference< XJavaVM > xVM = JavaVirtualMachine::create(_rxContext);
+
+ Sequence<sal_Int8> processID(17); // 16 + 1
+ auto pprocessID = processID.getArray();
+ rtl_getGlobalProcessId( reinterpret_cast<sal_uInt8*>(pprocessID) );
+ pprocessID[16] = 0; // RETURN_VIRTUALMACHINE
+
+ Any uaJVM = xVM->getJavaVM( processID );
+ sal_Int64 nTemp;
+ if (!(uaJVM >>= nTemp)) {
+ throw Exception("cannot get result for getJavaVM", nullptr); // -5
+ }
+ aRet = reinterpret_cast<jvmaccess::VirtualMachine *>(
+ static_cast<sal_IntPtr>(nTemp));
+ }
+ catch (Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("connectivity.commontools", "getJavaVM failed:");
+ }
+
+ return aRet;
+ }
+
+ bool existsJavaClassByName( const ::rtl::Reference< jvmaccess::VirtualMachine >& _pJVM,std::u16string_view _sClassName )
+ {
+ bool bRet = false;
+ if ( _pJVM.is() )
+ {
+ jvmaccess::VirtualMachine::AttachGuard aGuard(_pJVM);
+ JNIEnv* pEnv = aGuard.getEnvironment();
+ if( pEnv )
+ {
+ OString sClassName = OUStringToOString(_sClassName, RTL_TEXTENCODING_ASCII_US);
+ sClassName = sClassName.replace('.','/');
+ jobject out = pEnv->FindClass(sClassName.getStr());
+ bRet = out != nullptr;
+ pEnv->DeleteLocalRef( out );
+ }
+ }
+ return bRet;
+ }
+#endif
+}
+
+namespace dbtools
+{
+
+static bool isCharOk(sal_Unicode c, std::u16string_view _rSpecials)
+{
+
+ return ( ((c >= 97) && (c <= 122)) || ((c >= 65) && (c <= 90)) || ((c >= 48) && (c <= 57)) ||
+ c == '_' || _rSpecials.find(c) != std::u16string_view::npos);
+}
+
+
+bool isValidSQLName(const OUString& rName, std::u16string_view _rSpecials)
+{
+ // Test for correct naming (in SQL sense)
+ // This is important for table names for example
+ const sal_Unicode* pStr = rName.getStr();
+ if (*pStr > 127 || rtl::isAsciiDigit(*pStr))
+ return false;
+
+ for (; *pStr; ++pStr )
+ if(!isCharOk(*pStr,_rSpecials))
+ return false;
+
+ if ( !rName.isEmpty()
+ && ( (rName.toChar() == '_')
+ || ( (rName.toChar() >= '0')
+ && (rName.toChar() <= '9')
+ )
+ )
+ )
+ return false;
+ // the SQL-Standard requires the first character to be an alphabetic character, which
+ // isn't easy to decide in UniCode...
+ // So we just prohibit the characters which already lead to problems...
+ // 11.04.00 - 74902 - FS
+
+ return true;
+}
+
+// Creates a new name if necessary
+OUString convertName2SQLName(const OUString& rName, std::u16string_view _rSpecials)
+{
+ if(isValidSQLName(rName,_rSpecials))
+ return rName;
+
+ const sal_Unicode* pStr = rName.getStr();
+ // if not valid
+ if (*pStr >= 128 || rtl::isAsciiDigit(*pStr))
+ return OUString();
+
+ OUStringBuffer aNewName(rName);
+ sal_Int32 nLength = rName.getLength();
+ for (sal_Int32 i=0; i < nLength; ++i)
+ if(!isCharOk(aNewName[i],_rSpecials))
+ aNewName[i] = '_';
+
+ return aNewName.makeStringAndClear();
+}
+
+OUString quoteName(std::u16string_view _rQuote, const OUString& _rName)
+{
+ OUString sName = _rName;
+ if( !_rQuote.empty() && _rQuote[0] != ' ')
+ sName = _rQuote + _rName + _rQuote;
+ return sName;
+}
+
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/commontools/ConnectionWrapper.cxx b/connectivity/source/commontools/ConnectionWrapper.cxx
new file mode 100644
index 0000000000..df5ef04ee5
--- /dev/null
+++ b/connectivity/source/commontools/ConnectionWrapper.cxx
@@ -0,0 +1,238 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <connectivity/ConnectionWrapper.hxx>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <comphelper/uno3.hxx>
+#include <comphelper/sequence.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <comphelper/hash.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <com/sun/star/reflection/ProxyFactory.hpp>
+#include <algorithm>
+
+using namespace connectivity;
+
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::sdbc;
+using namespace ::com::sun::star::reflection;
+
+OConnectionWrapper::OConnectionWrapper()
+{
+
+}
+
+void OConnectionWrapper::setDelegation(Reference< XAggregation >& _rxProxyConnection,oslInterlockedCount& _rRefCount)
+{
+ OSL_ENSURE(_rxProxyConnection.is(),"OConnectionWrapper: Connection must be valid!");
+ osl_atomic_increment( &_rRefCount );
+ if (_rxProxyConnection.is())
+ {
+ // transfer the (one and only) real ref to the aggregate to our member
+ m_xProxyConnection = _rxProxyConnection;
+ _rxProxyConnection = nullptr;
+ ::comphelper::query_aggregation(m_xProxyConnection,m_xConnection);
+ m_xTypeProvider.set(m_xConnection,UNO_QUERY);
+ m_xUnoTunnel.set(m_xConnection,UNO_QUERY);
+ m_xServiceInfo.set(m_xConnection,UNO_QUERY);
+
+ // set ourself as delegator
+ Reference<XInterface> xIf = static_cast< XUnoTunnel* >( this );
+ m_xProxyConnection->setDelegator( xIf );
+
+ }
+ osl_atomic_decrement( &_rRefCount );
+}
+
+void OConnectionWrapper::setDelegation(const Reference< XConnection >& _xConnection
+ ,const Reference< XComponentContext>& _rxContext
+ ,oslInterlockedCount& _rRefCount)
+{
+ OSL_ENSURE(_xConnection.is(),"OConnectionWrapper: Connection must be valid!");
+ osl_atomic_increment( &_rRefCount );
+
+ m_xConnection = _xConnection;
+ m_xTypeProvider.set(m_xConnection,UNO_QUERY);
+ m_xUnoTunnel.set(m_xConnection,UNO_QUERY);
+ m_xServiceInfo.set(m_xConnection,UNO_QUERY);
+
+ Reference< XProxyFactory > xProxyFactory = ProxyFactory::create( _rxContext );
+ Reference< XAggregation > xConProxy = xProxyFactory->createProxy(_xConnection);
+ if (xConProxy.is())
+ {
+ // transfer the (one and only) real ref to the aggregate to our member
+ m_xProxyConnection = xConProxy;
+
+ // set ourself as delegator
+ Reference<XInterface> xIf = static_cast< XUnoTunnel* >( this );
+ m_xProxyConnection->setDelegator( xIf );
+
+ }
+ osl_atomic_decrement( &_rRefCount );
+}
+
+void OConnectionWrapper::disposing()
+{
+m_xConnection.clear();
+}
+
+OConnectionWrapper::~OConnectionWrapper()
+{
+ if (m_xProxyConnection.is())
+ m_xProxyConnection->setDelegator(nullptr);
+}
+
+// XServiceInfo
+
+OUString SAL_CALL OConnectionWrapper::getImplementationName( )
+{
+ return "com.sun.star.sdbc.drivers.OConnectionWrapper";
+}
+
+
+css::uno::Sequence< OUString > SAL_CALL OConnectionWrapper::getSupportedServiceNames( )
+{
+ // first collect the services which are supported by our aggregate
+ Sequence< OUString > aSupported;
+ if ( m_xServiceInfo.is() )
+ aSupported = m_xServiceInfo->getSupportedServiceNames();
+
+ // append our own service, if necessary
+ OUString sConnectionService( "com.sun.star.sdbc.Connection" );
+ if ( ::comphelper::findValue( aSupported, sConnectionService ) == -1 )
+ {
+ sal_Int32 nLen = aSupported.getLength();
+ aSupported.realloc( nLen + 1 );
+ aSupported.getArray()[ nLen ] = sConnectionService;
+ }
+
+ // outta here
+ return aSupported;
+}
+
+
+sal_Bool SAL_CALL OConnectionWrapper::supportsService( const OUString& _rServiceName )
+{
+ return cppu::supportsService(this, _rServiceName);
+}
+
+
+Any SAL_CALL OConnectionWrapper::queryInterface( const Type& _rType )
+{
+ Any aReturn = OConnection_BASE::queryInterface(_rType);
+ return aReturn.hasValue() ? aReturn : (m_xProxyConnection.is() ? m_xProxyConnection->queryAggregation(_rType) : aReturn);
+}
+
+Sequence< Type > SAL_CALL OConnectionWrapper::getTypes( )
+{
+ return ::comphelper::concatSequences(
+ OConnection_BASE::getTypes(),
+ m_xTypeProvider->getTypes()
+ );
+}
+
+// css::lang::XUnoTunnel
+sal_Int64 SAL_CALL OConnectionWrapper::getSomething( const Sequence< sal_Int8 >& rId )
+{
+ if (comphelper::isUnoTunnelId<OConnectionWrapper>(rId))
+ return comphelper::getSomething_cast(this);
+
+ if(m_xUnoTunnel.is())
+ return m_xUnoTunnel->getSomething(rId);
+ return 0;
+}
+
+
+const Sequence< sal_Int8 > & OConnectionWrapper::getUnoTunnelId()
+{
+ static const comphelper::UnoIdInit implId;
+ return implId.getSeq();
+}
+
+namespace
+{
+ class TPropertyValueLessFunctor
+ {
+ public:
+ TPropertyValueLessFunctor()
+ {}
+ bool operator() (const css::beans::PropertyValue& lhs, const css::beans::PropertyValue& rhs) const
+ {
+ return lhs.Name.compareToIgnoreAsciiCase(rhs.Name) < 0;
+ }
+ };
+
+}
+
+
+// creates a unique id out of the url and sequence of properties
+void OConnectionWrapper::createUniqueId( const OUString& _rURL
+ ,Sequence< PropertyValue >& _rInfo
+ ,sal_uInt8* _pBuffer
+ ,const OUString& _rUserName
+ ,const OUString& _rPassword)
+{
+ // first we create the digest we want to have
+ ::comphelper::Hash sha1(::comphelper::HashType::SHA1);
+ sha1.update(reinterpret_cast<unsigned char const*>(_rURL.getStr()), _rURL.getLength() * sizeof(sal_Unicode));
+ if ( !_rUserName.isEmpty() )
+ sha1.update(reinterpret_cast<unsigned char const*>(_rUserName.getStr()), _rUserName.getLength() * sizeof(sal_Unicode));
+ if ( !_rPassword.isEmpty() )
+ sha1.update(reinterpret_cast<unsigned char const*>(_rPassword.getStr()), _rPassword.getLength() * sizeof(sal_Unicode));
+ // now we need to sort the properties
+ auto [begin, end] = asNonConstRange(_rInfo);
+ std::sort(begin,end,TPropertyValueLessFunctor());
+
+ for (PropertyValue const & prop : std::as_const(_rInfo))
+ {
+ // we only include strings an integer values
+ OUString sValue;
+ if ( prop.Value >>= sValue )
+ ;
+ else
+ {
+ sal_Int32 nValue = 0;
+ if ( prop.Value >>= nValue )
+ sValue = OUString::number(nValue);
+ else
+ {
+ Sequence< OUString> aSeq;
+ if ( prop.Value >>= aSeq )
+ {
+ for(OUString const & s : std::as_const(aSeq))
+ sha1.update(reinterpret_cast<unsigned char const*>(s.getStr()), s.getLength() * sizeof(sal_Unicode));
+ }
+ }
+ }
+ if ( !sValue.isEmpty() )
+ {
+ // we don't have to convert this into UTF8 because we don't store on a file system
+ sha1.update(reinterpret_cast<unsigned char const*>(sValue.getStr()), sValue.getLength() * sizeof(sal_Unicode));
+ }
+ }
+
+ std::vector<unsigned char> result(sha1.finalize());
+ std::copy(result.begin(), result.end(), _pBuffer);
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/commontools/DateConversion.cxx b/connectivity/source/commontools/DateConversion.cxx
new file mode 100644
index 0000000000..0895881d7e
--- /dev/null
+++ b/connectivity/source/commontools/DateConversion.cxx
@@ -0,0 +1,517 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <connectivity/dbconversion.hxx>
+#include <connectivity/dbtools.hxx>
+#include <com/sun/star/script/XTypeConverter.hpp>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <com/sun/star/util/NumberFormat.hpp>
+#include <com/sun/star/util/XNumberFormatter.hpp>
+#include <com/sun/star/util/XNumberFormatTypes.hpp>
+#include <com/sun/star/sdb/XColumnUpdate.hpp>
+#include <com/sun/star/sdb/XColumn.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <comphelper/extract.hxx>
+#include <TConnection.hxx>
+#include <comphelper/numbers.hxx>
+#include <comphelper/types.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <sal/log.hxx>
+#include <comphelper/diagnose_ex.hxx>
+
+
+using namespace ::connectivity;
+using namespace ::comphelper;
+using namespace ::com::sun::star::script;
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::sdbc;
+using namespace ::dbtools;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::util;
+using namespace ::com::sun::star::uno;
+
+OUString DBTypeConversion::toSQLString(sal_Int32 eType, const Any& _rVal,
+ const Reference< XTypeConverter >& _rxTypeConverter)
+{
+ OUStringBuffer aRet;
+ if (_rVal.hasValue())
+ {
+ try
+ {
+ switch (eType)
+ {
+ case DataType::INTEGER:
+ case DataType::BIT:
+ case DataType::BOOLEAN:
+ case DataType::TINYINT:
+ case DataType::SMALLINT:
+ if (_rVal.getValueType().getTypeClass() == css::uno::TypeClass_BOOLEAN)
+ {
+ if (::cppu::any2bool(_rVal))
+ aRet.append("1");
+ else
+ aRet.append("0");
+ }
+ else
+ {
+ OUString sTemp;
+ _rxTypeConverter->convertToSimpleType(_rVal, TypeClass_STRING) >>= sTemp;
+ aRet.append(sTemp);
+ }
+ break;
+ case DataType::CHAR:
+ case DataType::VARCHAR:
+ case DataType::LONGVARCHAR:
+ aRet.append("'");
+ {
+ OUString aTemp;
+ _rxTypeConverter->convertToSimpleType(_rVal, TypeClass_STRING) >>= aTemp;
+ aTemp = aTemp.replaceAll(u"\'", u"\'\'");
+ aRet.append(aTemp);
+ }
+ aRet.append("'");
+ break;
+ case DataType::REAL:
+ case DataType::DOUBLE:
+ case DataType::DECIMAL:
+ case DataType::NUMERIC:
+ case DataType::BIGINT:
+ default:
+ {
+ OUString sTemp;
+ _rxTypeConverter->convertToSimpleType(_rVal, TypeClass_STRING) >>= sTemp;
+ aRet.append(sTemp);
+ }
+ break;
+ case DataType::TIMESTAMP:
+ {
+ DateTime aDateTime;
+ bool bOk = false;
+ if (_rVal.getValueType().getTypeClass() == css::uno::TypeClass_DOUBLE)
+ {
+ double nValue = 0.0;
+ _rVal >>= nValue;
+ aDateTime = DBTypeConversion::toDateTime(nValue);
+ bOk = true;
+ }
+ else if (_rVal.getValueType().getTypeClass() == css::uno::TypeClass_STRING)
+ {
+ OUString sValue;
+ _rVal >>= sValue;
+ aDateTime = DBTypeConversion::toDateTime(sValue);
+ bOk = true;
+ }
+ else
+ bOk = _rVal >>= aDateTime;
+
+ OSL_ENSURE( bOk, "DBTypeConversion::toSQLString: _rVal is not datetime!");
+ // check if this is really a timestamp or only a date
+ if ( bOk )
+ {
+ aRet.append("{ts '"
+ + DBTypeConversion::toDateTimeString(aDateTime)
+ + "'}");
+ break;
+ }
+ break;
+ }
+ case DataType::DATE:
+ {
+ Date aDate;
+ bool bOk = false;
+ if (_rVal.getValueType().getTypeClass() == css::uno::TypeClass_DOUBLE)
+ {
+ double nValue = 0.0;
+ _rVal >>= nValue;
+ aDate = DBTypeConversion::toDate(nValue);
+ bOk = true;
+ }
+ else if (_rVal.getValueType().getTypeClass() == css::uno::TypeClass_STRING)
+ {
+ OUString sValue;
+ _rVal >>= sValue;
+ aDate = DBTypeConversion::toDate(sValue);
+ bOk = true;
+ }
+ else
+ bOk = _rVal >>= aDate;
+ OSL_ENSURE( bOk, "DBTypeConversion::toSQLString: _rVal is not date!");
+ aRet.append("{d '"
+ + DBTypeConversion::toDateString(aDate)
+ + "'}");
+ } break;
+ case DataType::TIME:
+ {
+ css::util::Time aTime;
+ bool bOk = false;
+ if (_rVal.getValueType().getTypeClass() == css::uno::TypeClass_DOUBLE)
+ {
+ double nValue = 0.0;
+ _rVal >>= nValue;
+ aTime = DBTypeConversion::toTime(nValue);
+ bOk = true;
+ }
+ else if (_rVal.getValueType().getTypeClass() == css::uno::TypeClass_STRING)
+ {
+ OUString sValue;
+ _rVal >>= sValue;
+ aTime = DBTypeConversion::toTime(sValue);
+ bOk = true;
+ }
+ else
+ bOk = _rVal >>= aTime;
+ OSL_ENSURE( bOk,"DBTypeConversion::toSQLString: _rVal is not time!");
+ aRet.append("{t '"
+ + DBTypeConversion::toTimeString(aTime)
+ + "'}");
+ } break;
+ }
+ }
+ catch ( const Exception& )
+ {
+ OSL_FAIL("TypeConversion Error");
+ }
+ }
+ else
+ aRet.append(" NULL ");
+ return aRet.makeStringAndClear();
+}
+
+Date DBTypeConversion::getNULLDate(const Reference< XNumberFormatsSupplier > &xSupplier)
+{
+ OSL_ENSURE(xSupplier.is(), "getNULLDate : the formatter doesn't implement a supplier !");
+ if (xSupplier.is())
+ {
+ try
+ {
+ // get the null date
+ Date aDate;
+ xSupplier->getNumberFormatSettings()->getPropertyValue("NullDate") >>= aDate;
+ return aDate;
+ }
+ catch ( const Exception& )
+ {
+ }
+ }
+
+ return getStandardDate();
+}
+
+void DBTypeConversion::setValue(const Reference<XColumnUpdate>& xVariant,
+ const Reference<XNumberFormatter>& xFormatter,
+ const Date& rNullDate,
+ const OUString& rString,
+ sal_Int32 nKey,
+ sal_Int16 nFieldType,
+ sal_Int16 nKeyType)
+{
+ if (!rString.isEmpty())
+ {
+ // Does the String need to be formatted?
+ sal_Int16 nTypeClass = nKeyType & ~NumberFormat::DEFINED;
+ bool bTextFormat = nTypeClass == NumberFormat::TEXT;
+ sal_Int32 nKeyToUse = bTextFormat ? 0 : nKey;
+ sal_Int16 nRealUsedTypeClass = nTypeClass;
+ // for a Text-Format the formatter needs some more freedom, otherwise
+ // convertStringToNumber will throw a NotNumericException
+ try
+ {
+ double fValue = xFormatter->convertStringToNumber(nKeyToUse, rString);
+ Reference< XNumberFormats > xFormats(xFormatter->getNumberFormatsSupplier()->getNumberFormats());
+ Reference< XNumberFormatTypes > xFormatTypes(xFormats, UNO_QUERY);
+ sal_Int32 nStandardKey(0);
+ if(xFormatTypes.is())
+ {
+ const Reference< XPropertySet > xFormatProps(xFormats->getByKey(nKeyToUse));
+ if (xFormatProps.is())
+ {
+ css::lang::Locale loc;
+ if (xFormatProps->getPropertyValue("Locale") >>= loc)
+ nStandardKey = xFormatTypes->getStandardIndex(loc);
+ else
+ {
+ assert(false);
+ }
+ }
+ else
+ {
+ SAL_WARN("connectivity.commontools", "no format by key " << nKeyToUse);
+ }
+ }
+ else
+ {
+ assert(false);
+ }
+ // Why use nStandardKey rather than nKeyToUse here? I'm not sure, but "it was always like that".
+ // Previously had hardcoded 0 instead of nStandardKey, which led to problems with dates
+ // because of differences M/D/Y vs D/M/Y. This at least fixes those problems, but possibly
+ // nKeyToUse is an even better choice than nStandardKey.
+ // OTOH, using nKeyToUse nullifies the special treatment for percent formats,
+ // leading to "5" (in a percent format) to be understood as "500%" instead of "5%".
+ sal_Int32 nRealUsedKey = xFormatter->detectNumberFormat(nStandardKey, rString);
+ if (nRealUsedKey != nKeyToUse)
+ nRealUsedTypeClass = getNumberFormatType(xFormatter, nRealUsedKey) & ~NumberFormat::DEFINED;
+
+ // and again a special treatment, this time for percent formats
+ if ((NumberFormat::NUMBER == nRealUsedTypeClass) && (NumberFormat::PERCENT == nTypeClass))
+ { // formatting should be "percent", but the String provides just a simple number -> adjust
+ OUString sExpanded = rString + "%";
+ fValue = xFormatter->convertStringToNumber(nKeyToUse, sExpanded);
+ }
+
+ switch (nRealUsedTypeClass)
+ {
+ case NumberFormat::DATE:
+ case NumberFormat::DATETIME:
+ case NumberFormat::TIME:
+ DBTypeConversion::setValue(xVariant,rNullDate,fValue,nRealUsedTypeClass);
+ break;
+ case NumberFormat::CURRENCY:
+ case NumberFormat::NUMBER:
+ case NumberFormat::SCIENTIFIC:
+ case NumberFormat::FRACTION:
+ case NumberFormat::PERCENT:
+ xVariant->updateDouble(fValue);
+ break;
+ default:
+ xVariant->updateString(rString);
+ }
+ }
+ catch(const Exception& )
+ {
+ xVariant->updateString(rString);
+ }
+ }
+ else
+ {
+ switch (nFieldType)
+ {
+ case css::sdbc::DataType::CHAR:
+ case css::sdbc::DataType::VARCHAR:
+ case css::sdbc::DataType::LONGVARCHAR:
+ xVariant->updateString(rString);
+ break;
+ default:
+ xVariant->updateNull();
+ }
+ }
+}
+
+
+void DBTypeConversion::setValue(const Reference<XColumnUpdate>& xVariant,
+ const Date& rNullDate,
+ const double& rValue,
+ sal_Int16 nKeyType)
+{
+ switch (nKeyType & ~NumberFormat::DEFINED)
+ {
+ case NumberFormat::DATE:
+ xVariant->updateDate(toDate( rValue, rNullDate));
+ break;
+ case NumberFormat::DATETIME:
+ xVariant->updateTimestamp(toDateTime(rValue,rNullDate));
+ break;
+ case NumberFormat::TIME:
+ xVariant->updateTime(toTime(rValue));
+ break;
+ default:
+ {
+ double nValue = rValue;
+// Reference<XPropertySet> xProp(xVariant,UNO_QUERY);
+// if ( xProp.is()
+// && xProp->getPropertySetInfo()->hasPropertyByName(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISSIGNED))
+// && !::comphelper::getBOOL(xProp->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISSIGNED))) )
+// {
+// switch (::comphelper::getINT32(xProp->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE))))
+// {
+// case DataType::TINYINT:
+// nValue = static_cast<sal_uInt8>(rValue);
+// break;
+// case DataType::SMALLINT:
+// nValue = static_cast<sal_uInt16>(rValue);
+// break;
+// case DataType::INTEGER:
+// nValue = static_cast<sal_uInt32>(rValue);
+// break;
+// case DataType::BIGINT:
+// nValue = static_cast<sal_uInt64>(rValue);
+// break;
+// }
+// }
+ xVariant->updateDouble(nValue);
+ }
+ }
+}
+
+
+double DBTypeConversion::getValue( const Reference< XColumn >& i_column, const Date& i_relativeToNullDate )
+{
+ try
+ {
+ const Reference< XPropertySet > xProp( i_column, UNO_QUERY_THROW );
+
+ const sal_Int32 nColumnType = ::comphelper::getINT32( xProp->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex( PROPERTY_ID_TYPE ) ) );
+ switch ( nColumnType )
+ {
+ case DataType::DATE:
+ return toDouble( i_column->getDate(), i_relativeToNullDate );
+
+ case DataType::TIME:
+ return toDouble( i_column->getTime() );
+
+ case DataType::TIMESTAMP:
+ return toDouble( i_column->getTimestamp(), i_relativeToNullDate );
+
+ default:
+ {
+ bool bIsSigned = true;
+ OSL_VERIFY( xProp->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex( PROPERTY_ID_ISSIGNED ) ) >>= bIsSigned );
+ if ( !bIsSigned )
+ {
+ switch ( nColumnType)
+ {
+ case DataType::TINYINT:
+ return static_cast<double>(static_cast<sal_uInt8>(i_column->getByte()));
+ case DataType::SMALLINT:
+ return static_cast<double>(static_cast<sal_uInt16>(i_column->getShort()));
+ case DataType::INTEGER:
+ return static_cast<double>(static_cast<sal_uInt32>(i_column->getInt()));
+ case DataType::BIGINT:
+ return static_cast<double>(static_cast<sal_uInt64>(i_column->getLong()));
+ }
+ }
+ }
+ return i_column->getDouble();
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("connectivity.commontools");
+ return 0.0;
+ }
+}
+
+OUString DBTypeConversion::getFormattedValue(const Reference< XPropertySet>& _xColumn,
+ const Reference<XNumberFormatter>& _xFormatter,
+ const css::lang::Locale& _rLocale,
+ const Date& _rNullDate)
+{
+ OSL_ENSURE(_xColumn.is() && _xFormatter.is(), "DBTypeConversion::getFormattedValue: invalid arg !");
+ if (!_xColumn.is() || !_xFormatter.is())
+ return OUString();
+
+ sal_Int32 nKey(0);
+ try
+ {
+ _xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FORMATKEY)) >>= nKey;
+ }
+ catch (const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "connectivity.commontools", "DBTypeConversion::getValue: caught an exception while asking for the format key!");
+ }
+
+ if (!nKey)
+ {
+ Reference<XNumberFormats> xFormats( _xFormatter->getNumberFormatsSupplier()->getNumberFormats() );
+
+ nKey = ::dbtools::getDefaultNumberFormat(_xColumn,
+ Reference< XNumberFormatTypes > (xFormats, UNO_QUERY),
+ _rLocale);
+
+ }
+
+ sal_Int16 nKeyType = getNumberFormatType(_xFormatter, nKey) & ~NumberFormat::DEFINED;
+
+ return DBTypeConversion::getFormattedValue(Reference< XColumn > (_xColumn, UNO_QUERY), _xFormatter, _rNullDate, nKey, nKeyType);
+}
+
+
+OUString DBTypeConversion::getFormattedValue(const Reference<XColumn>& xVariant,
+ const Reference<XNumberFormatter>& xFormatter,
+ const Date& rNullDate,
+ sal_Int32 nKey,
+ sal_Int16 nKeyType)
+{
+ OUString aString;
+ if (xVariant.is())
+ {
+ try
+ {
+ switch (nKeyType & ~NumberFormat::DEFINED)
+ {
+ case NumberFormat::DATE:
+ case NumberFormat::DATETIME:
+ {
+ // get a value which represents the given date, relative to the given null date
+ double fValue = getValue( xVariant, rNullDate );
+ if ( !xVariant->wasNull() )
+ {
+ // get the null date of the formatter
+ Date aFormatterNullDate( rNullDate );
+ try
+ {
+ Reference< XNumberFormatsSupplier > xSupplier( xFormatter->getNumberFormatsSupplier(), UNO_SET_THROW );
+ Reference< XPropertySet > xFormatterSettings( xSupplier->getNumberFormatSettings(), UNO_SET_THROW );
+ OSL_VERIFY( xFormatterSettings->getPropertyValue("NullDate") >>= aFormatterNullDate );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("connectivity.commontools");
+ }
+ // get a value which represents the given date, relative to the null date of the formatter
+ fValue -= toDays( rNullDate, aFormatterNullDate );
+ // format this value
+ aString = xFormatter->convertNumberToString( nKey, fValue );
+ }
+ }
+ break;
+ case NumberFormat::TIME:
+ case NumberFormat::NUMBER:
+ case NumberFormat::SCIENTIFIC:
+ case NumberFormat::FRACTION:
+ case NumberFormat::PERCENT:
+ {
+ double fValue = xVariant->getDouble();
+ if (!xVariant->wasNull())
+ aString = xFormatter->convertNumberToString(nKey, fValue);
+ } break;
+ case NumberFormat::CURRENCY:
+ {
+ double fValue = xVariant->getDouble();
+ if (!xVariant->wasNull())
+ aString = xFormatter->getInputString(nKey, fValue);
+ } break;
+ case NumberFormat::TEXT:
+ aString = xFormatter->formatString(nKey, xVariant->getString());
+ break;
+ default:
+ aString = xVariant->getString();
+ }
+ }
+ catch(const Exception& )
+ {
+ aString = xVariant->getString();
+ }
+ }
+ return aString;
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/commontools/DriversConfig.cxx b/connectivity/source/commontools/DriversConfig.cxx
new file mode 100644
index 0000000000..26a241e3f8
--- /dev/null
+++ b/connectivity/source/commontools/DriversConfig.cxx
@@ -0,0 +1,249 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#include <config_fuzzers.h>
+
+#include <connectivity/DriversConfig.hxx>
+#include <o3tl/string_view.hxx>
+#include <tools/wldcrd.hxx>
+#include <comphelper/sequence.hxx>
+#include <utility>
+
+using namespace connectivity;
+using namespace utl;
+using namespace ::com::sun::star;
+
+namespace
+{
+ void lcl_convert(const uno::Sequence< OUString >& _aSource,uno::Any& _rDest)
+ {
+ uno::Sequence<uno::Any> aRet(_aSource.getLength());
+ uno::Any* pAny = aRet.getArray();
+ const OUString* pIter = _aSource.getConstArray();
+ const OUString* pEnd = pIter + _aSource.getLength();
+ for (;pIter != pEnd ; ++pIter,++pAny)
+ {
+ *pAny <<= *pIter;
+ }
+ _rDest <<= aRet;
+ }
+ void lcl_fillValues(const ::utl::OConfigurationNode& _aURLPatternNode,const OUString& _sNode,::comphelper::NamedValueCollection& _rValues)
+ {
+ const ::utl::OConfigurationNode aPropertiesNode = _aURLPatternNode.openNode(_sNode);
+ if ( !aPropertiesNode.isValid() )
+ return;
+
+ uno::Sequence< OUString > aStringSeq;
+ const uno::Sequence< OUString > aProperties = aPropertiesNode.getNodeNames();
+ const OUString* pPropertiesIter = aProperties.getConstArray();
+ const OUString* pPropertiesEnd = pPropertiesIter + aProperties.getLength();
+ for (;pPropertiesIter != pPropertiesEnd ; ++pPropertiesIter)
+ {
+ uno::Any aValue = aPropertiesNode.getNodeValue(*pPropertiesIter + "/Value");
+ if ( aValue >>= aStringSeq )
+ {
+ lcl_convert(aStringSeq,aValue);
+ }
+ _rValues.put(*pPropertiesIter,aValue);
+ } // for (;pPropertiesIter != pPropertiesEnd ; ++pPropertiesIter,++pNamedIter)
+ }
+ void lcl_readURLPatternNode(const ::utl::OConfigurationTreeRoot& _aInstalled,const OUString& _sEntry,TInstalledDriver& _rInstalledDriver)
+ {
+ const ::utl::OConfigurationNode aURLPatternNode = _aInstalled.openNode(_sEntry);
+ if ( !aURLPatternNode.isValid() )
+ return;
+
+ OUString sParentURLPattern;
+ aURLPatternNode.getNodeValue("ParentURLPattern") >>= sParentURLPattern;
+ if ( !sParentURLPattern.isEmpty() )
+ lcl_readURLPatternNode(_aInstalled,sParentURLPattern,_rInstalledDriver);
+
+ OUString sDriverFactory;
+ aURLPatternNode.getNodeValue("Driver") >>= sDriverFactory;
+ if ( !sDriverFactory.isEmpty() )
+ _rInstalledDriver.sDriverFactory = sDriverFactory;
+
+ OUString sDriverTypeDisplayName;
+ aURLPatternNode.getNodeValue("DriverTypeDisplayName") >>= sDriverTypeDisplayName;
+ OSL_ENSURE(!sDriverTypeDisplayName.isEmpty(),"No valid DriverTypeDisplayName property!");
+ if ( !sDriverTypeDisplayName.isEmpty() )
+ _rInstalledDriver.sDriverTypeDisplayName = sDriverTypeDisplayName;
+
+ lcl_fillValues(aURLPatternNode,"Properties",_rInstalledDriver.aProperties);
+ lcl_fillValues(aURLPatternNode,"Features",_rInstalledDriver.aFeatures);
+ lcl_fillValues(aURLPatternNode,"MetaData",_rInstalledDriver.aMetaData);
+ }
+}
+
+DriversConfigImpl::DriversConfigImpl()
+{
+}
+
+const TInstalledDrivers& DriversConfigImpl::getInstalledDrivers(const uno::Reference< uno::XComponentContext >& _rxORB) const
+{
+ if ( m_aDrivers.empty() )
+ {
+ if ( !m_aInstalled.isValid() )
+ {
+ m_aInstalled = ::utl::OConfigurationTreeRoot::createWithComponentContext(_rxORB,
+ "org.openoffice.Office.DataAccess.Drivers/Installed", -1, ::utl::OConfigurationTreeRoot::CM_READONLY);
+ }
+
+ if ( m_aInstalled.isValid() )
+ {
+ const uno::Sequence< OUString > aURLPatterns = m_aInstalled.getNodeNames();
+ const OUString* pPatternIter = aURLPatterns.getConstArray();
+ const OUString* pPatternEnd = pPatternIter + aURLPatterns.getLength();
+ for (;pPatternIter != pPatternEnd ; ++pPatternIter)
+ {
+ TInstalledDriver aInstalledDriver;
+ lcl_readURLPatternNode(m_aInstalled,*pPatternIter,aInstalledDriver);
+ if ( !aInstalledDriver.sDriverFactory.isEmpty() )
+ m_aDrivers.emplace(*pPatternIter,aInstalledDriver);
+ }
+ } // if ( m_aInstalled.isValid() )
+ }
+ return m_aDrivers;
+}
+
+DriversConfig::DriversConfig(uno::Reference< uno::XComponentContext > _xORB)
+:m_xORB(std::move(_xORB))
+{
+}
+
+
+DriversConfig::~DriversConfig()
+{
+}
+
+
+DriversConfig::DriversConfig( const DriversConfig& _rhs )
+{
+ *this = _rhs;
+}
+
+
+DriversConfig& DriversConfig::operator=( const DriversConfig& _rhs )
+{
+ if ( this != &_rhs )
+ {
+ m_aNode = _rhs.m_aNode;
+ }
+ return *this;
+}
+
+
+OUString DriversConfig::getDriverFactoryName(std::u16string_view _sURL) const
+{
+#if ENABLE_FUZZERS
+ if (o3tl::starts_with(_sURL, u"sdbc:dbase:"))
+ return "com.sun.star.comp.sdbc.dbase.ODriver";
+#endif
+
+ const TInstalledDrivers& rDrivers = m_aNode->getInstalledDrivers(m_xORB);
+ OUString sRet;
+ OUString sOldPattern;
+ for(const auto& [rPattern, rDriver] : rDrivers)
+ {
+ WildCard aWildCard(rPattern);
+ if ( sOldPattern.getLength() < rPattern.getLength() && aWildCard.Matches(_sURL) )
+ {
+ sRet = rDriver.sDriverFactory;
+ sOldPattern = rPattern;
+ }
+ }
+
+ return sRet;
+}
+
+OUString DriversConfig::getDriverTypeDisplayName(std::u16string_view _sURL) const
+{
+ const TInstalledDrivers& rDrivers = m_aNode->getInstalledDrivers(m_xORB);
+ OUString sRet;
+ OUString sOldPattern;
+ for(const auto& [rPattern, rDriver] : rDrivers)
+ {
+ WildCard aWildCard(rPattern);
+ if ( sOldPattern.getLength() < rPattern.getLength() && aWildCard.Matches(_sURL) )
+ {
+ sRet = rDriver.sDriverTypeDisplayName;
+ sOldPattern = rPattern;
+ }
+ }
+
+ return sRet;
+}
+
+const ::comphelper::NamedValueCollection& DriversConfig::getProperties(std::u16string_view _sURL)
+ const
+{
+ return impl_get(_sURL,1);
+}
+
+const ::comphelper::NamedValueCollection& DriversConfig::getFeatures(std::u16string_view _sURL)
+ const
+{
+ return impl_get(_sURL,0);
+}
+
+const ::comphelper::NamedValueCollection& DriversConfig::getMetaData(std::u16string_view _sURL)
+ const
+{
+ return impl_get(_sURL,2);
+}
+
+const ::comphelper::NamedValueCollection& DriversConfig::impl_get(std::u16string_view _sURL,sal_Int32 _nProps) const
+{
+ const TInstalledDrivers& rDrivers = m_aNode->getInstalledDrivers(m_xORB);
+ const ::comphelper::NamedValueCollection* pRet = nullptr;
+ OUString sOldPattern;
+ for(const auto& [rPattern, rDriver] : rDrivers)
+ {
+ WildCard aWildCard(rPattern);
+ if ( sOldPattern.getLength() < rPattern.getLength() && aWildCard.Matches(_sURL) )
+ {
+ switch(_nProps)
+ {
+ case 0:
+ pRet = &rDriver.aFeatures;
+ break;
+ case 1:
+ pRet = &rDriver.aProperties;
+ break;
+ case 2:
+ pRet = &rDriver.aMetaData;
+ break;
+ }
+ sOldPattern = rPattern;
+ }
+ } // for(;aIter != aEnd;++aIter)
+ if ( pRet == nullptr )
+ {
+ static const ::comphelper::NamedValueCollection s_sEmpty;
+ pRet = &s_sEmpty;
+ }
+ return *pRet;
+}
+
+uno::Sequence< OUString > DriversConfig::getURLs() const
+{
+ const TInstalledDrivers& rDrivers = m_aNode->getInstalledDrivers(m_xORB);
+ return comphelper::mapKeysToSequence(rDrivers);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/commontools/FDatabaseMetaDataResultSet.cxx b/connectivity/source/commontools/FDatabaseMetaDataResultSet.cxx
new file mode 100644
index 0000000000..d4ae8760f2
--- /dev/null
+++ b/connectivity/source/commontools/FDatabaseMetaDataResultSet.cxx
@@ -0,0 +1,839 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <ParameterSubstitution.hxx>
+#include <FDatabaseMetaDataResultSet.hxx>
+#include <FDatabaseMetaDataResultSetMetaData.hxx>
+#include <com/sun/star/sdbc/ColumnSearch.hpp>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <cppuhelper/typeprovider.hxx>
+#include <comphelper/sequence.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <connectivity/dbexception.hxx>
+#include <o3tl/safeint.hxx>
+#include <o3tl/unreachable.hxx>
+#include <TConnection.hxx>
+
+using namespace connectivity;
+using namespace dbtools;
+using namespace cppu;
+
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+
+ODatabaseMetaDataResultSet::ODatabaseMetaDataResultSet()
+ :ODatabaseMetaDataResultSet_BASE(m_aMutex)
+ ,::comphelper::OPropertyContainer(ODatabaseMetaDataResultSet_BASE::rBHelper)
+ ,m_nColPos(0)
+ ,m_bBOF(true)
+ ,m_bEOF(true)
+{
+ construct();
+}
+
+
+ODatabaseMetaDataResultSet::ODatabaseMetaDataResultSet( MetaDataResultSetType _eType )
+ :ODatabaseMetaDataResultSet_BASE(m_aMutex)
+ ,::comphelper::OPropertyContainer(ODatabaseMetaDataResultSet_BASE::rBHelper)
+ ,m_nColPos(0)
+ ,m_bBOF(true)
+ ,m_bEOF(true)
+{
+ construct();
+
+ setType(_eType);
+}
+
+
+ODatabaseMetaDataResultSet::~ODatabaseMetaDataResultSet()
+{
+}
+
+void ODatabaseMetaDataResultSet::construct()
+{
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHSIZE), PROPERTY_ID_FETCHSIZE, 0,&m_nFetchSize, ::cppu::UnoType<sal_Int32>::get());
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETTYPE), PROPERTY_ID_RESULTSETTYPE, PropertyAttribute::READONLY,&m_nResultSetType, ::cppu::UnoType<sal_Int32>::get());
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHDIRECTION), PROPERTY_ID_FETCHDIRECTION, 0, &m_nFetchDirection, ::cppu::UnoType<sal_Int32>::get());
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETCONCURRENCY), PROPERTY_ID_RESULTSETCONCURRENCY, PropertyAttribute::READONLY,&m_nResultSetConcurrency, ::cppu::UnoType<sal_Int32>::get());
+}
+
+void ODatabaseMetaDataResultSet::setType(MetaDataResultSetType _eType)
+{
+ switch( _eType )
+ {
+ case eCatalogs: setCatalogsMap(); break;
+ case eSchemas: setSchemasMap(); break;
+ case eColumnPrivileges: setColumnPrivilegesMap(); break;
+ case eColumns: setColumnsMap(); break;
+ case eTables: setTablesMap(); break;
+ case eTableTypes: setTableTypes(); break;
+ case eProcedureColumns: setProcedureColumnsMap(); break;
+ case eProcedures: setProceduresMap(); break;
+ case eExportedKeys: setExportedKeysMap(); break;
+ case eImportedKeys: setImportedKeysMap(); break;
+ case ePrimaryKeys: setPrimaryKeysMap(); break;
+ case eIndexInfo: setIndexInfoMap(); break;
+ case eTablePrivileges: setTablePrivilegesMap(); break;
+ case eCrossReference: setCrossReferenceMap(); break;
+ case eTypeInfo: setTypeInfoMap(); break;
+ case eBestRowIdentifier: setBestRowIdentifierMap(); break;
+ case eVersionColumns: setVersionColumnsMap(); break;
+ case eUDTs: setUDTsMap(); break;
+ default:
+ OSL_FAIL("Wrong type!");
+ }
+}
+
+void ODatabaseMetaDataResultSet::disposing()
+{
+ OPropertySetHelper::disposing();
+
+ ::osl::MutexGuard aGuard(m_aMutex);
+ m_aStatement.clear();
+ m_xMetaData.clear();
+ m_aRowsIter = m_aRows.end();
+ m_aRows.clear();
+ m_aRowsIter = m_aRows.end();
+}
+
+void SAL_CALL ODatabaseMetaDataResultSet::acquire() noexcept
+{
+ ODatabaseMetaDataResultSet_BASE::acquire();
+}
+
+void SAL_CALL ODatabaseMetaDataResultSet::release() noexcept
+{
+ ODatabaseMetaDataResultSet_BASE::release();
+}
+
+Any SAL_CALL ODatabaseMetaDataResultSet::queryInterface( const Type & rType )
+{
+ Any aRet = OPropertySetHelper::queryInterface(rType);
+ return aRet.hasValue() ? aRet : ODatabaseMetaDataResultSet_BASE::queryInterface(rType);
+}
+
+Sequence< Type > SAL_CALL ODatabaseMetaDataResultSet::getTypes( )
+{
+ ::cppu::OTypeCollection aTypes( cppu::UnoType<css::beans::XMultiPropertySet>::get(),
+ cppu::UnoType<css::beans::XFastPropertySet>::get(),
+ cppu::UnoType<css::beans::XPropertySet>::get());
+
+ return ::comphelper::concatSequences(aTypes.getTypes(),ODatabaseMetaDataResultSet_BASE::getTypes());
+}
+
+void ODatabaseMetaDataResultSet::setRows(ORows&& _rRows)
+{
+ m_aRows = std::move(_rRows);
+ m_bBOF = true;
+ m_bEOF = m_aRows.empty();
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaDataResultSet::findColumn( const OUString& columnName )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed );
+
+
+ Reference< XResultSetMetaData > xMeta = getMetaData();
+ sal_Int32 nLen = xMeta->getColumnCount();
+ sal_Int32 i = 1;
+ for(;i<=nLen;++i)
+ {
+ if(xMeta->isCaseSensitive(i) ? columnName == xMeta->getColumnName(i) :
+ columnName.equalsIgnoreAsciiCase(xMeta->getColumnName(i))
+ )
+ return i;
+ }
+
+ ::dbtools::throwInvalidColumnException( columnName, *this );
+ O3TL_UNREACHABLE;
+}
+
+void ODatabaseMetaDataResultSet::checkIndex(sal_Int32 columnIndex )
+{
+ if(columnIndex < 1 || o3tl::make_unsigned(columnIndex) >= (*m_aRowsIter).size())
+ ::dbtools::throwInvalidIndexException(*this);
+}
+
+Reference< css::io::XInputStream > SAL_CALL ODatabaseMetaDataResultSet::getBinaryStream( sal_Int32 /*columnIndex*/ )
+{
+ return nullptr;
+}
+
+Reference< css::io::XInputStream > SAL_CALL ODatabaseMetaDataResultSet::getCharacterStream( sal_Int32 /*columnIndex*/ )
+{
+ return nullptr;
+}
+
+
+sal_Bool SAL_CALL ODatabaseMetaDataResultSet::getBoolean( sal_Int32 columnIndex )
+{
+ return getValue(columnIndex).getBool();
+}
+
+
+sal_Int8 SAL_CALL ODatabaseMetaDataResultSet::getByte( sal_Int32 columnIndex )
+{
+ return getValue(columnIndex).getInt8();
+}
+
+
+Sequence< sal_Int8 > SAL_CALL ODatabaseMetaDataResultSet::getBytes( sal_Int32 columnIndex )
+{
+ return getValue(columnIndex).getSequence();
+}
+
+
+css::util::Date SAL_CALL ODatabaseMetaDataResultSet::getDate( sal_Int32 columnIndex )
+{
+ return getValue(columnIndex).getDate();
+}
+
+
+double SAL_CALL ODatabaseMetaDataResultSet::getDouble( sal_Int32 columnIndex )
+{
+ return getValue(columnIndex).getDouble();
+}
+
+
+float SAL_CALL ODatabaseMetaDataResultSet::getFloat( sal_Int32 columnIndex )
+{
+ return getValue(columnIndex).getFloat();
+}
+
+
+sal_Int32 SAL_CALL ODatabaseMetaDataResultSet::getInt( sal_Int32 columnIndex )
+{
+ return getValue(columnIndex).getInt32();
+}
+
+
+sal_Int32 SAL_CALL ODatabaseMetaDataResultSet::getRow( )
+{
+ return 0;
+}
+
+
+sal_Int64 SAL_CALL ODatabaseMetaDataResultSet::getLong( sal_Int32 columnIndex )
+{
+ return getValue(columnIndex).getLong();
+}
+
+
+Reference< XResultSetMetaData > SAL_CALL ODatabaseMetaDataResultSet::getMetaData( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed );
+
+
+ if(!m_xMetaData.is())
+ m_xMetaData = new ODatabaseMetaDataResultSetMetaData();
+
+ return m_xMetaData;
+}
+
+Reference< XArray > SAL_CALL ODatabaseMetaDataResultSet::getArray( sal_Int32 /*columnIndex*/ )
+{
+ return nullptr;
+}
+
+
+Reference< XClob > SAL_CALL ODatabaseMetaDataResultSet::getClob( sal_Int32 /*columnIndex*/ )
+{
+ return nullptr;
+}
+
+Reference< XBlob > SAL_CALL ODatabaseMetaDataResultSet::getBlob( sal_Int32 /*columnIndex*/ )
+{
+ return nullptr;
+}
+
+
+Reference< XRef > SAL_CALL ODatabaseMetaDataResultSet::getRef( sal_Int32 /*columnIndex*/ )
+{
+ return nullptr;
+}
+
+
+Any SAL_CALL ODatabaseMetaDataResultSet::getObject( sal_Int32 columnIndex, const Reference< css::container::XNameAccess >& /*typeMap*/ )
+{
+ return getValue(columnIndex).makeAny();
+}
+
+
+sal_Int16 SAL_CALL ODatabaseMetaDataResultSet::getShort( sal_Int32 columnIndex )
+{
+ return getValue(columnIndex).getInt16();
+}
+
+
+OUString SAL_CALL ODatabaseMetaDataResultSet::getString( sal_Int32 columnIndex )
+{
+ return getValue(columnIndex).getString();
+}
+
+
+css::util::Time SAL_CALL ODatabaseMetaDataResultSet::getTime( sal_Int32 columnIndex )
+{
+ return getValue(columnIndex).getTime();
+}
+
+
+css::util::DateTime SAL_CALL ODatabaseMetaDataResultSet::getTimestamp( sal_Int32 columnIndex )
+{
+ return getValue(columnIndex).getDateTime();
+}
+
+
+sal_Bool SAL_CALL ODatabaseMetaDataResultSet::isAfterLast( )
+{
+ return m_bEOF;
+}
+
+
+sal_Bool SAL_CALL ODatabaseMetaDataResultSet::isFirst( )
+{
+ ::dbtools::throwFunctionSequenceException(*this);
+ O3TL_UNREACHABLE;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaDataResultSet::isLast( )
+{
+ ::dbtools::throwFunctionSequenceException(*this);
+ O3TL_UNREACHABLE;
+}
+
+
+void SAL_CALL ODatabaseMetaDataResultSet::beforeFirst( )
+{
+ ::dbtools::throwFunctionSequenceException(*this);
+}
+
+void SAL_CALL ODatabaseMetaDataResultSet::afterLast( )
+{
+ ::dbtools::throwFunctionSequenceException(*this);
+}
+
+
+void SAL_CALL ODatabaseMetaDataResultSet::close( )
+{
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed );
+
+ }
+ dispose();
+}
+
+
+sal_Bool SAL_CALL ODatabaseMetaDataResultSet::first( )
+{
+ ::dbtools::throwFunctionSequenceException(*this);
+ O3TL_UNREACHABLE;
+}
+
+
+sal_Bool SAL_CALL ODatabaseMetaDataResultSet::last( )
+{
+ ::dbtools::throwFunctionSequenceException(*this);
+ O3TL_UNREACHABLE;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaDataResultSet::absolute( sal_Int32 /*row*/ )
+{
+ ::dbtools::throwFunctionSequenceException(*this);
+ O3TL_UNREACHABLE;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaDataResultSet::relative( sal_Int32 /*row*/ )
+{
+ ::dbtools::throwFunctionSequenceException(*this);
+ O3TL_UNREACHABLE;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaDataResultSet::previous( )
+{
+ ::dbtools::throwFunctionSequenceException(*this);
+ O3TL_UNREACHABLE;
+}
+
+
+Reference< XInterface > SAL_CALL ODatabaseMetaDataResultSet::getStatement( )
+{
+ return m_aStatement.get();
+}
+
+
+sal_Bool SAL_CALL ODatabaseMetaDataResultSet::rowDeleted( )
+{
+ ::dbtools::throwFunctionSequenceException(*this);
+ O3TL_UNREACHABLE;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaDataResultSet::rowInserted( )
+{
+ ::dbtools::throwFunctionSequenceException(*this);
+ O3TL_UNREACHABLE;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaDataResultSet::rowUpdated( )
+{
+ ::dbtools::throwFunctionSequenceException(*this);
+ O3TL_UNREACHABLE;
+}
+
+
+sal_Bool SAL_CALL ODatabaseMetaDataResultSet::isBeforeFirst( )
+{
+ return m_bBOF;
+}
+
+
+sal_Bool SAL_CALL ODatabaseMetaDataResultSet::next( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed );
+
+ if ( m_bBOF )
+ {
+ m_aRowsIter = m_aRows.begin();
+ m_bBOF = false;
+ }
+ else
+ {
+ if ( m_bEOF )
+ throwFunctionSequenceException( *this );
+ else
+ if ( m_aRowsIter != m_aRows.end() )
+ ++m_aRowsIter;
+ }
+
+ bool bSuccess = m_aRowsIter != m_aRows.end();
+ if ( !bSuccess )
+ {
+ m_bEOF = true;
+ m_bBOF = m_aRows.empty();
+ }
+ return bSuccess;
+}
+
+
+sal_Bool SAL_CALL ODatabaseMetaDataResultSet::wasNull( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed );
+
+
+ if(m_aRowsIter == m_aRows.end() || !(*m_aRowsIter)[m_nColPos].is())
+ return true;
+
+ return (*m_aRowsIter)[m_nColPos]->getValue().isNull();
+}
+
+void SAL_CALL ODatabaseMetaDataResultSet::refreshRow( )
+{
+}
+
+
+void SAL_CALL ODatabaseMetaDataResultSet::cancel( )
+{
+}
+
+void SAL_CALL ODatabaseMetaDataResultSet::clearWarnings( )
+{
+}
+
+Any SAL_CALL ODatabaseMetaDataResultSet::getWarnings( )
+{
+ return Any();
+}
+
+::cppu::IPropertyArrayHelper* ODatabaseMetaDataResultSet::createArrayHelper( ) const
+{
+ Sequence< Property > aProps;
+ describeProperties(aProps);
+ return new ::cppu::OPropertyArrayHelper(aProps);
+}
+
+::cppu::IPropertyArrayHelper & ODatabaseMetaDataResultSet::getInfoHelper()
+{
+ return *getArrayHelper();
+}
+
+void ODatabaseMetaDataResultSet::setProceduresMap()
+{
+ rtl::Reference<ODatabaseMetaDataResultSetMetaData> pMetaData = new ODatabaseMetaDataResultSetMetaData();
+ pMetaData->setProceduresMap();
+ m_xMetaData = pMetaData;
+}
+
+void ODatabaseMetaDataResultSet::setCatalogsMap()
+{
+ rtl::Reference<ODatabaseMetaDataResultSetMetaData> pMetaData = new ODatabaseMetaDataResultSetMetaData();
+ pMetaData->setCatalogsMap();
+ m_xMetaData = pMetaData;
+}
+
+void ODatabaseMetaDataResultSet::setSchemasMap()
+{
+ rtl::Reference<ODatabaseMetaDataResultSetMetaData> pMetaData = new ODatabaseMetaDataResultSetMetaData();
+ pMetaData->setSchemasMap();
+ m_xMetaData = pMetaData;
+}
+
+void ODatabaseMetaDataResultSet::setColumnPrivilegesMap()
+{
+ rtl::Reference<ODatabaseMetaDataResultSetMetaData> pMetaData = new ODatabaseMetaDataResultSetMetaData();
+ pMetaData->setColumnPrivilegesMap();
+ m_xMetaData = pMetaData;
+}
+
+void ODatabaseMetaDataResultSet::setColumnsMap()
+{
+ rtl::Reference<ODatabaseMetaDataResultSetMetaData> pMetaData = new ODatabaseMetaDataResultSetMetaData();
+ pMetaData->setColumnsMap();
+ m_xMetaData = pMetaData;
+}
+
+void ODatabaseMetaDataResultSet::setTablesMap()
+{
+ rtl::Reference<ODatabaseMetaDataResultSetMetaData> pMetaData = new ODatabaseMetaDataResultSetMetaData();
+ pMetaData->setTablesMap();
+ m_xMetaData = pMetaData;
+}
+
+void ODatabaseMetaDataResultSet::setProcedureColumnsMap()
+{
+ rtl::Reference<ODatabaseMetaDataResultSetMetaData> pMetaData = new ODatabaseMetaDataResultSetMetaData();
+ pMetaData->setProcedureColumnsMap();
+ m_xMetaData = pMetaData;
+}
+
+void ODatabaseMetaDataResultSet::setPrimaryKeysMap()
+{
+ rtl::Reference<ODatabaseMetaDataResultSetMetaData> pMetaData = new ODatabaseMetaDataResultSetMetaData();
+ pMetaData->setPrimaryKeysMap();
+ m_xMetaData = pMetaData;
+}
+
+void ODatabaseMetaDataResultSet::setIndexInfoMap()
+{
+ rtl::Reference<ODatabaseMetaDataResultSetMetaData> pMetaData = new ODatabaseMetaDataResultSetMetaData();
+ pMetaData->setIndexInfoMap();
+ m_xMetaData = pMetaData;
+}
+
+void ODatabaseMetaDataResultSet::setTablePrivilegesMap()
+{
+ rtl::Reference<ODatabaseMetaDataResultSetMetaData> pMetaData = new ODatabaseMetaDataResultSetMetaData();
+ pMetaData->setTablePrivilegesMap();
+ m_xMetaData = pMetaData;
+}
+
+void ODatabaseMetaDataResultSet::setCrossReferenceMap()
+{
+ rtl::Reference<ODatabaseMetaDataResultSetMetaData> pMetaData = new ODatabaseMetaDataResultSetMetaData();
+ pMetaData->setCrossReferenceMap();
+ m_xMetaData = pMetaData;
+}
+
+void ODatabaseMetaDataResultSet::setVersionColumnsMap()
+{
+ rtl::Reference<ODatabaseMetaDataResultSetMetaData> pMetaData = new ODatabaseMetaDataResultSetMetaData();
+ pMetaData->setVersionColumnsMap();
+ m_xMetaData = pMetaData;
+}
+
+void ODatabaseMetaDataResultSet::setBestRowIdentifierMap()
+{
+ rtl::Reference<ODatabaseMetaDataResultSetMetaData> pMetaData = new ODatabaseMetaDataResultSetMetaData();
+ pMetaData->setBestRowIdentifierMap();
+ m_xMetaData = pMetaData;
+}
+
+void ODatabaseMetaDataResultSet::setTypeInfoMap()
+{
+ rtl::Reference<ODatabaseMetaDataResultSetMetaData> pMetaData = new ODatabaseMetaDataResultSetMetaData();
+ pMetaData->setTypeInfoMap();
+ m_xMetaData = pMetaData;
+}
+
+void ODatabaseMetaDataResultSet::setUDTsMap()
+{
+ rtl::Reference<ODatabaseMetaDataResultSetMetaData> pMetaData = new ODatabaseMetaDataResultSetMetaData();
+ pMetaData->setUDTsMap();
+ m_xMetaData = pMetaData;
+}
+
+void ODatabaseMetaDataResultSet::setTableTypes()
+{
+ rtl::Reference<ODatabaseMetaDataResultSetMetaData> pMetaData = new ODatabaseMetaDataResultSetMetaData();
+ pMetaData->setTableTypes();
+ m_xMetaData = pMetaData;
+}
+
+void ODatabaseMetaDataResultSet::setExportedKeysMap()
+{
+ rtl::Reference<ODatabaseMetaDataResultSetMetaData> pMetaData = new ODatabaseMetaDataResultSetMetaData();
+ pMetaData->setExportedKeysMap();
+ m_xMetaData = pMetaData;
+}
+
+void ODatabaseMetaDataResultSet::setImportedKeysMap()
+{
+ rtl::Reference<ODatabaseMetaDataResultSetMetaData> pMetaData = new ODatabaseMetaDataResultSetMetaData();
+ pMetaData->setImportedKeysMap();
+ m_xMetaData = pMetaData;
+}
+
+Reference< css::beans::XPropertySetInfo > SAL_CALL ODatabaseMetaDataResultSet::getPropertySetInfo( )
+{
+ return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper());
+}
+
+ORowSetValueDecorator& ORowSetValueDecorator::operator=(const ORowSetValue& _aValue)
+{
+ m_aValue = _aValue;
+ return *this;
+}
+
+const ORowSetValue& ODatabaseMetaDataResultSet::getValue(sal_Int32 columnIndex)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed );
+
+ if ( isBeforeFirst() || isAfterLast() )
+ ::dbtools::throwFunctionSequenceException( *this );
+
+ checkIndex(columnIndex );
+ m_nColPos = columnIndex;
+
+ if(m_aRowsIter != m_aRows.end() && (*m_aRowsIter)[columnIndex].is())
+ return *(*m_aRowsIter)[columnIndex];
+ return m_aEmptyValue;
+}
+
+/// return an empty ORowSetValueDecorator
+ORowSetValueDecoratorRef const & ODatabaseMetaDataResultSet::getEmptyValue()
+{
+ static ORowSetValueDecoratorRef aEmptyValueRef = new ORowSetValueDecorator();
+ return aEmptyValueRef;
+}
+
+/// return an ORowSetValueDecorator with 0 as value
+ORowSetValueDecoratorRef const & ODatabaseMetaDataResultSet::get0Value()
+{
+ static ORowSetValueDecoratorRef a0ValueRef = new ORowSetValueDecorator(sal_Int32(0));
+ return a0ValueRef;
+}
+
+/// return an ORowSetValueDecorator with 1 as value
+ORowSetValueDecoratorRef const & ODatabaseMetaDataResultSet::get1Value()
+{
+ static ORowSetValueDecoratorRef a1ValueRef = new ORowSetValueDecorator(sal_Int32(1));
+ return a1ValueRef;
+}
+
+/// return an ORowSetValueDecorator with ColumnSearch::BASIC as value
+ORowSetValueDecoratorRef const & ODatabaseMetaDataResultSet::getBasicValue()
+{
+ static ORowSetValueDecoratorRef aValueRef = new ORowSetValueDecorator(ColumnSearch::BASIC);
+ return aValueRef;
+}
+
+ORowSetValueDecoratorRef const & ODatabaseMetaDataResultSet::getSelectValue()
+{
+ static ORowSetValueDecoratorRef aValueRef = new ORowSetValueDecorator(OUString("SELECT"));
+ return aValueRef;
+}
+
+ORowSetValueDecoratorRef const & ODatabaseMetaDataResultSet::getInsertValue()
+{
+ static ORowSetValueDecoratorRef aValueRef = new ORowSetValueDecorator(OUString("INSERT"));
+ return aValueRef;
+}
+
+ORowSetValueDecoratorRef const & ODatabaseMetaDataResultSet::getDeleteValue()
+{
+ static ORowSetValueDecoratorRef aValueRef = new ORowSetValueDecorator(OUString("DELETE"));
+ return aValueRef;
+}
+
+ORowSetValueDecoratorRef const & ODatabaseMetaDataResultSet::getUpdateValue()
+{
+ static ORowSetValueDecoratorRef aValueRef = new ORowSetValueDecorator(OUString("UPDATE"));
+ return aValueRef;
+}
+
+ORowSetValueDecoratorRef const & ODatabaseMetaDataResultSet::getCreateValue()
+{
+ static ORowSetValueDecoratorRef aValueRef = new ORowSetValueDecorator(OUString("CREATE"));
+ return aValueRef;
+}
+
+ORowSetValueDecoratorRef const & ODatabaseMetaDataResultSet::getReadValue()
+{
+ static ORowSetValueDecoratorRef aValueRef = new ORowSetValueDecorator(OUString("READ"));
+ return aValueRef;
+}
+
+ORowSetValueDecoratorRef const & ODatabaseMetaDataResultSet::getAlterValue()
+{
+ static ORowSetValueDecoratorRef aValueRef = new ORowSetValueDecorator(OUString("ALTER"));
+ return aValueRef;
+}
+
+ORowSetValueDecoratorRef const & ODatabaseMetaDataResultSet::getDropValue()
+{
+ static ORowSetValueDecoratorRef aValueRef = new ORowSetValueDecorator(OUString("DROP"));
+ return aValueRef;
+}
+
+ORowSetValueDecoratorRef const & ODatabaseMetaDataResultSet::getQuoteValue()
+{
+ static ORowSetValueDecoratorRef aValueRef = new ORowSetValueDecorator(OUString("'"));
+ return aValueRef;
+}
+
+void SAL_CALL ODatabaseMetaDataResultSet::initialize( const Sequence< Any >& _aArguments )
+{
+ if ( _aArguments.getLength() != 2 )
+ return;
+
+ sal_Int32 nResultSetType = 0;
+ if ( !(_aArguments[0] >>= nResultSetType))
+ return;
+
+ setType(static_cast<MetaDataResultSetType>(nResultSetType));
+ Sequence< Sequence<Any> > aRows;
+ if ( !(_aArguments[1] >>= aRows) )
+ return;
+
+ ORows aRowsToSet;
+ const Sequence<Any>* pRowsIter = aRows.getConstArray();
+ const Sequence<Any>* pRowsEnd = pRowsIter + aRows.getLength();
+ for (; pRowsIter != pRowsEnd;++pRowsIter)
+ {
+ ORow aRowToSet;
+ const Any* pRowIter = pRowsIter->getConstArray();
+ const Any* pRowEnd = pRowIter + pRowsIter->getLength();
+ for (; pRowIter != pRowEnd;++pRowIter)
+ {
+ ORowSetValueDecoratorRef aValue;
+ switch( pRowIter->getValueTypeClass() )
+ {
+ case TypeClass_BOOLEAN:
+ {
+ bool bValue = false;
+ *pRowIter >>= bValue;
+ aValue = new ORowSetValueDecorator(ORowSetValue(bValue));
+ }
+ break;
+ case TypeClass_BYTE:
+ {
+ sal_Int8 nValue(0);
+ *pRowIter >>= nValue;
+ aValue = new ORowSetValueDecorator(ORowSetValue(nValue));
+ }
+ break;
+ case TypeClass_SHORT:
+ case TypeClass_UNSIGNED_SHORT:
+ {
+ sal_Int16 nValue(0);
+ *pRowIter >>= nValue;
+ aValue = new ORowSetValueDecorator(ORowSetValue(nValue));
+ }
+ break;
+ case TypeClass_LONG:
+ case TypeClass_UNSIGNED_LONG:
+ {
+ sal_Int32 nValue(0);
+ *pRowIter >>= nValue;
+ aValue = new ORowSetValueDecorator(ORowSetValue(nValue));
+ }
+ break;
+ case TypeClass_HYPER:
+ case TypeClass_UNSIGNED_HYPER:
+ {
+ sal_Int64 nValue(0);
+ *pRowIter >>= nValue;
+ aValue = new ORowSetValueDecorator(ORowSetValue(nValue));
+ }
+ break;
+ case TypeClass_FLOAT:
+ {
+ float nValue(0.0);
+ *pRowIter >>= nValue;
+ aValue = new ORowSetValueDecorator(ORowSetValue(nValue));
+ }
+ break;
+ case TypeClass_DOUBLE:
+ {
+ double nValue(0.0);
+ *pRowIter >>= nValue;
+ aValue = new ORowSetValueDecorator(ORowSetValue(nValue));
+ }
+ break;
+ case TypeClass_STRING:
+ {
+ OUString sValue;
+ *pRowIter >>= sValue;
+ aValue = new ORowSetValueDecorator(ORowSetValue(sValue));
+ }
+ break;
+ default:
+ break;
+ }
+ aRowToSet.push_back(aValue);
+ }
+ aRowsToSet.push_back(aRowToSet);
+ } // for (; pRowsIter != pRowsEnd;++pRowsIter
+ setRows(std::move(aRowsToSet));
+}
+// XServiceInfo
+
+
+ OUString SAL_CALL ODatabaseMetaDataResultSet::getImplementationName( )
+ {
+ return "org.openoffice.comp.helper.DatabaseMetaDataResultSet";
+ }
+
+ sal_Bool SAL_CALL ODatabaseMetaDataResultSet::supportsService( const OUString& _rServiceName )
+ {
+ return cppu::supportsService(this, _rServiceName);
+ }
+
+ Sequence< OUString > SAL_CALL ODatabaseMetaDataResultSet::getSupportedServiceNames( )
+ {
+ return Sequence<OUString>{ "com.sun.star.sdbc.ResultSet" };
+ }
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+connectivity_dbtools_ODatabaseMetaDataResultSet_get_implementation(
+ css::uno::XComponentContext* , css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new ODatabaseMetaDataResultSet());
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/commontools/FDatabaseMetaDataResultSetMetaData.cxx b/connectivity/source/commontools/FDatabaseMetaDataResultSetMetaData.cxx
new file mode 100644
index 0000000000..561953a079
--- /dev/null
+++ b/connectivity/source/commontools/FDatabaseMetaDataResultSetMetaData.cxx
@@ -0,0 +1,357 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <FDatabaseMetaDataResultSetMetaData.hxx>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <com/sun/star/sdbc/ColumnValue.hpp>
+
+using namespace connectivity;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::lang;
+
+ODatabaseMetaDataResultSetMetaData::~ODatabaseMetaDataResultSetMetaData()
+{
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaDataResultSetMetaData::getColumnDisplaySize( sal_Int32 column )
+{
+ if((m_mColumnsIter = m_mColumns.find(column)) != m_mColumns.end())
+ return (*m_mColumnsIter).second.getColumnDisplaySize();
+
+ return 0;
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaDataResultSetMetaData::getColumnType( sal_Int32 column )
+{
+ if((m_mColumnsIter = m_mColumns.find(column)) != m_mColumns.end())
+ return (*m_mColumnsIter).second.getColumnType();
+ return 1;
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaDataResultSetMetaData::getColumnCount( )
+{
+ return m_mColumns.size();
+}
+
+sal_Bool SAL_CALL ODatabaseMetaDataResultSetMetaData::isCaseSensitive( sal_Int32 column )
+{
+ if((m_mColumnsIter = m_mColumns.find(column)) != m_mColumns.end())
+ return (*m_mColumnsIter).second.isCaseSensitive();
+ return true;
+}
+
+OUString SAL_CALL ODatabaseMetaDataResultSetMetaData::getSchemaName( sal_Int32 /*column*/ )
+{
+ return OUString();
+}
+
+OUString SAL_CALL ODatabaseMetaDataResultSetMetaData::getColumnName( sal_Int32 column )
+{
+ if((m_mColumnsIter = m_mColumns.find(column)) != m_mColumns.end())
+ return (*m_mColumnsIter).second.getColumnName();
+ return OUString();
+}
+
+OUString SAL_CALL ODatabaseMetaDataResultSetMetaData::getTableName( sal_Int32 column )
+{
+ if((m_mColumnsIter = m_mColumns.find(column)) != m_mColumns.end())
+ return (*m_mColumnsIter).second.getTableName();
+ return OUString();
+}
+
+OUString SAL_CALL ODatabaseMetaDataResultSetMetaData::getCatalogName( sal_Int32 /*column*/ )
+{
+ return OUString();
+}
+
+OUString SAL_CALL ODatabaseMetaDataResultSetMetaData::getColumnTypeName( sal_Int32 /*column*/ )
+{
+ return OUString();
+}
+
+OUString SAL_CALL ODatabaseMetaDataResultSetMetaData::getColumnLabel( sal_Int32 column )
+{
+ if((m_mColumnsIter = m_mColumns.find(column)) != m_mColumns.end())
+ return (*m_mColumnsIter).second.getColumnLabel();
+ return getColumnName(column);
+}
+
+OUString SAL_CALL ODatabaseMetaDataResultSetMetaData::getColumnServiceName( sal_Int32 /*column*/ )
+{
+ return OUString();
+}
+
+sal_Bool SAL_CALL ODatabaseMetaDataResultSetMetaData::isCurrency( sal_Int32 column )
+{
+ if((m_mColumnsIter = m_mColumns.find(column)) != m_mColumns.end())
+ return (*m_mColumnsIter).second.isCurrency();
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaDataResultSetMetaData::isAutoIncrement( sal_Int32 column )
+{
+ if((m_mColumnsIter = m_mColumns.find(column)) != m_mColumns.end())
+ return (*m_mColumnsIter).second.isAutoIncrement();
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaDataResultSetMetaData::isSigned( sal_Int32 column )
+{
+ if((m_mColumnsIter = m_mColumns.find(column)) != m_mColumns.end())
+ return (*m_mColumnsIter).second.isSigned();
+ return false;
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaDataResultSetMetaData::getPrecision( sal_Int32 column )
+{
+ if((m_mColumnsIter = m_mColumns.find(column)) != m_mColumns.end())
+ return (*m_mColumnsIter).second.getPrecision();
+ return 0;
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaDataResultSetMetaData::getScale( sal_Int32 column )
+{
+ if((m_mColumnsIter = m_mColumns.find(column)) != m_mColumns.end())
+ return (*m_mColumnsIter).second.getScale();
+
+ return 0;
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaDataResultSetMetaData::isNullable( sal_Int32 column )
+{
+ if((m_mColumnsIter = m_mColumns.find(column)) != m_mColumns.end())
+ return (*m_mColumnsIter).second.isNullable();
+
+ return sal_Int32(false);
+}
+
+sal_Bool SAL_CALL ODatabaseMetaDataResultSetMetaData::isSearchable( sal_Int32 column )
+{
+ if((m_mColumnsIter = m_mColumns.find(column)) != m_mColumns.end())
+ return (*m_mColumnsIter).second.isSearchable();
+ return true;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaDataResultSetMetaData::isReadOnly( sal_Int32 /*column*/ )
+{
+ return true;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaDataResultSetMetaData::isDefinitelyWritable( sal_Int32 /*column*/ )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaDataResultSetMetaData::isWritable( sal_Int32 column )
+{
+ return isDefinitelyWritable(column);
+}
+
+void ODatabaseMetaDataResultSetMetaData::setColumnPrivilegesMap()
+{
+ setColumnMap();
+ m_mColumns[5] = OColumn(OUString(),"GRANTOR", ColumnValue::NULLABLE, 3,3,0, DataType::VARCHAR);
+ m_mColumns[6] = OColumn(OUString(),"GRANTEE", ColumnValue::NULLABLE, 3,3,0, DataType::VARCHAR);
+ m_mColumns[7] = OColumn(OUString(),"PRIVILEGE", ColumnValue::NULLABLE, 3,3,0, DataType::VARCHAR);
+ m_mColumns[8] = OColumn(OUString(),"IS_GRANTABLE", ColumnValue::NULLABLE, 3,3,0, DataType::VARCHAR);
+}
+
+void ODatabaseMetaDataResultSetMetaData::setTableNameMap()
+{
+ m_mColumns[1] = OColumn(OUString(),"TABLE_CAT", ColumnValue::NULLABLE, 3,3,0, DataType::VARCHAR);
+ m_mColumns[2] = OColumn(OUString(),"TABLE_SCHEM", ColumnValue::NULLABLE, 3,3,0, DataType::VARCHAR);
+ m_mColumns[3] = OColumn(OUString(),"TABLE_NAME", ColumnValue::NO_NULLS, 3,3,0, DataType::VARCHAR);
+}
+
+void ODatabaseMetaDataResultSetMetaData::setColumnMap()
+{
+ setTableNameMap();
+ m_mColumns[4] = OColumn(OUString(),"COLUMN_NAME", ColumnValue::NO_NULLS, 3,3,0, DataType::VARCHAR);
+}
+
+void ODatabaseMetaDataResultSetMetaData::setColumnsMap()
+{
+ setColumnMap();
+
+ m_mColumns[5] = OColumn(OUString(),"DATA_TYPE", ColumnValue::NO_NULLS, 0,0,0, DataType::INTEGER);
+ m_mColumns[6] = OColumn(OUString(),"TYPE_NAME", ColumnValue::NO_NULLS, 0,0,0, DataType::VARCHAR);
+ m_mColumns[7] = OColumn(OUString(),"COLUMN_SIZE", ColumnValue::NO_NULLS, 3,3,0, DataType::INTEGER);
+ m_mColumns[8] = OColumn(OUString(),"BUFFER_LENGTH", ColumnValue::NULLABLE, 3,3,0, DataType::INTEGER);
+ m_mColumns[9] = OColumn(OUString(),"DECIMAL_DIGITS", ColumnValue::NO_NULLS, 0,0,0, DataType::INTEGER);
+ m_mColumns[10] = OColumn(OUString(),"NUM_PREC_RADIX", ColumnValue::NO_NULLS, 0,0,0, DataType::INTEGER);
+ m_mColumns[11] = OColumn(OUString(),"NULLABLE", ColumnValue::NO_NULLS, 1,1,0, DataType::INTEGER);
+ m_mColumns[12] = OColumn(OUString(),"REMARKS", ColumnValue::NULLABLE, 0,0,0, DataType::VARCHAR);
+ m_mColumns[13] = OColumn(OUString(),"COLUMN_DEF", ColumnValue::NULLABLE, 0,0,0, DataType::VARCHAR);
+ m_mColumns[14] = OColumn(OUString(),"SQL_DATA_TYPE", ColumnValue::NO_NULLS, 1,1,0, DataType::INTEGER);
+ m_mColumns[15] = OColumn(OUString(),"SQL_DATETIME_SUB", ColumnValue::NO_NULLS, 1,1,0, DataType::INTEGER);
+ m_mColumns[16] = OColumn(OUString(),"CHAR_OCTET_LENGTH", ColumnValue::NO_NULLS, 1,1,0, DataType::INTEGER);
+ m_mColumns[17] = OColumn(OUString(),"ORDINAL_POSITION", ColumnValue::NO_NULLS, 1,1,0, DataType::INTEGER);
+ m_mColumns[18] = OColumn(OUString(),"IS_NULLABLE", ColumnValue::NO_NULLS, 1,1,0, DataType::VARCHAR);
+}
+
+void ODatabaseMetaDataResultSetMetaData::setTablesMap()
+{
+ setTableNameMap();
+ m_mColumns[4] = OColumn(OUString(),"TABLE_TYPE", ColumnValue::NO_NULLS, 0,0,0, DataType::VARCHAR);
+ m_mColumns[5] = OColumn(OUString(),"REMARKS", ColumnValue::NULLABLE, 0,0,0, DataType::VARCHAR);
+}
+
+void ODatabaseMetaDataResultSetMetaData::setProcedureNameMap()
+{
+ m_mColumns[1] = OColumn(OUString(),"PROCEDURE_CAT", ColumnValue::NULLABLE, 0,0,0, DataType::VARCHAR);
+ m_mColumns[2] = OColumn(OUString(),"PROCEDURE_SCHEM", ColumnValue::NULLABLE, 0,0,0, DataType::VARCHAR);
+ m_mColumns[3] = OColumn(OUString(),"PROCEDURE_NAME", ColumnValue::NO_NULLS, 0,0,0, DataType::VARCHAR);
+}
+
+void ODatabaseMetaDataResultSetMetaData::setProcedureColumnsMap()
+{
+ setProcedureNameMap();
+ m_mColumns[4] = OColumn(OUString(),"COLUMN_NAME", ColumnValue::NO_NULLS, 0,0,0, DataType::VARCHAR);
+ m_mColumns[5] = OColumn(OUString(),"COLUMN_TYPE", ColumnValue::NO_NULLS, 0,0,0, DataType::INTEGER);
+ m_mColumns[6] = OColumn(OUString(),"DATA_TYPE", ColumnValue::NO_NULLS, 0,0,0, DataType::INTEGER);
+ m_mColumns[7] = OColumn(OUString(),"TYPE_NAME", ColumnValue::NULLABLE, 0,0,0, DataType::VARCHAR);
+ m_mColumns[8] = OColumn(OUString(),"PRECISION", ColumnValue::NO_NULLS, 0,0,0, DataType::INTEGER);
+ m_mColumns[9] = OColumn(OUString(),"LENGTH", ColumnValue::NO_NULLS, 0,0,0, DataType::INTEGER);
+ m_mColumns[10] = OColumn(OUString(),"SCALE", ColumnValue::NO_NULLS, 0,0,0, DataType::INTEGER);
+ m_mColumns[11] = OColumn(OUString(),"RADIX", ColumnValue::NO_NULLS, 0,0,0, DataType::INTEGER);
+ m_mColumns[12] = OColumn(OUString(),"NULLABLE", ColumnValue::NO_NULLS, 0,0,0, DataType::INTEGER);
+ m_mColumns[13] = OColumn(OUString(),"REMARKS", ColumnValue::NULLABLE, 0,0,0, DataType::VARCHAR);
+}
+
+void ODatabaseMetaDataResultSetMetaData::setPrimaryKeysMap()
+{
+ setColumnMap();
+ m_mColumns[5] = OColumn(OUString(),"KEY_SEQ", ColumnValue::NO_NULLS, 1,1,0, DataType::INTEGER);
+ m_mColumns[6] = OColumn(OUString(),"PK_NAME", ColumnValue::NULLABLE, 0,0,0, DataType::VARCHAR);
+}
+
+void ODatabaseMetaDataResultSetMetaData::setIndexInfoMap()
+{
+ setTableNameMap();
+ m_mColumns[4] = OColumn(OUString(),"NON_UNIQUE", ColumnValue::NO_NULLS, 1,1,0, DataType::BIT);
+ m_mColumns[5] = OColumn(OUString(),"INDEX_QUALIFIER", ColumnValue::NULLABLE, 0,0,0, DataType::VARCHAR);
+ m_mColumns[6] = OColumn(OUString(),"INDEX_NAME", ColumnValue::NULLABLE, 0,0,0, DataType::VARCHAR);
+ m_mColumns[7] = OColumn(OUString(),"TYPE", ColumnValue::NO_NULLS, 0,0,0, DataType::INTEGER);
+ m_mColumns[8] = OColumn(OUString(),"ORDINAL_POSITION", ColumnValue::NO_NULLS, 0,0,0, DataType::INTEGER);
+ m_mColumns[9] = OColumn(OUString(),"COLUMN_NAME", ColumnValue::NO_NULLS, 0,0,0, DataType::VARCHAR);
+ m_mColumns[10] = OColumn(OUString(),"ASC_OR_DESC", ColumnValue::NULLABLE, 0,0,0, DataType::VARCHAR);
+ m_mColumns[11] = OColumn(OUString(),"CARDINALITY", ColumnValue::NO_NULLS, 0,0,0, DataType::INTEGER);
+ m_mColumns[12] = OColumn(OUString(),"PAGES", ColumnValue::NO_NULLS, 0,0,0, DataType::INTEGER);
+ m_mColumns[13] = OColumn(OUString(),"FILTER_CONDITION", ColumnValue::NULLABLE, 0,0,0, DataType::VARCHAR);
+}
+
+void ODatabaseMetaDataResultSetMetaData::setTablePrivilegesMap()
+{
+ setTableNameMap();
+ m_mColumns[4] = OColumn(OUString(),"GRANTOR", ColumnValue::NULLABLE, 0,0,0, DataType::VARCHAR);
+ m_mColumns[5] = OColumn(OUString(),"GRANTEE", ColumnValue::NO_NULLS, 0,0,0, DataType::VARCHAR);
+ m_mColumns[6] = OColumn(OUString(),"PRIVILEGE", ColumnValue::NULLABLE, 0,0,0, DataType::VARCHAR);
+ m_mColumns[7] = OColumn(OUString(),"IS_GRANTABLE", ColumnValue::NULLABLE, 0,0,0, DataType::VARCHAR);
+}
+
+void ODatabaseMetaDataResultSetMetaData::setCrossReferenceMap()
+{
+ m_mColumns[1] = OColumn(OUString(),"PKTABLE_CAT", ColumnValue::NULLABLE, 0,0,0, DataType::VARCHAR);
+ m_mColumns[2] = OColumn(OUString(),"PKTABLE_SCHEM", ColumnValue::NULLABLE, 0,0,0, DataType::VARCHAR);
+ m_mColumns[3] = OColumn(OUString(),"PKTABLE_NAME", ColumnValue::NO_NULLS, 0,0,0, DataType::VARCHAR);
+ m_mColumns[4] = OColumn(OUString(),"PKCOLUMN_NAME", ColumnValue::NO_NULLS, 0,0,0, DataType::VARCHAR);
+ m_mColumns[5] = OColumn(OUString(),"FKTABLE_CAT", ColumnValue::NULLABLE, 0,0,0, DataType::VARCHAR);
+ m_mColumns[6] = OColumn(OUString(),"FKTABLE_SCHEM", ColumnValue::NULLABLE, 0,0,0, DataType::VARCHAR);
+ m_mColumns[7] = OColumn(OUString(),"FKTABLE_NAME", ColumnValue::NO_NULLS, 0,0,0, DataType::VARCHAR);
+ m_mColumns[8] = OColumn(OUString(),"FKCOLUMN_NAME", ColumnValue::NO_NULLS, 0,0,0, DataType::VARCHAR);
+
+ m_mColumns[9] = OColumn(OUString(),"KEY_SEQ", ColumnValue::NO_NULLS, 1,1,0, DataType::INTEGER);
+ m_mColumns[10] = OColumn(OUString(),"UPDATE_RULE", ColumnValue::NO_NULLS, 1,1,0, DataType::INTEGER);
+ m_mColumns[11] = OColumn(OUString(),"DELETE_RULE", ColumnValue::NO_NULLS, 1,1,0, DataType::INTEGER);
+ m_mColumns[12] = OColumn(OUString(),"FK_NAME", ColumnValue::NULLABLE, 0,0,0, DataType::VARCHAR);
+ m_mColumns[13] = OColumn(OUString(),"PK_NAME", ColumnValue::NULLABLE, 0,0,0, DataType::VARCHAR);
+ m_mColumns[14] = OColumn(OUString(),"DEFERRABILITY", ColumnValue::NO_NULLS, 1,1,0, DataType::INTEGER);
+}
+
+void ODatabaseMetaDataResultSetMetaData::setTypeInfoMap()
+{
+ m_mColumns[1] = OColumn(OUString(),"TYPE_NAME", ColumnValue::NO_NULLS, 0,0,0, DataType::VARCHAR);
+ m_mColumns[2] = OColumn(OUString(),"DATA_TYPE", ColumnValue::NO_NULLS, 1,1,0, DataType::INTEGER);
+ m_mColumns[3] = OColumn(OUString(),"PRECISION", ColumnValue::NO_NULLS, 1,1,0, DataType::INTEGER);
+ m_mColumns[4] = OColumn(OUString(),"LITERAL_PREFIX", ColumnValue::NULLABLE, 0,0,0, DataType::VARCHAR);
+ m_mColumns[5] = OColumn(OUString(),"LITERAL_SUFFIX", ColumnValue::NULLABLE, 0,0,0, DataType::VARCHAR);
+ m_mColumns[6] = OColumn(OUString(),"CREATE_PARAMS", ColumnValue::NULLABLE, 0,0,0, DataType::VARCHAR);
+ m_mColumns[7] = OColumn(OUString(),"NULLABLE", ColumnValue::NO_NULLS, 1,1,0, DataType::INTEGER);
+ m_mColumns[8] = OColumn(OUString(),"CASE_SENSITIVE", ColumnValue::NO_NULLS, 1,1,0, DataType::BIT);
+ m_mColumns[9] = OColumn(OUString(),"SEARCHABLE", ColumnValue::NO_NULLS, 1,1,0, DataType::INTEGER);
+ m_mColumns[10] = OColumn(OUString(),"UNSIGNED_ATTRIBUTE", ColumnValue::NO_NULLS, 1,1,0, DataType::BIT);
+ m_mColumns[11] = OColumn(OUString(),"FIXED_PREC_SCALE", ColumnValue::NO_NULLS, 1,1,0, DataType::BIT);
+ m_mColumns[12] = OColumn(OUString(),"AUTO_INCREMENT", ColumnValue::NO_NULLS, 1,1,0, DataType::BIT);
+ m_mColumns[13] = OColumn(OUString(),"LOCAL_TYPE_NAME", ColumnValue::NO_NULLS, 0,0,0, DataType::VARCHAR);
+ m_mColumns[14] = OColumn(OUString(),"MINIMUM_SCALE", ColumnValue::NO_NULLS, 0,0,0, DataType::INTEGER);
+ m_mColumns[15] = OColumn(OUString(),"MAXIMUM_SCALE", ColumnValue::NO_NULLS, 0,0,0, DataType::INTEGER);
+ m_mColumns[16] = OColumn(OUString(),"SQL_DATA_TYPE", ColumnValue::NO_NULLS, 1,1,0, DataType::INTEGER);
+ m_mColumns[17] = OColumn(OUString(),"SQL_DATETIME_SUB", ColumnValue::NO_NULLS, 1,1,0, DataType::INTEGER);
+ m_mColumns[18] = OColumn(OUString(),"NUM_PREC_RADIX", ColumnValue::NO_NULLS, 1,1,0, DataType::INTEGER);
+}
+
+void ODatabaseMetaDataResultSetMetaData::setProceduresMap()
+{
+ setProcedureNameMap();
+ m_mColumns[4] = OColumn(OUString(),"RESERVED1", ColumnValue::NULLABLE, 0,0,0, DataType::VARCHAR);
+ m_mColumns[5] = OColumn(OUString(),"RESERVED2", ColumnValue::NULLABLE, 0,0,0, DataType::VARCHAR);
+ m_mColumns[6] = OColumn(OUString(),"RESERVED3", ColumnValue::NULLABLE, 0,0,0, DataType::VARCHAR);
+ m_mColumns[7] = OColumn(OUString(),"REMARKS", ColumnValue::NULLABLE, 0,0,0, DataType::VARCHAR);
+ m_mColumns[8] = OColumn(OUString(),"PROCEDURE_TYPE", ColumnValue::NO_NULLS, 1,1,0, DataType::INTEGER);
+}
+
+void ODatabaseMetaDataResultSetMetaData::setTableTypes()
+{
+ m_mColumns[1] = OColumn(OUString(),"TABLE_TYPE", ColumnValue::NULLABLE, 0,0,0, DataType::VARCHAR);
+}
+
+void ODatabaseMetaDataResultSetMetaData::setCatalogsMap()
+{
+ m_mColumns[1] = OColumn(OUString(),"TABLE_CAT", ColumnValue::NULLABLE, 0,0,0, DataType::VARCHAR);
+}
+
+void ODatabaseMetaDataResultSetMetaData::setSchemasMap()
+{
+ m_mColumns[1] = OColumn(OUString(),"TABLE_SCHEM", ColumnValue::NULLABLE, 0,0,0, DataType::VARCHAR);
+}
+
+void ODatabaseMetaDataResultSetMetaData::setVersionColumnsMap()
+{
+ m_mColumns[1] = OColumn(OUString(),"SCOPE", ColumnValue::NO_NULLS, 0,0,0, DataType::INTEGER);
+ m_mColumns[2] = OColumn(OUString(),"COLUMN_NAME", ColumnValue::NO_NULLS, 0,0,0, DataType::VARCHAR);
+ m_mColumns[3] = OColumn(OUString(),"DATA_TYPE", ColumnValue::NO_NULLS, 0,0,0, DataType::INTEGER);
+ m_mColumns[4] = OColumn(OUString(),"TYPE_NAME", ColumnValue::NO_NULLS, 0,0,0, DataType::VARCHAR);
+ m_mColumns[5] = OColumn(OUString(),"COLUMN_SIZE", ColumnValue::NO_NULLS, 0,0,0, DataType::INTEGER);
+ m_mColumns[6] = OColumn(OUString(),"BUFFER_LENGTH", ColumnValue::NO_NULLS, 0,0,0, DataType::INTEGER);
+ m_mColumns[7] = OColumn(OUString(),"DECIMAL_DIGITS", ColumnValue::NULLABLE, 0,0,0, DataType::INTEGER);
+ m_mColumns[8] = OColumn(OUString(),"PSEUDO_COLUMN", ColumnValue::NO_NULLS, 0,0,0, DataType::INTEGER);
+}
+
+void ODatabaseMetaDataResultSetMetaData::setUDTsMap()
+{
+ m_mColumns[1] = OColumn(OUString(),"TYPE_CAT", ColumnValue::NULLABLE, 0,0,0, DataType::VARCHAR);
+ m_mColumns[2] = OColumn(OUString(),"TYPE_SCHEM", ColumnValue::NULLABLE, 0,0,0, DataType::VARCHAR);
+ m_mColumns[3] = OColumn(OUString(),"TYPE_NAME", ColumnValue::NO_NULLS, 0,0,0, DataType::VARCHAR);
+ m_mColumns[4] = OColumn(OUString(),"CLASS_NAME", ColumnValue::NO_NULLS, 0,0,0, DataType::VARCHAR);
+ m_mColumns[5] = OColumn(OUString(),"DATA_TYPE", ColumnValue::NO_NULLS, 0,0,0, DataType::VARCHAR);
+ m_mColumns[6] = OColumn(OUString(),"REMARKS", ColumnValue::NO_NULLS, 0,0,0, DataType::VARCHAR);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/commontools/FValue.cxx b/connectivity/source/commontools/FValue.cxx
new file mode 100644
index 0000000000..4ac0235ac4
--- /dev/null
+++ b/connectivity/source/commontools/FValue.cxx
@@ -0,0 +1,2473 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <string.h>
+#include <connectivity/FValue.hxx>
+#include <connectivity/dbconversion.hxx>
+#include <comphelper/extract.hxx>
+#include <com/sun/star/io/XInputStream.hpp>
+#include <com/sun/star/sdbc/XClob.hpp>
+#include <com/sun/star/sdbc/XBlob.hpp>
+#include <com/sun/star/sdb/XColumn.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <rtl/ustrbuf.hxx>
+#include <sal/log.hxx>
+#include <osl/diagnose.h>
+
+using namespace ::dbtools;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::util;
+using namespace ::com::sun::star::io;
+
+namespace connectivity
+{
+
+namespace {
+ bool isStorageCompatible(sal_Int32 _eType1, sal_Int32 _eType2)
+ {
+ bool bIsCompatible = true;
+
+ if (_eType1 != _eType2)
+ {
+ SAL_INFO( "connectivity.commontools", "ORowSetValue::isStorageCompatible _eType1 != _eType2" );
+ switch (_eType1)
+ {
+ case DataType::CHAR:
+ case DataType::VARCHAR:
+ case DataType::DECIMAL:
+ case DataType::NUMERIC:
+ case DataType::LONGVARCHAR:
+ bIsCompatible = (DataType::CHAR == _eType2)
+ || (DataType::VARCHAR == _eType2)
+ || (DataType::DECIMAL == _eType2)
+ || (DataType::NUMERIC == _eType2)
+ || (DataType::LONGVARCHAR == _eType2);
+ break;
+
+ case DataType::DOUBLE:
+ case DataType::REAL:
+ bIsCompatible = (DataType::DOUBLE == _eType2)
+ || (DataType::REAL == _eType2);
+ break;
+
+ case DataType::BINARY:
+ case DataType::VARBINARY:
+ case DataType::LONGVARBINARY:
+ bIsCompatible = (DataType::BINARY == _eType2)
+ || (DataType::VARBINARY == _eType2)
+ || (DataType::LONGVARBINARY == _eType2);
+ break;
+
+ case DataType::INTEGER:
+ bIsCompatible = (DataType::SMALLINT == _eType2)
+ || (DataType::TINYINT == _eType2)
+ || (DataType::BIT == _eType2)
+ || (DataType::BOOLEAN == _eType2);
+ break;
+ case DataType::SMALLINT:
+ bIsCompatible = (DataType::TINYINT == _eType2)
+ || (DataType::BIT == _eType2)
+ || (DataType::BOOLEAN == _eType2);
+ break;
+ case DataType::TINYINT:
+ bIsCompatible = (DataType::BIT == _eType2)
+ || (DataType::BOOLEAN == _eType2);
+ break;
+
+ case DataType::BLOB:
+ case DataType::CLOB:
+ case DataType::OBJECT:
+ bIsCompatible = (DataType::BLOB == _eType2)
+ || (DataType::CLOB == _eType2)
+ || (DataType::OBJECT == _eType2);
+ break;
+
+ default:
+ bIsCompatible = false;
+ }
+ }
+ return bIsCompatible;
+ }
+
+ bool isStorageComparable(sal_Int32 _eType1, sal_Int32 _eType2)
+ {
+ bool bIsComparable = true;
+
+ if (_eType1 != _eType2)
+ {
+ SAL_INFO( "connectivity.commontools", "ORowSetValue::isStorageCompatible _eType1 != _eType2" );
+ switch (_eType1)
+ {
+ case DataType::CHAR:
+ case DataType::VARCHAR:
+ case DataType::LONGVARCHAR:
+ bIsComparable = (DataType::CHAR == _eType2)
+ || (DataType::VARCHAR == _eType2)
+ || (DataType::LONGVARCHAR == _eType2);
+ break;
+
+ case DataType::DECIMAL:
+ case DataType::NUMERIC:
+ bIsComparable = (DataType::DECIMAL == _eType2)
+ || (DataType::NUMERIC == _eType2);
+ break;
+
+ case DataType::DOUBLE:
+ case DataType::REAL:
+ bIsComparable = (DataType::DOUBLE == _eType2)
+ || (DataType::REAL == _eType2);
+ break;
+
+ case DataType::BINARY:
+ case DataType::VARBINARY:
+ case DataType::LONGVARBINARY:
+ bIsComparable = (DataType::BINARY == _eType2)
+ || (DataType::VARBINARY == _eType2)
+ || (DataType::LONGVARBINARY == _eType2);
+ break;
+
+ case DataType::INTEGER:
+ bIsComparable = (DataType::SMALLINT == _eType2)
+ || (DataType::TINYINT == _eType2)
+ || (DataType::BIT == _eType2)
+ || (DataType::BOOLEAN == _eType2);
+ break;
+ case DataType::SMALLINT:
+ bIsComparable = (DataType::TINYINT == _eType2)
+ || (DataType::BIT == _eType2)
+ || (DataType::BOOLEAN == _eType2);
+ break;
+ case DataType::TINYINT:
+ bIsComparable = (DataType::BIT == _eType2)
+ || (DataType::BOOLEAN == _eType2);
+ break;
+
+ case DataType::BLOB:
+ case DataType::CLOB:
+ case DataType::OBJECT:
+ bIsComparable = (DataType::BLOB == _eType2)
+ || (DataType::CLOB == _eType2)
+ || (DataType::OBJECT == _eType2);
+ break;
+
+ default:
+ bIsComparable = false;
+ }
+ }
+ return bIsComparable;
+ }
+}
+
+void ORowSetValue::setTypeKind(sal_Int32 _eType)
+{
+ if ( !m_bNull && !isStorageCompatible(_eType, m_eTypeKind) )
+ {
+ switch(_eType)
+ {
+ case DataType::VARCHAR:
+ case DataType::CHAR:
+ case DataType::DECIMAL:
+ case DataType::NUMERIC:
+ case DataType::LONGVARCHAR:
+ (*this) = getString();
+ break;
+ case DataType::BIGINT:
+ {
+ sal_Int64 nVal(getLong());
+ sal_uInt64 nuVal(getULong());
+ if (nVal == 0 && nuVal != 0)
+ (*this) = nuVal;
+ else
+ (*this) = nVal;
+ break;
+ }
+
+ case DataType::FLOAT:
+ (*this) = getFloat();
+ break;
+ case DataType::DOUBLE:
+ case DataType::REAL:
+ (*this) = getDouble();
+ break;
+ case DataType::TINYINT:
+ (*this) = getInt8();
+ break;
+ case DataType::SMALLINT:
+ (*this) = getInt16();
+ break;
+ case DataType::INTEGER:
+ {
+ sal_Int32 nVal(getInt32());
+ sal_uInt32 nuVal(getUInt32());
+ if (nVal == 0 && nuVal != 0)
+ (*this) = nuVal;
+ else
+ (*this) = nVal;
+ break;
+ }
+ case DataType::BIT:
+ case DataType::BOOLEAN:
+ (*this) = getBool();
+ break;
+ case DataType::DATE:
+ (*this) = getDate();
+ break;
+ case DataType::TIME:
+ (*this) = getTime();
+ break;
+ case DataType::TIMESTAMP:
+ (*this) = getDateTime();
+ break;
+ case DataType::BINARY:
+ case DataType::VARBINARY:
+ case DataType::LONGVARBINARY:
+ (*this) = getSequence();
+ break;
+ case DataType::BLOB:
+ case DataType::CLOB:
+ case DataType::OBJECT:
+ case DataType::OTHER:
+ (*this) = makeAny();
+ break;
+ default:
+ (*this) = makeAny();
+ SAL_WARN( "connectivity.commontools","ORowSetValue::setTypeKind(): UNSUPPORTED TYPE!");
+ }
+ }
+
+ m_eTypeKind = _eType;
+}
+
+
+void ORowSetValue::free() noexcept
+{
+ if(m_bNull)
+ return;
+
+ switch(m_eTypeKind)
+ {
+ case DataType::CHAR:
+ case DataType::VARCHAR:
+ case DataType::DECIMAL:
+ case DataType::NUMERIC:
+ case DataType::LONGVARCHAR:
+ OSL_ENSURE(m_aValue.m_pString,"String pointer is null!");
+ rtl_uString_release(m_aValue.m_pString);
+ m_aValue.m_pString = nullptr;
+ break;
+ case DataType::DATE:
+ delete static_cast<css::util::Date*>(m_aValue.m_pValue);
+ m_aValue.m_pValue = nullptr;
+ break;
+ case DataType::TIME:
+ delete static_cast<css::util::Time*>(m_aValue.m_pValue);
+ m_aValue.m_pValue = nullptr;
+ break;
+ case DataType::TIMESTAMP:
+ delete static_cast<css::util::DateTime*>(m_aValue.m_pValue);
+ m_aValue.m_pValue = nullptr;
+ break;
+ case DataType::BINARY:
+ case DataType::VARBINARY:
+ case DataType::LONGVARBINARY:
+ delete static_cast<Sequence<sal_Int8>*>(m_aValue.m_pValue);
+ m_aValue.m_pValue = nullptr;
+ break;
+ case DataType::BLOB:
+ case DataType::CLOB:
+ case DataType::OBJECT:
+ delete static_cast<Any*>(m_aValue.m_pValue);
+ m_aValue.m_pValue = nullptr;
+ break;
+ case DataType::BIT:
+ case DataType::TINYINT:
+ case DataType::SMALLINT:
+ case DataType::INTEGER:
+ case DataType::BIGINT:
+ case DataType::BOOLEAN:
+ case DataType::FLOAT:
+ case DataType::DOUBLE:
+ case DataType::REAL:
+ break;
+ default:
+ if ( m_aValue.m_pValue )
+ {
+ delete static_cast<Any*>(m_aValue.m_pValue);
+ m_aValue.m_pValue = nullptr;
+ }
+ break;
+
+ }
+ m_bNull = true;
+}
+
+ORowSetValue& ORowSetValue::operator=(const ORowSetValue& _rRH)
+{
+ if(&_rRH == this)
+ return *this;
+
+ if ( m_eTypeKind != _rRH.m_eTypeKind || (_rRH.m_bNull && !m_bNull) || m_bSigned != _rRH.m_bSigned)
+ free();
+
+ m_bBound = _rRH.m_bBound;
+ m_eTypeKind = _rRH.m_eTypeKind;
+ m_bSigned = _rRH.m_bSigned;
+
+ if(m_bNull && !_rRH.m_bNull)
+ {
+ switch(_rRH.m_eTypeKind)
+ {
+ case DataType::CHAR:
+ case DataType::VARCHAR:
+ case DataType::DECIMAL:
+ case DataType::NUMERIC:
+ case DataType::LONGVARCHAR:
+ rtl_uString_acquire(_rRH.m_aValue.m_pString);
+ m_aValue.m_pString = _rRH.m_aValue.m_pString;
+ break;
+ case DataType::DATE:
+ m_aValue.m_pValue = new Date(*static_cast<Date*>(_rRH.m_aValue.m_pValue));
+ break;
+ case DataType::TIME:
+ m_aValue.m_pValue = new Time(*static_cast<Time*>(_rRH.m_aValue.m_pValue));
+ break;
+ case DataType::TIMESTAMP:
+ m_aValue.m_pValue = new DateTime(*static_cast<DateTime*>(_rRH.m_aValue.m_pValue));
+ break;
+ case DataType::BINARY:
+ case DataType::VARBINARY:
+ case DataType::LONGVARBINARY:
+ m_aValue.m_pValue = new Sequence<sal_Int8>(*static_cast<Sequence<sal_Int8>*>(_rRH.m_aValue.m_pValue));
+ break;
+ case DataType::BIT:
+ case DataType::BOOLEAN:
+ m_aValue.m_bBool = _rRH.m_aValue.m_bBool;
+ break;
+ case DataType::TINYINT:
+ if ( _rRH.m_bSigned )
+ m_aValue.m_nInt8 = _rRH.m_aValue.m_nInt8;
+ else
+ m_aValue.m_uInt8 = _rRH.m_aValue.m_uInt8;
+ break;
+ case DataType::SMALLINT:
+ if ( _rRH.m_bSigned )
+ m_aValue.m_nInt16 = _rRH.m_aValue.m_nInt16;
+ else
+ m_aValue.m_uInt16 = _rRH.m_aValue.m_uInt16;
+ break;
+ case DataType::INTEGER:
+ if ( _rRH.m_bSigned )
+ m_aValue.m_nInt32 = _rRH.m_aValue.m_nInt32;
+ else
+ m_aValue.m_uInt32 = _rRH.m_aValue.m_uInt32;
+ break;
+ case DataType::BIGINT:
+ if ( _rRH.m_bSigned )
+ m_aValue.m_nInt64 = _rRH.m_aValue.m_nInt64;
+ else
+ m_aValue.m_uInt64 = _rRH.m_aValue.m_uInt64;
+ break;
+ case DataType::FLOAT:
+ m_aValue.m_nFloat = _rRH.m_aValue.m_nFloat;
+ break;
+ case DataType::DOUBLE:
+ case DataType::REAL:
+ m_aValue.m_nDouble = _rRH.m_aValue.m_nDouble;
+ break;
+ default:
+ m_aValue.m_pValue = new Any(*static_cast<Any*>(_rRH.m_aValue.m_pValue));
+ }
+ }
+ else if(!_rRH.m_bNull)
+ {
+ switch(_rRH.m_eTypeKind)
+ {
+ case DataType::CHAR:
+ case DataType::VARCHAR:
+ case DataType::DECIMAL:
+ case DataType::NUMERIC:
+ case DataType::LONGVARCHAR:
+ (*this) = OUString(_rRH.m_aValue.m_pString);
+ break;
+ case DataType::DATE:
+ (*this) = *static_cast<Date*>(_rRH.m_aValue.m_pValue);
+ break;
+ case DataType::TIME:
+ (*this) = *static_cast<Time*>(_rRH.m_aValue.m_pValue);
+ break;
+ case DataType::TIMESTAMP:
+ (*this) = *static_cast<DateTime*>(_rRH.m_aValue.m_pValue);
+ break;
+ case DataType::BINARY:
+ case DataType::VARBINARY:
+ case DataType::LONGVARBINARY:
+ (*this) = *static_cast<Sequence<sal_Int8>*>(_rRH.m_aValue.m_pValue);
+ break;
+ case DataType::BIT:
+ case DataType::BOOLEAN:
+ m_aValue.m_bBool = _rRH.m_aValue.m_bBool;
+ break;
+ case DataType::TINYINT:
+ if ( _rRH.m_bSigned )
+ m_aValue.m_nInt8 = _rRH.m_aValue.m_nInt8;
+ else
+ m_aValue.m_uInt8 = _rRH.m_aValue.m_uInt8;
+ break;
+ case DataType::SMALLINT:
+ if ( _rRH.m_bSigned )
+ m_aValue.m_nInt16 = _rRH.m_aValue.m_nInt16;
+ else
+ m_aValue.m_uInt16 = _rRH.m_aValue.m_uInt16;
+ break;
+ case DataType::INTEGER:
+ if ( _rRH.m_bSigned )
+ m_aValue.m_nInt32 = _rRH.m_aValue.m_nInt32;
+ else
+ m_aValue.m_uInt32 = _rRH.m_aValue.m_uInt32;
+ break;
+ case DataType::BIGINT:
+ if ( _rRH.m_bSigned )
+ m_aValue.m_nInt64 = _rRH.m_aValue.m_nInt64;
+ else
+ m_aValue.m_uInt64 = _rRH.m_aValue.m_uInt64;
+ break;
+ case DataType::FLOAT:
+ m_aValue.m_nFloat = _rRH.m_aValue.m_nFloat;
+ break;
+ case DataType::DOUBLE:
+ case DataType::REAL:
+ m_aValue.m_nDouble = _rRH.m_aValue.m_nDouble;
+ break;
+ default:
+ *static_cast<Any*>(m_aValue.m_pValue) = *static_cast<Any*>(_rRH.m_aValue.m_pValue);
+ }
+ }
+
+ m_bNull = _rRH.m_bNull;
+ // OJ: BUGID: 96277
+ m_eTypeKind = _rRH.m_eTypeKind;
+
+ return *this;
+}
+
+ORowSetValue& ORowSetValue::operator=(ORowSetValue&& _rRH) noexcept
+{
+ if ( m_eTypeKind != _rRH.m_eTypeKind || !m_bNull)
+ free();
+ if(!_rRH.m_bNull)
+ {
+ m_aValue = _rRH.m_aValue;
+ memset(&_rRH.m_aValue, 0, sizeof(_rRH.m_aValue));
+ }
+ m_bBound = _rRH.m_bBound;
+ m_eTypeKind = _rRH.m_eTypeKind;
+ m_bSigned = _rRH.m_bSigned;
+ m_bNull = _rRH.m_bNull;
+ _rRH.m_bNull = true;
+ return *this;
+}
+
+
+ORowSetValue& ORowSetValue::operator=(const Date& _rRH)
+{
+ if(m_eTypeKind != DataType::DATE)
+ free();
+
+ if(m_bNull)
+ {
+ m_aValue.m_pValue = new Date(_rRH);
+ m_eTypeKind = DataType::DATE;
+ m_bNull = false;
+ }
+ else
+ *static_cast<Date*>(m_aValue.m_pValue) = _rRH;
+
+ return *this;
+}
+
+ORowSetValue& ORowSetValue::operator=(const css::util::Time& _rRH)
+{
+ if(m_eTypeKind != DataType::TIME)
+ free();
+
+ if(m_bNull)
+ {
+ m_aValue.m_pValue = new Time(_rRH);
+ m_eTypeKind = DataType::TIME;
+ m_bNull = false;
+ }
+ else
+ *static_cast<Time*>(m_aValue.m_pValue) = _rRH;
+
+ return *this;
+}
+
+ORowSetValue& ORowSetValue::operator=(const DateTime& _rRH)
+{
+ if(m_eTypeKind != DataType::TIMESTAMP)
+ free();
+ if(m_bNull)
+ {
+ m_aValue.m_pValue = new DateTime(_rRH);
+ m_eTypeKind = DataType::TIMESTAMP;
+ m_bNull = false;
+ }
+ else
+ *static_cast<DateTime*>(m_aValue.m_pValue) = _rRH;
+
+ return *this;
+}
+
+
+ORowSetValue& ORowSetValue::operator=(const OUString& _rRH)
+{
+ if(m_eTypeKind != DataType::VARCHAR || m_aValue.m_pString != _rRH.pData)
+ {
+ free();
+ m_bNull = false;
+
+ m_aValue.m_pString = _rRH.pData;
+ rtl_uString_acquire(m_aValue.m_pString);
+ m_eTypeKind = DataType::VARCHAR;
+ }
+
+ return *this;
+}
+
+
+ORowSetValue& ORowSetValue::operator=(double _rRH)
+{
+ if(m_eTypeKind != DataType::DOUBLE)
+ free();
+
+ m_aValue.m_nDouble = _rRH;
+ m_eTypeKind = DataType::DOUBLE;
+ m_bNull = false;
+
+ return *this;
+}
+
+ORowSetValue& ORowSetValue::operator=(float _rRH)
+{
+ if(m_eTypeKind != DataType::FLOAT)
+ free();
+
+ m_aValue.m_nFloat = _rRH;
+ m_eTypeKind = DataType::FLOAT;
+ m_bNull = false;
+
+ return *this;
+}
+
+
+ORowSetValue& ORowSetValue::operator=(sal_Int8 _rRH)
+{
+ if(m_eTypeKind != DataType::TINYINT )
+ free();
+
+ m_aValue.m_nInt8 = _rRH;
+ m_eTypeKind = DataType::TINYINT;
+ m_bNull = false;
+ m_bSigned = true;
+ return *this;
+}
+
+ORowSetValue& ORowSetValue::operator=(sal_Int16 _rRH)
+{
+ if(m_eTypeKind != DataType::SMALLINT )
+ free();
+
+ m_aValue.m_nInt16 = _rRH;
+ m_eTypeKind = DataType::SMALLINT;
+ m_bNull = false;
+ m_bSigned = true;
+
+ return *this;
+}
+
+
+ORowSetValue& ORowSetValue::operator=(sal_uInt16 _rRH)
+{
+ if(m_eTypeKind != DataType::SMALLINT )
+ free();
+
+ m_aValue.m_uInt16 = _rRH;
+ m_eTypeKind = DataType::SMALLINT;
+ m_bNull = false;
+ m_bSigned = false;
+
+ return *this;
+}
+
+
+ORowSetValue& ORowSetValue::operator=(sal_Int32 _rRH)
+{
+ if(m_eTypeKind != DataType::INTEGER )
+ free();
+
+ m_aValue.m_nInt32 = _rRH;
+
+ m_eTypeKind = DataType::INTEGER;
+ m_bNull = false;
+ m_bSigned = true;
+
+ return *this;
+}
+
+
+ORowSetValue& ORowSetValue::operator=(sal_uInt32 _rRH)
+{
+ if(m_eTypeKind != DataType::INTEGER )
+ free();
+
+ m_aValue.m_uInt32 = _rRH;
+
+ m_eTypeKind = DataType::INTEGER;
+ m_bNull = false;
+ m_bSigned = false;
+
+ return *this;
+}
+
+
+ORowSetValue& ORowSetValue::operator=(const bool _rRH)
+{
+ if(m_eTypeKind != DataType::BIT && DataType::BOOLEAN != m_eTypeKind )
+ free();
+
+ m_aValue.m_bBool = _rRH;
+ m_eTypeKind = DataType::BOOLEAN;
+ m_bNull = false;
+
+ return *this;
+}
+
+ORowSetValue& ORowSetValue::operator=(sal_Int64 _rRH)
+{
+ if ( DataType::BIGINT != m_eTypeKind)
+ free();
+
+ m_aValue.m_nInt64 = _rRH;
+ m_eTypeKind = DataType::BIGINT;
+ m_bNull = false;
+ m_bSigned = true;
+
+ return *this;
+}
+
+ORowSetValue& ORowSetValue::operator=(sal_uInt64 _rRH)
+{
+ if ( DataType::BIGINT != m_eTypeKind)
+ free();
+
+ m_aValue.m_uInt64 = _rRH;
+ m_eTypeKind = DataType::BIGINT;
+ m_bNull = false;
+ m_bSigned = false;
+
+ return *this;
+}
+
+ORowSetValue& ORowSetValue::operator=(const Sequence<sal_Int8>& _rRH)
+{
+ if (!isStorageCompatible(DataType::LONGVARBINARY,m_eTypeKind))
+ free();
+
+ if (m_bNull)
+ {
+ m_aValue.m_pValue = new Sequence<sal_Int8>(_rRH);
+ }
+ else
+ *static_cast< Sequence< sal_Int8 >* >(m_aValue.m_pValue) = _rRH;
+
+ m_eTypeKind = DataType::LONGVARBINARY;
+ m_bNull = false;
+
+ return *this;
+}
+
+ORowSetValue& ORowSetValue::operator=(const Any& _rAny)
+{
+ if (!isStorageCompatible(DataType::OBJECT,m_eTypeKind))
+ free();
+
+ if ( m_bNull )
+ {
+ m_aValue.m_pValue = new Any(_rAny);
+ }
+ else
+ *static_cast<Any*>(m_aValue.m_pValue) = _rAny;
+
+ m_eTypeKind = DataType::OBJECT;
+ m_bNull = false;
+
+ return *this;
+}
+
+
+bool ORowSetValue::operator==(const ORowSetValue& _rRH) const
+{
+ if ( m_bNull != _rRH.isNull() )
+ return false;
+
+ if(m_bNull && _rRH.isNull())
+ return true;
+
+ if ( !isStorageComparable(m_eTypeKind, _rRH.m_eTypeKind ))
+ {
+ switch(m_eTypeKind)
+ {
+ case DataType::FLOAT:
+ case DataType::DOUBLE:
+ case DataType::REAL:
+ return getDouble() == _rRH.getDouble();
+ default:
+ switch(_rRH.m_eTypeKind)
+ {
+ case DataType::FLOAT:
+ case DataType::DOUBLE:
+ case DataType::REAL:
+ return getDouble() == _rRH.getDouble();
+ default:
+ break;
+ }
+ break;
+ }
+ return false;
+ }
+
+ bool bRet = false;
+ OSL_ENSURE(!m_bNull,"Should not be null!");
+ switch(m_eTypeKind)
+ {
+ case DataType::VARCHAR:
+ case DataType::CHAR:
+ case DataType::LONGVARCHAR:
+ {
+ OUString aVal1(m_aValue.m_pString);
+ OUString aVal2(_rRH.m_aValue.m_pString);
+ return aVal1 == aVal2;
+ }
+ default:
+ if ( m_bSigned != _rRH.m_bSigned )
+ return false;
+ break;
+ }
+
+ switch(m_eTypeKind)
+ {
+ case DataType::DECIMAL:
+ case DataType::NUMERIC:
+ {
+ OUString aVal1(m_aValue.m_pString);
+ OUString aVal2(_rRH.m_aValue.m_pString);
+ bRet = aVal1 == aVal2;
+ }
+ break;
+ case DataType::FLOAT:
+ bRet = m_aValue.m_nFloat == _rRH.m_aValue.m_nFloat;
+ break;
+ case DataType::DOUBLE:
+ case DataType::REAL:
+ bRet = m_aValue.m_nDouble == _rRH.m_aValue.m_nDouble;
+ break;
+ case DataType::TINYINT:
+ bRet = m_bSigned ? ( m_aValue.m_nInt8 == _rRH.m_aValue.m_nInt8 ) : (m_aValue.m_uInt8 == _rRH.m_aValue.m_uInt8);
+ break;
+ case DataType::SMALLINT:
+ bRet = m_bSigned ? ( m_aValue.m_nInt16 == _rRH.m_aValue.m_nInt16 ) : (m_aValue.m_uInt16 == _rRH.m_aValue.m_uInt16);
+ break;
+ case DataType::INTEGER:
+ bRet = m_bSigned ? ( m_aValue.m_nInt32 == _rRH.m_aValue.m_nInt32 ) : (m_aValue.m_uInt32 == _rRH.m_aValue.m_uInt32);
+ break;
+ case DataType::BIGINT:
+ bRet = m_bSigned ? ( m_aValue.m_nInt64 == _rRH.m_aValue.m_nInt64 ) : (m_aValue.m_uInt64 == _rRH.m_aValue.m_uInt64);
+ break;
+ case DataType::BIT:
+ case DataType::BOOLEAN:
+ bRet = m_aValue.m_bBool == _rRH.m_aValue.m_bBool;
+ break;
+ case DataType::DATE:
+ bRet = *static_cast<Date*>(m_aValue.m_pValue) == *static_cast<Date*>(_rRH.m_aValue.m_pValue);
+ break;
+ case DataType::TIME:
+ bRet = *static_cast<Time*>(m_aValue.m_pValue) == *static_cast<Time*>(_rRH.m_aValue.m_pValue);
+ break;
+ case DataType::TIMESTAMP:
+ bRet = *static_cast<DateTime*>(m_aValue.m_pValue) == *static_cast<DateTime*>(_rRH.m_aValue.m_pValue);
+ break;
+ case DataType::BINARY:
+ case DataType::VARBINARY:
+ case DataType::LONGVARBINARY:
+ bRet = false;
+ break;
+ case DataType::BLOB:
+ case DataType::CLOB:
+ case DataType::OBJECT:
+ case DataType::OTHER:
+ bRet = false;
+ break;
+ default:
+ bRet = false;
+ SAL_WARN( "connectivity.commontools","ORowSetValue::operator==(): UNSUPPORTED TYPE!");
+ break;
+ }
+ return bRet;
+}
+
+Any ORowSetValue::makeAny() const
+{
+ Any rValue;
+ if(isBound() && !isNull())
+ {
+ switch(getTypeKind())
+ {
+ case DataType::SQLNULL:
+ assert(rValue == Any());
+ break;
+ case DataType::CHAR:
+ case DataType::VARCHAR:
+ case DataType::DECIMAL:
+ case DataType::NUMERIC:
+ case DataType::LONGVARCHAR:
+ OSL_ENSURE(m_aValue.m_pString,"Value is null!");
+ rValue <<= OUString(m_aValue.m_pString);
+ break;
+ case DataType::FLOAT:
+ rValue <<= m_aValue.m_nFloat;
+ break;
+ case DataType::DOUBLE:
+ case DataType::REAL:
+ rValue <<= m_aValue.m_nDouble;
+ break;
+ case DataType::DATE:
+ OSL_ENSURE(m_aValue.m_pValue,"Value is null!");
+ rValue <<= *static_cast<Date*>(m_aValue.m_pValue);
+ break;
+ case DataType::TIME:
+ OSL_ENSURE(m_aValue.m_pValue,"Value is null!");
+ rValue <<= *static_cast<Time*>(m_aValue.m_pValue);
+ break;
+ case DataType::TIMESTAMP:
+ OSL_ENSURE(m_aValue.m_pValue,"Value is null!");
+ rValue <<= *static_cast<DateTime*>(m_aValue.m_pValue);
+ break;
+ case DataType::BINARY:
+ case DataType::VARBINARY:
+ case DataType::LONGVARBINARY:
+ OSL_ENSURE(m_aValue.m_pValue,"Value is null!");
+ rValue <<= *static_cast<Sequence<sal_Int8>*>(m_aValue.m_pValue);
+ break;
+ case DataType::BLOB:
+ case DataType::CLOB:
+ case DataType::OBJECT:
+ case DataType::OTHER:
+ rValue = getAny();
+ break;
+ case DataType::BIT:
+ case DataType::BOOLEAN:
+ rValue <<= m_aValue.m_bBool;
+ break;
+ case DataType::TINYINT:
+ if ( m_bSigned )
+ // TypeClass_BYTE
+ rValue <<= m_aValue.m_nInt8;
+ else
+ // There is no TypeClass_UNSIGNED_BYTE,
+ // so silently promote it to a 16-bit integer,
+ // that is TypeClass_UNSIGNED_SHORT
+ rValue <<= static_cast<sal_uInt16>(m_aValue.m_uInt8);
+ break;
+ case DataType::SMALLINT:
+ if ( m_bSigned )
+ // TypeClass_SHORT
+ rValue <<= m_aValue.m_nInt16;
+ else
+ // TypeClass_UNSIGNED_SHORT
+ rValue <<= m_aValue.m_uInt16;
+ break;
+ case DataType::INTEGER:
+ if ( m_bSigned )
+ // TypeClass_LONG
+ rValue <<= m_aValue.m_nInt32;
+ else
+ // TypeClass_UNSIGNED_LONG
+ rValue <<= m_aValue.m_uInt32;
+ break;
+ case DataType::BIGINT:
+ if ( m_bSigned )
+ // TypeClass_HYPER
+ rValue <<= m_aValue.m_nInt64;
+ else
+ // TypeClass_UNSIGNED_HYPER
+ rValue <<= m_aValue.m_uInt64;
+ break;
+ default:
+ SAL_WARN( "connectivity.commontools","ORowSetValue::makeAny(): UNSUPPORTED TYPE!");
+ rValue = getAny();
+ break;
+ }
+ }
+ return rValue;
+}
+
+OUString ORowSetValue::getString( ) const
+{
+ OUString aRet;
+ if(!m_bNull)
+ {
+ switch(getTypeKind())
+ {
+ case DataType::CHAR:
+ case DataType::VARCHAR:
+ case DataType::DECIMAL:
+ case DataType::NUMERIC:
+ case DataType::LONGVARCHAR:
+ aRet = m_aValue.m_pString;
+ break;
+ case DataType::FLOAT:
+ aRet = OUString::number(getFloat());
+ break;
+ case DataType::DOUBLE:
+ case DataType::REAL:
+ aRet = OUString::number(getDouble());
+ break;
+ case DataType::DATE:
+ aRet = DBTypeConversion::toDateString(getDate());
+ break;
+ case DataType::TIME:
+ aRet = DBTypeConversion::toTimeString(getTime());
+ break;
+ case DataType::TIMESTAMP:
+ aRet = DBTypeConversion::toDateTimeString(getDateTime());
+ break;
+ case DataType::BINARY:
+ case DataType::VARBINARY:
+ case DataType::LONGVARBINARY:
+ {
+ OUStringBuffer sVal("0x");
+ Sequence<sal_Int8> aSeq(getSequence());
+ const sal_Int8* pBegin = aSeq.getConstArray();
+ const sal_Int8* pEnd = pBegin + aSeq.getLength();
+ for(;pBegin != pEnd;++pBegin)
+ sVal.append(static_cast<sal_Int32>(*pBegin),16);
+ aRet = sVal.makeStringAndClear();
+ }
+ break;
+ case DataType::BIT:
+ aRet = OUString::number(int(getBool()));
+ break;
+ case DataType::BOOLEAN:
+ aRet = OUString::boolean(getBool());
+ break;
+ case DataType::TINYINT:
+ case DataType::SMALLINT:
+ case DataType::INTEGER:
+ if ( m_bSigned )
+ aRet = OUString::number(getInt32());
+ else
+ aRet = OUString::number(getUInt32());
+ break;
+ case DataType::BIGINT:
+ if ( m_bSigned )
+ aRet = OUString::number(getLong());
+ else
+ aRet = OUString::number(getULong());
+ break;
+ case DataType::CLOB:
+ {
+ Any aValue( getAny() );
+ Reference< XClob > xClob;
+ if ( (aValue >>= xClob) && xClob.is() )
+ {
+ aRet = xClob->getSubString(1,static_cast<sal_Int32>(xClob->length()) );
+ }
+ }
+ break;
+ default:
+ {
+ Any aValue = makeAny();
+ aValue >>= aRet;
+ break;
+ }
+ }
+ }
+ return aRet;
+}
+
+bool ORowSetValue::getBool() const
+{
+ bool bRet = false;
+ if(!m_bNull)
+ {
+ switch(getTypeKind())
+ {
+ case DataType::CHAR:
+ case DataType::VARCHAR:
+ case DataType::LONGVARCHAR:
+ {
+ const OUString sValue(m_aValue.m_pString);
+ if ( sValue.equalsIgnoreAsciiCase("true") || (sValue == "1") )
+ {
+ bRet = true;
+ break;
+ }
+ else if ( sValue.equalsIgnoreAsciiCase("false") || (sValue == "0") )
+ {
+ bRet = false;
+ break;
+ }
+ }
+ [[fallthrough]];
+ case DataType::DECIMAL:
+ case DataType::NUMERIC:
+
+ bRet = OUString::unacquired(&m_aValue.m_pString).toInt32() != 0;
+ break;
+ case DataType::FLOAT:
+ bRet = m_aValue.m_nFloat != 0.0;
+ break;
+ case DataType::DOUBLE:
+ case DataType::REAL:
+ bRet = m_aValue.m_nDouble != 0.0;
+ break;
+ case DataType::DATE:
+ case DataType::TIME:
+ case DataType::TIMESTAMP:
+ case DataType::BINARY:
+ case DataType::VARBINARY:
+ case DataType::LONGVARBINARY:
+ OSL_FAIL("getBool() for this type is not allowed!");
+ break;
+ case DataType::BIT:
+ case DataType::BOOLEAN:
+ bRet = m_aValue.m_bBool;
+ break;
+ case DataType::TINYINT:
+ bRet = m_bSigned ? (m_aValue.m_nInt8 != 0) : (m_aValue.m_uInt8 != 0);
+ break;
+ case DataType::SMALLINT:
+ bRet = m_bSigned ? (m_aValue.m_nInt16 != 0) : (m_aValue.m_uInt16 != 0);
+ break;
+ case DataType::INTEGER:
+ bRet = m_bSigned ? (m_aValue.m_nInt32 != 0) : (m_aValue.m_uInt32 != 0);
+ break;
+ case DataType::BIGINT:
+ bRet = m_bSigned ? (m_aValue.m_nInt64 != 0) : (m_aValue.m_uInt64 != 0);
+ break;
+ default:
+ {
+ Any aValue = makeAny();
+ aValue >>= bRet;
+ break;
+ }
+ }
+ }
+ return bRet;
+}
+
+
+sal_Int8 ORowSetValue::getInt8() const
+{
+ sal_Int8 nRet = 0;
+ if(!m_bNull)
+ {
+ switch(getTypeKind())
+ {
+ case DataType::CHAR:
+ case DataType::VARCHAR:
+ case DataType::DECIMAL:
+ case DataType::NUMERIC:
+ case DataType::LONGVARCHAR:
+ nRet = sal_Int8(OUString::unacquired(&m_aValue.m_pString).toInt32());
+ break;
+ case DataType::FLOAT:
+ nRet = sal_Int8(m_aValue.m_nFloat);
+ break;
+ case DataType::DOUBLE:
+ case DataType::REAL:
+ nRet = sal_Int8(m_aValue.m_nDouble);
+ break;
+ case DataType::DATE:
+ case DataType::TIME:
+ case DataType::TIMESTAMP:
+ case DataType::BINARY:
+ case DataType::VARBINARY:
+ case DataType::LONGVARBINARY:
+ case DataType::BLOB:
+ case DataType::CLOB:
+ OSL_FAIL("getInt8() for this type is not allowed!");
+ break;
+ case DataType::BIT:
+ case DataType::BOOLEAN:
+ nRet = sal_Int8(m_aValue.m_bBool);
+ break;
+ case DataType::TINYINT:
+ if ( m_bSigned )
+ nRet = m_aValue.m_nInt8;
+ else
+ nRet = static_cast<sal_Int8>(m_aValue.m_uInt8);
+ break;
+ case DataType::SMALLINT:
+ if ( m_bSigned )
+ nRet = static_cast<sal_Int8>(m_aValue.m_nInt16);
+ else
+ nRet = static_cast<sal_Int8>(m_aValue.m_uInt16);
+ break;
+ case DataType::INTEGER:
+ if ( m_bSigned )
+ nRet = static_cast<sal_Int8>(m_aValue.m_nInt32);
+ else
+ nRet = static_cast<sal_Int8>(m_aValue.m_uInt32);
+ break;
+ case DataType::BIGINT:
+ if ( m_bSigned )
+ nRet = static_cast<sal_Int8>(m_aValue.m_nInt64);
+ else
+ nRet = static_cast<sal_Int8>(m_aValue.m_uInt64);
+ break;
+ default:
+ {
+ Any aValue = makeAny();
+ aValue >>= nRet;
+ break;
+ }
+ }
+ }
+ return nRet;
+}
+
+
+sal_uInt8 ORowSetValue::getUInt8() const
+{
+ sal_uInt8 nRet = 0;
+ if(!m_bNull)
+ {
+ switch(getTypeKind())
+ {
+ case DataType::CHAR:
+ case DataType::VARCHAR:
+ case DataType::DECIMAL:
+ case DataType::NUMERIC:
+ case DataType::LONGVARCHAR:
+ nRet = sal_uInt8(OUString::unacquired(&m_aValue.m_pString).toInt32());
+ break;
+ case DataType::FLOAT:
+ nRet = sal_uInt8(m_aValue.m_nFloat);
+ break;
+ case DataType::DOUBLE:
+ case DataType::REAL:
+ nRet = sal_uInt8(m_aValue.m_nDouble);
+ break;
+ case DataType::DATE:
+ case DataType::TIME:
+ case DataType::TIMESTAMP:
+ case DataType::BINARY:
+ case DataType::VARBINARY:
+ case DataType::LONGVARBINARY:
+ case DataType::BLOB:
+ case DataType::CLOB:
+ OSL_FAIL("getuInt8() for this type is not allowed!");
+ break;
+ case DataType::BIT:
+ case DataType::BOOLEAN:
+ nRet = int(m_aValue.m_bBool);
+ break;
+ case DataType::TINYINT:
+ if ( m_bSigned )
+ nRet = m_aValue.m_nInt8;
+ else
+ nRet = m_aValue.m_uInt8;
+ break;
+ case DataType::SMALLINT:
+ if ( m_bSigned )
+ nRet = static_cast<sal_uInt8>(m_aValue.m_nInt16);
+ else
+ nRet = static_cast<sal_uInt8>(m_aValue.m_uInt16);
+ break;
+ case DataType::INTEGER:
+ if ( m_bSigned )
+ nRet = static_cast<sal_uInt8>(m_aValue.m_nInt32);
+ else
+ nRet = static_cast<sal_uInt8>(m_aValue.m_uInt32);
+ break;
+ case DataType::BIGINT:
+ if ( m_bSigned )
+ nRet = static_cast<sal_uInt8>(m_aValue.m_nInt64);
+ else
+ nRet = static_cast<sal_uInt8>(m_aValue.m_uInt64);
+ break;
+ default:
+ {
+ Any aValue = makeAny();
+ // Cf. "There is no TypeClass_UNSIGNED_BYTE" in makeAny:
+ sal_uInt16 n;
+ if (aValue >>= n) {
+ nRet = static_cast<sal_uInt8>(n);
+ }
+ break;
+ }
+ }
+ }
+ return nRet;
+}
+
+
+sal_Int16 ORowSetValue::getInt16() const
+{
+ sal_Int16 nRet = 0;
+ if(!m_bNull)
+ {
+ switch(getTypeKind())
+ {
+ case DataType::CHAR:
+ case DataType::VARCHAR:
+ case DataType::DECIMAL:
+ case DataType::NUMERIC:
+ case DataType::LONGVARCHAR:
+ nRet = sal_Int16(OUString::unacquired(&m_aValue.m_pString).toInt32());
+ break;
+ case DataType::FLOAT:
+ nRet = sal_Int16(m_aValue.m_nFloat);
+ break;
+ case DataType::DOUBLE:
+ case DataType::REAL:
+ nRet = sal_Int16(m_aValue.m_nDouble);
+ break;
+ case DataType::DATE:
+ case DataType::TIME:
+ case DataType::TIMESTAMP:
+ case DataType::BINARY:
+ case DataType::VARBINARY:
+ case DataType::LONGVARBINARY:
+ case DataType::BLOB:
+ case DataType::CLOB:
+ OSL_FAIL("getInt16() for this type is not allowed!");
+ break;
+ case DataType::BIT:
+ case DataType::BOOLEAN:
+ nRet = sal_Int16(m_aValue.m_bBool);
+ break;
+ case DataType::TINYINT:
+ if ( m_bSigned )
+ nRet = m_aValue.m_nInt8;
+ else
+ nRet = m_aValue.m_uInt8;
+ break;
+ case DataType::SMALLINT:
+ if ( m_bSigned )
+ nRet = m_aValue.m_nInt16;
+ else
+ nRet = static_cast<sal_Int16>(m_aValue.m_uInt16);
+ break;
+ case DataType::INTEGER:
+ if ( m_bSigned )
+ nRet = static_cast<sal_Int16>(m_aValue.m_nInt32);
+ else
+ nRet = static_cast<sal_Int16>(m_aValue.m_uInt32);
+ break;
+ case DataType::BIGINT:
+ if ( m_bSigned )
+ nRet = static_cast<sal_Int16>(m_aValue.m_nInt64);
+ else
+ nRet = static_cast<sal_Int16>(m_aValue.m_uInt64);
+ break;
+ default:
+ {
+ Any aValue = makeAny();
+ aValue >>= nRet;
+ break;
+ }
+ }
+ }
+ return nRet;
+}
+
+
+sal_uInt16 ORowSetValue::getUInt16() const
+{
+ sal_uInt16 nRet = 0;
+ if(!m_bNull)
+ {
+ switch(getTypeKind())
+ {
+ case DataType::CHAR:
+ case DataType::VARCHAR:
+ case DataType::DECIMAL:
+ case DataType::NUMERIC:
+ case DataType::LONGVARCHAR:
+ nRet = sal_uInt16(OUString::unacquired(&m_aValue.m_pString).toInt32());
+ break;
+ case DataType::FLOAT:
+ nRet = sal_uInt16(m_aValue.m_nFloat);
+ break;
+ case DataType::DOUBLE:
+ case DataType::REAL:
+ nRet = sal_uInt16(m_aValue.m_nDouble);
+ break;
+ case DataType::DATE:
+ case DataType::TIME:
+ case DataType::TIMESTAMP:
+ case DataType::BINARY:
+ case DataType::VARBINARY:
+ case DataType::LONGVARBINARY:
+ case DataType::BLOB:
+ case DataType::CLOB:
+ OSL_FAIL("getuInt16() for this type is not allowed!");
+ break;
+ case DataType::BIT:
+ case DataType::BOOLEAN:
+ nRet = sal_uInt16(m_aValue.m_bBool);
+ break;
+ case DataType::TINYINT:
+ if ( m_bSigned )
+ nRet = m_aValue.m_nInt8;
+ else
+ nRet = m_aValue.m_uInt8;
+ break;
+ case DataType::SMALLINT:
+ if ( m_bSigned )
+ nRet = m_aValue.m_nInt16;
+ else
+ nRet = m_aValue.m_uInt16;
+ break;
+ case DataType::INTEGER:
+ if ( m_bSigned )
+ nRet = static_cast<sal_uInt16>(m_aValue.m_nInt32);
+ else
+ nRet = static_cast<sal_uInt16>(m_aValue.m_uInt32);
+ break;
+ case DataType::BIGINT:
+ if ( m_bSigned )
+ nRet = static_cast<sal_uInt16>(m_aValue.m_nInt64);
+ else
+ nRet = static_cast<sal_uInt16>(m_aValue.m_uInt64);
+ break;
+ default:
+ {
+ Any aValue = makeAny();
+ aValue >>= nRet;
+ break;
+ }
+ }
+ }
+ return nRet;
+}
+
+
+sal_Int32 ORowSetValue::getInt32() const
+{
+ sal_Int32 nRet = 0;
+ if(!m_bNull)
+ {
+ switch(getTypeKind())
+ {
+ case DataType::CHAR:
+ case DataType::VARCHAR:
+ case DataType::DECIMAL:
+ case DataType::NUMERIC:
+ case DataType::LONGVARCHAR:
+ nRet = OUString::unacquired(&m_aValue.m_pString).toInt32();
+ break;
+ case DataType::FLOAT:
+ nRet = sal_Int32(m_aValue.m_nFloat);
+ break;
+ case DataType::DOUBLE:
+ case DataType::REAL:
+ nRet = sal_Int32(m_aValue.m_nDouble);
+ break;
+ case DataType::DATE:
+ nRet = dbtools::DBTypeConversion::toDays(*static_cast<css::util::Date*>(m_aValue.m_pValue));
+ break;
+ case DataType::TIME:
+ case DataType::TIMESTAMP:
+ case DataType::BINARY:
+ case DataType::VARBINARY:
+ case DataType::LONGVARBINARY:
+ case DataType::BLOB:
+ case DataType::CLOB:
+ OSL_FAIL("getInt32() for this type is not allowed!");
+ break;
+ case DataType::BIT:
+ case DataType::BOOLEAN:
+ nRet = sal_Int32(m_aValue.m_bBool);
+ break;
+ case DataType::TINYINT:
+ if ( m_bSigned )
+ nRet = m_aValue.m_nInt8;
+ else
+ nRet = m_aValue.m_uInt8;
+ break;
+ case DataType::SMALLINT:
+ if ( m_bSigned )
+ nRet = m_aValue.m_nInt16;
+ else
+ nRet = m_aValue.m_uInt16;
+ break;
+ case DataType::INTEGER:
+ if ( m_bSigned )
+ nRet = m_aValue.m_nInt32;
+ else
+ nRet = static_cast<sal_Int32>(m_aValue.m_uInt32);
+ break;
+ case DataType::BIGINT:
+ if ( m_bSigned )
+ nRet = static_cast<sal_Int32>(m_aValue.m_nInt64);
+ else
+ nRet = static_cast<sal_Int32>(m_aValue.m_uInt64);
+ break;
+ default:
+ {
+ Any aValue = makeAny();
+ aValue >>= nRet;
+ break;
+ }
+ }
+ }
+ return nRet;
+}
+
+
+sal_uInt32 ORowSetValue::getUInt32() const
+{
+ sal_uInt32 nRet = 0;
+ if(!m_bNull)
+ {
+ switch(getTypeKind())
+ {
+ case DataType::CHAR:
+ case DataType::VARCHAR:
+ case DataType::DECIMAL:
+ case DataType::NUMERIC:
+ case DataType::LONGVARCHAR:
+ nRet = OUString::unacquired(&m_aValue.m_pString).toUInt32();
+ break;
+ case DataType::FLOAT:
+ nRet = sal_uInt32(m_aValue.m_nFloat);
+ break;
+ case DataType::DOUBLE:
+ case DataType::REAL:
+ nRet = sal_uInt32(m_aValue.m_nDouble);
+ break;
+ case DataType::DATE:
+ nRet = dbtools::DBTypeConversion::toDays(*static_cast<css::util::Date*>(m_aValue.m_pValue));
+ break;
+ case DataType::TIME:
+ case DataType::TIMESTAMP:
+ case DataType::BINARY:
+ case DataType::VARBINARY:
+ case DataType::LONGVARBINARY:
+ case DataType::BLOB:
+ case DataType::CLOB:
+ OSL_FAIL("getuInt32() for this type is not allowed!");
+ break;
+ case DataType::BIT:
+ case DataType::BOOLEAN:
+ nRet = sal_uInt32(m_aValue.m_bBool);
+ break;
+ case DataType::TINYINT:
+ if ( m_bSigned )
+ nRet = m_aValue.m_nInt8;
+ else
+ nRet = m_aValue.m_uInt8;
+ break;
+ case DataType::SMALLINT:
+ if ( m_bSigned )
+ nRet = m_aValue.m_nInt16;
+ else
+ nRet = m_aValue.m_uInt16;
+ break;
+ case DataType::INTEGER:
+ if ( m_bSigned )
+ nRet = m_aValue.m_nInt32;
+ else
+ nRet = m_aValue.m_uInt32;
+ break;
+ case DataType::BIGINT:
+ if ( m_bSigned )
+ nRet = static_cast<sal_uInt32>(m_aValue.m_nInt64);
+ else
+ nRet = static_cast<sal_uInt32>(m_aValue.m_uInt64);
+ break;
+ default:
+ {
+ Any aValue = makeAny();
+ aValue >>= nRet;
+ break;
+ }
+ }
+ }
+ return nRet;
+}
+
+
+sal_Int64 ORowSetValue::getLong() const
+{
+ sal_Int64 nRet = 0;
+ if(!m_bNull)
+ {
+ switch(getTypeKind())
+ {
+ case DataType::CHAR:
+ case DataType::VARCHAR:
+ case DataType::DECIMAL:
+ case DataType::NUMERIC:
+ case DataType::LONGVARCHAR:
+ nRet = OUString::unacquired(&m_aValue.m_pString).toInt64();
+ break;
+ case DataType::FLOAT:
+ nRet = sal_Int64(m_aValue.m_nFloat);
+ break;
+ case DataType::DOUBLE:
+ case DataType::REAL:
+ nRet = sal_Int64(m_aValue.m_nDouble);
+ break;
+ case DataType::DATE:
+ nRet = dbtools::DBTypeConversion::toDays(*static_cast<css::util::Date*>(m_aValue.m_pValue));
+ break;
+ case DataType::TIME:
+ case DataType::TIMESTAMP:
+ case DataType::BINARY:
+ case DataType::VARBINARY:
+ case DataType::LONGVARBINARY:
+ case DataType::BLOB:
+ case DataType::CLOB:
+ OSL_FAIL("getLong() for this type is not allowed!");
+ break;
+ case DataType::BIT:
+ case DataType::BOOLEAN:
+ nRet = sal_Int64(m_aValue.m_bBool);
+ break;
+ case DataType::TINYINT:
+ if ( m_bSigned )
+ nRet = m_aValue.m_nInt8;
+ else
+ nRet = m_aValue.m_uInt8;
+ break;
+ case DataType::SMALLINT:
+ if ( m_bSigned )
+ nRet = m_aValue.m_nInt16;
+ else
+ nRet = m_aValue.m_uInt16;
+ break;
+ case DataType::INTEGER:
+ if ( m_bSigned )
+ nRet = m_aValue.m_nInt32;
+ else
+ nRet = m_aValue.m_uInt32;
+ break;
+ case DataType::BIGINT:
+ if ( m_bSigned )
+ nRet = m_aValue.m_nInt64;
+ else
+ nRet = static_cast<sal_Int64>(m_aValue.m_uInt64);
+ break;
+ default:
+ {
+ Any aValue = makeAny();
+ aValue >>= nRet;
+ break;
+ }
+ }
+ }
+ return nRet;
+}
+
+
+sal_uInt64 ORowSetValue::getULong() const
+{
+ sal_uInt64 nRet = 0;
+ if(!m_bNull)
+ {
+ switch(getTypeKind())
+ {
+ case DataType::CHAR:
+ case DataType::VARCHAR:
+ case DataType::DECIMAL:
+ case DataType::NUMERIC:
+ case DataType::LONGVARCHAR:
+ nRet = OUString::unacquired(&m_aValue.m_pString).toUInt64();
+ break;
+ case DataType::FLOAT:
+ nRet = sal_uInt64(m_aValue.m_nFloat);
+ break;
+ case DataType::DOUBLE:
+ case DataType::REAL:
+ nRet = sal_uInt64(m_aValue.m_nDouble);
+ break;
+ case DataType::DATE:
+ nRet = dbtools::DBTypeConversion::toDays(*static_cast<css::util::Date*>(m_aValue.m_pValue));
+ break;
+ case DataType::TIME:
+ case DataType::TIMESTAMP:
+ case DataType::BINARY:
+ case DataType::VARBINARY:
+ case DataType::LONGVARBINARY:
+ case DataType::BLOB:
+ case DataType::CLOB:
+ OSL_FAIL("getULong() for this type is not allowed!");
+ break;
+ case DataType::BIT:
+ case DataType::BOOLEAN:
+ nRet = sal_uInt64(m_aValue.m_bBool);
+ break;
+ case DataType::TINYINT:
+ if ( m_bSigned )
+ nRet = m_aValue.m_nInt8;
+ else
+ nRet = m_aValue.m_uInt8;
+ break;
+ case DataType::SMALLINT:
+ if ( m_bSigned )
+ nRet = m_aValue.m_nInt16;
+ else
+ nRet = m_aValue.m_uInt16;
+ break;
+ case DataType::INTEGER:
+ if ( m_bSigned )
+ nRet = m_aValue.m_nInt32;
+ else
+ nRet = m_aValue.m_uInt32;
+ break;
+ case DataType::BIGINT:
+ if ( m_bSigned )
+ nRet = m_aValue.m_nInt64;
+ else
+ nRet = m_aValue.m_uInt64;
+ break;
+ default:
+ {
+ Any aValue = makeAny();
+ aValue >>= nRet;
+ break;
+ }
+ }
+ }
+ return nRet;
+}
+
+
+float ORowSetValue::getFloat() const
+{
+ float nRet = 0;
+ if(!m_bNull)
+ {
+ switch(getTypeKind())
+ {
+ case DataType::CHAR:
+ case DataType::VARCHAR:
+ case DataType::DECIMAL:
+ case DataType::NUMERIC:
+ case DataType::LONGVARCHAR:
+ nRet = OUString::unacquired(&m_aValue.m_pString).toFloat();
+ break;
+ case DataType::FLOAT:
+ nRet = m_aValue.m_nFloat;
+ break;
+ case DataType::DOUBLE:
+ case DataType::REAL:
+ nRet = static_cast<float>(m_aValue.m_nDouble);
+ break;
+ case DataType::DATE:
+ nRet = static_cast<float>(dbtools::DBTypeConversion::toDouble(*static_cast<css::util::Date*>(m_aValue.m_pValue)));
+ break;
+ case DataType::TIME:
+ nRet = static_cast<float>(dbtools::DBTypeConversion::toDouble(*static_cast<css::util::Time*>(m_aValue.m_pValue)));
+ break;
+ case DataType::TIMESTAMP:
+ nRet = static_cast<float>(dbtools::DBTypeConversion::toDouble(*static_cast<css::util::DateTime*>(m_aValue.m_pValue)));
+ break;
+ case DataType::BINARY:
+ case DataType::VARBINARY:
+ case DataType::LONGVARBINARY:
+ case DataType::BLOB:
+ case DataType::CLOB:
+ OSL_FAIL("getDouble() for this type is not allowed!");
+ break;
+ case DataType::BIT:
+ case DataType::BOOLEAN:
+ nRet = float(m_aValue.m_bBool);
+ break;
+ case DataType::TINYINT:
+ if ( m_bSigned )
+ nRet = m_aValue.m_nInt8;
+ else
+ nRet = m_aValue.m_uInt8;
+ break;
+ case DataType::SMALLINT:
+ if ( m_bSigned )
+ nRet = m_aValue.m_nInt16;
+ else
+ nRet = static_cast<float>(m_aValue.m_uInt16);
+ break;
+ case DataType::INTEGER:
+ if ( m_bSigned )
+ nRet = static_cast<float>(m_aValue.m_nInt32);
+ else
+ nRet = static_cast<float>(m_aValue.m_uInt32);
+ break;
+ case DataType::BIGINT:
+ if ( m_bSigned )
+ nRet = static_cast<float>(m_aValue.m_nInt64);
+ else
+ nRet = static_cast<float>(m_aValue.m_uInt64);
+ break;
+ default:
+ {
+ Any aValue = makeAny();
+ aValue >>= nRet;
+ break;
+ }
+ }
+ }
+ return nRet;
+}
+
+double ORowSetValue::getDouble() const
+{
+ double nRet = 0;
+ if(!m_bNull)
+ {
+ switch(getTypeKind())
+ {
+ case DataType::CHAR:
+ case DataType::VARCHAR:
+ case DataType::DECIMAL:
+ case DataType::NUMERIC:
+ case DataType::LONGVARCHAR:
+ nRet = OUString::unacquired(&m_aValue.m_pString).toDouble();
+ break;
+ case DataType::FLOAT:
+ nRet = m_aValue.m_nFloat;
+ break;
+ case DataType::DOUBLE:
+ case DataType::REAL:
+ nRet = m_aValue.m_nDouble;
+ break;
+ case DataType::DATE:
+ nRet = dbtools::DBTypeConversion::toDouble(*static_cast<css::util::Date*>(m_aValue.m_pValue));
+ break;
+ case DataType::TIME:
+ nRet = dbtools::DBTypeConversion::toDouble(*static_cast<css::util::Time*>(m_aValue.m_pValue));
+ break;
+ case DataType::TIMESTAMP:
+ nRet = dbtools::DBTypeConversion::toDouble(*static_cast<css::util::DateTime*>(m_aValue.m_pValue));
+ break;
+ case DataType::BINARY:
+ case DataType::VARBINARY:
+ case DataType::LONGVARBINARY:
+ case DataType::BLOB:
+ case DataType::CLOB:
+ OSL_FAIL("getDouble() for this type is not allowed!");
+ break;
+ case DataType::BIT:
+ case DataType::BOOLEAN:
+ nRet = double(m_aValue.m_bBool);
+ break;
+ case DataType::TINYINT:
+ if ( m_bSigned )
+ nRet = m_aValue.m_nInt8;
+ else
+ nRet = m_aValue.m_uInt8;
+ break;
+ case DataType::SMALLINT:
+ if ( m_bSigned )
+ nRet = m_aValue.m_nInt16;
+ else
+ nRet = m_aValue.m_uInt16;
+ break;
+ case DataType::INTEGER:
+ if ( m_bSigned )
+ nRet = m_aValue.m_nInt32;
+ else
+ nRet = m_aValue.m_uInt32;
+ break;
+ case DataType::BIGINT:
+ if ( m_bSigned )
+ nRet = m_aValue.m_nInt64;
+ else
+ nRet = m_aValue.m_uInt64;
+ break;
+ default:
+ {
+ Any aValue = makeAny();
+ aValue >>= nRet;
+ break;
+ }
+ }
+ }
+ return nRet;
+}
+
+Sequence<sal_Int8> ORowSetValue::getSequence() const
+{
+ Sequence<sal_Int8> aSeq;
+ if (!m_bNull)
+ {
+ switch(m_eTypeKind)
+ {
+ case DataType::OBJECT:
+ case DataType::CLOB:
+ case DataType::BLOB:
+ {
+ Reference<XInputStream> xStream;
+ const Any aValue = makeAny();
+ if(aValue.hasValue())
+ {
+ Reference<XBlob> xBlob(aValue,UNO_QUERY);
+ if ( xBlob.is() )
+ xStream = xBlob->getBinaryStream();
+ else
+ {
+ Reference<XClob> xClob(aValue,UNO_QUERY);
+ if ( xClob.is() )
+ xStream = xClob->getCharacterStream();
+ }
+ if(xStream.is())
+ {
+ const sal_uInt32 nBytesToRead = 65535;
+ sal_uInt32 nRead;
+
+ do
+ {
+ css::uno::Sequence< sal_Int8 > aReadSeq;
+
+ nRead = xStream->readSomeBytes( aReadSeq, nBytesToRead );
+
+ if( nRead )
+ {
+ const sal_uInt32 nOldLength = aSeq.getLength();
+ aSeq.realloc( nOldLength + nRead );
+ memcpy( aSeq.getArray() + nOldLength, aReadSeq.getConstArray(), aReadSeq.getLength() );
+ }
+ }
+ while( nBytesToRead == nRead );
+ xStream->closeInput();
+ }
+ }
+ }
+ break;
+ case DataType::VARCHAR:
+ case DataType::LONGVARCHAR:
+ {
+ aSeq = Sequence<sal_Int8>(reinterpret_cast<const sal_Int8*>(m_aValue.m_pString->buffer),
+ sizeof(sal_Unicode) * m_aValue.m_pString->length);
+ }
+ break;
+ case DataType::BINARY:
+ case DataType::VARBINARY:
+ case DataType::LONGVARBINARY:
+ aSeq = *static_cast< Sequence<sal_Int8>*>(m_aValue.m_pValue);
+ break;
+ default:
+ {
+ Any aValue = makeAny();
+ aValue >>= aSeq;
+ break;
+ }
+ }
+ }
+ return aSeq;
+
+}
+
+css::util::Date ORowSetValue::getDate() const
+{
+ css::util::Date aValue;
+ if(!m_bNull)
+ {
+ switch(m_eTypeKind)
+ {
+ case DataType::CHAR:
+ case DataType::VARCHAR:
+ case DataType::LONGVARCHAR:
+ aValue = DBTypeConversion::toDate(getString());
+ break;
+ case DataType::DECIMAL:
+ case DataType::NUMERIC:
+ case DataType::FLOAT:
+ case DataType::DOUBLE:
+ case DataType::REAL:
+ aValue = DBTypeConversion::toDate(getDouble());
+ break;
+
+ case DataType::DATE:
+ aValue = *static_cast< css::util::Date*>(m_aValue.m_pValue);
+ break;
+ case DataType::TIMESTAMP:
+ {
+ css::util::DateTime* pDateTime = static_cast< css::util::DateTime*>(m_aValue.m_pValue);
+ aValue.Day = pDateTime->Day;
+ aValue.Month = pDateTime->Month;
+ aValue.Year = pDateTime->Year;
+ }
+ break;
+ case DataType::BIT:
+ case DataType::BOOLEAN:
+ case DataType::TINYINT:
+ case DataType::SMALLINT:
+ case DataType::INTEGER:
+ case DataType::BIGINT:
+ aValue = DBTypeConversion::toDate( double( getLong() ) );
+ break;
+
+ case DataType::BLOB:
+ case DataType::CLOB:
+ case DataType::OBJECT:
+ default:
+ OSL_ENSURE( false, "ORowSetValue::getDate: cannot retrieve the data!" );
+ [[fallthrough]];
+
+ case DataType::BINARY:
+ case DataType::VARBINARY:
+ case DataType::LONGVARBINARY:
+ case DataType::TIME:
+ aValue = DBTypeConversion::toDate( double(0) );
+ break;
+ }
+ }
+ return aValue;
+}
+
+css::util::Time ORowSetValue::getTime() const
+{
+ css::util::Time aValue;
+ if(!m_bNull)
+ {
+ switch(m_eTypeKind)
+ {
+ case DataType::CHAR:
+ case DataType::VARCHAR:
+ case DataType::LONGVARCHAR:
+ aValue = DBTypeConversion::toTime(getString());
+ break;
+ case DataType::DECIMAL:
+ case DataType::NUMERIC:
+ aValue = DBTypeConversion::toTime(getDouble());
+ break;
+ case DataType::FLOAT:
+ case DataType::DOUBLE:
+ case DataType::REAL:
+ aValue = DBTypeConversion::toTime(getDouble());
+ break;
+ case DataType::TIMESTAMP:
+ {
+ css::util::DateTime* pDateTime = static_cast< css::util::DateTime*>(m_aValue.m_pValue);
+ aValue.NanoSeconds = pDateTime->NanoSeconds;
+ aValue.Seconds = pDateTime->Seconds;
+ aValue.Minutes = pDateTime->Minutes;
+ aValue.Hours = pDateTime->Hours;
+ }
+ break;
+ case DataType::TIME:
+ aValue = *static_cast< css::util::Time*>(m_aValue.m_pValue);
+ break;
+ default:
+ {
+ Any aAnyValue = makeAny();
+ aAnyValue >>= aValue;
+ break;
+ }
+ }
+ }
+ return aValue;
+}
+
+css::util::DateTime ORowSetValue::getDateTime() const
+{
+ css::util::DateTime aValue;
+ if(!m_bNull)
+ {
+ switch(m_eTypeKind)
+ {
+ case DataType::CHAR:
+ case DataType::VARCHAR:
+ case DataType::LONGVARCHAR:
+ aValue = DBTypeConversion::toDateTime(getString());
+ break;
+ case DataType::DECIMAL:
+ case DataType::NUMERIC:
+ aValue = DBTypeConversion::toDateTime(getDouble());
+ break;
+ case DataType::FLOAT:
+ case DataType::DOUBLE:
+ case DataType::REAL:
+ aValue = DBTypeConversion::toDateTime(getDouble());
+ break;
+ case DataType::DATE:
+ {
+ css::util::Date* pDate = static_cast< css::util::Date*>(m_aValue.m_pValue);
+ aValue.Day = pDate->Day;
+ aValue.Month = pDate->Month;
+ aValue.Year = pDate->Year;
+ }
+ break;
+ case DataType::TIME:
+ {
+ css::util::Time* pTime = static_cast< css::util::Time*>(m_aValue.m_pValue);
+ aValue.NanoSeconds = pTime->NanoSeconds;
+ aValue.Seconds = pTime->Seconds;
+ aValue.Minutes = pTime->Minutes;
+ aValue.Hours = pTime->Hours;
+ }
+ break;
+ case DataType::TIMESTAMP:
+ aValue = *static_cast< css::util::DateTime*>(m_aValue.m_pValue);
+ break;
+ default:
+ {
+ Any aAnyValue = makeAny();
+ aAnyValue >>= aValue;
+ break;
+ }
+ }
+ }
+ return aValue;
+}
+
+void ORowSetValue::setSigned(bool _bMod)
+{
+ if ( m_bSigned == _bMod )
+ return;
+
+ m_bSigned = _bMod;
+ if ( m_bNull )
+ return;
+
+ sal_Int32 nType = m_eTypeKind;
+ switch(m_eTypeKind)
+ {
+ case DataType::TINYINT:
+ if ( m_bSigned )
+ (*this) = getInt8();
+ else
+ {
+ m_bSigned = !m_bSigned;
+ (*this) = getInt16();
+ m_bSigned = !m_bSigned;
+ }
+ break;
+ case DataType::SMALLINT:
+ if ( m_bSigned )
+ (*this) = getInt16();
+ else
+ {
+ m_bSigned = !m_bSigned;
+ (*this) = getInt32();
+ m_bSigned = !m_bSigned;
+ }
+ break;
+ case DataType::INTEGER:
+ if ( m_bSigned )
+ (*this) = getInt32();
+ else
+ {
+ m_bSigned = !m_bSigned;
+ (*this) = getLong();
+ m_bSigned = !m_bSigned;
+ }
+ break;
+ case DataType::BIGINT:
+ {
+ if ( m_bSigned )
+ {
+ auto nTmp = static_cast<sal_Int64>(m_aValue.m_uInt64);
+ m_aValue.m_nInt64 = nTmp;
+ }
+ else
+ {
+ auto nTmp = static_cast<sal_uInt64>(m_aValue.m_nInt64);
+ m_aValue.m_uInt64 = nTmp;
+ }
+ break;
+ }
+ }
+ m_eTypeKind = nType;
+}
+
+
+namespace detail
+{
+ class SAL_NO_VTABLE IValueSource
+ {
+ public:
+ virtual OUString getString() const = 0;
+ virtual bool getBoolean() const = 0;
+ virtual sal_Int8 getByte() const = 0;
+ virtual sal_Int16 getShort() const = 0;
+ virtual sal_Int32 getInt() const = 0;
+ virtual sal_Int64 getLong() const = 0;
+ virtual float getFloat() const = 0;
+ virtual double getDouble() const = 0;
+ virtual Date getDate() const = 0;
+ virtual css::util::Time getTime() const = 0;
+ virtual DateTime getTimestamp() const = 0;
+ virtual Sequence< sal_Int8 > getBytes() const = 0;
+ virtual Reference< XBlob > getBlob() const = 0;
+ virtual Reference< XClob > getClob() const = 0;
+ virtual Any getObject() const = 0;
+ virtual bool wasNull() const = 0;
+
+ virtual ~IValueSource() { }
+ };
+
+ namespace {
+
+ class RowValue : public IValueSource
+ {
+ public:
+ RowValue( const Reference< XRow >& _xRow, const sal_Int32 _nPos )
+ :m_xRow( _xRow )
+ ,m_nPos( _nPos )
+ {
+ }
+
+ // IValueSource
+ virtual OUString getString() const override { return m_xRow->getString( m_nPos ); };
+ virtual bool getBoolean() const override { return m_xRow->getBoolean( m_nPos ); };
+ virtual sal_Int8 getByte() const override { return m_xRow->getByte( m_nPos ); };
+ virtual sal_Int16 getShort() const override { return m_xRow->getShort( m_nPos ); }
+ virtual sal_Int32 getInt() const override { return m_xRow->getInt( m_nPos ); }
+ virtual sal_Int64 getLong() const override { return m_xRow->getLong( m_nPos ); }
+ virtual float getFloat() const override { return m_xRow->getFloat( m_nPos ); };
+ virtual double getDouble() const override { return m_xRow->getDouble( m_nPos ); };
+ virtual Date getDate() const override { return m_xRow->getDate( m_nPos ); };
+ virtual css::util::Time getTime() const override { return m_xRow->getTime( m_nPos ); };
+ virtual DateTime getTimestamp() const override { return m_xRow->getTimestamp( m_nPos ); };
+ virtual Sequence< sal_Int8 > getBytes() const override { return m_xRow->getBytes( m_nPos ); };
+ virtual Reference< XBlob > getBlob() const override { return m_xRow->getBlob( m_nPos ); };
+ virtual Reference< XClob > getClob() const override { return m_xRow->getClob( m_nPos ); };
+ virtual Any getObject() const override { return m_xRow->getObject( m_nPos ,nullptr); };
+ virtual bool wasNull() const override { return m_xRow->wasNull( ); };
+
+ private:
+ const Reference< XRow > m_xRow;
+ const sal_Int32 m_nPos;
+ };
+
+ class ColumnValue : public IValueSource
+ {
+ public:
+ explicit ColumnValue( const Reference< XColumn >& _rxColumn )
+ :m_xColumn( _rxColumn )
+ {
+ }
+
+ // IValueSource
+ virtual OUString getString() const override { return m_xColumn->getString(); };
+ virtual bool getBoolean() const override { return m_xColumn->getBoolean(); };
+ virtual sal_Int8 getByte() const override { return m_xColumn->getByte(); };
+ virtual sal_Int16 getShort() const override { return m_xColumn->getShort(); }
+ virtual sal_Int32 getInt() const override { return m_xColumn->getInt(); }
+ virtual sal_Int64 getLong() const override { return m_xColumn->getLong(); }
+ virtual float getFloat() const override { return m_xColumn->getFloat(); };
+ virtual double getDouble() const override { return m_xColumn->getDouble(); };
+ virtual Date getDate() const override { return m_xColumn->getDate(); };
+ virtual css::util::Time getTime() const override { return m_xColumn->getTime(); };
+ virtual DateTime getTimestamp() const override { return m_xColumn->getTimestamp(); };
+ virtual Sequence< sal_Int8 > getBytes() const override { return m_xColumn->getBytes(); };
+ virtual Reference< XBlob > getBlob() const override { return m_xColumn->getBlob(); };
+ virtual Reference< XClob > getClob() const override { return m_xColumn->getClob(); };
+ virtual Any getObject() const override { return m_xColumn->getObject( nullptr ); };
+ virtual bool wasNull() const override { return m_xColumn->wasNull( ); };
+
+ private:
+ const Reference< XColumn > m_xColumn;
+ };
+
+ }
+}
+
+
+void ORowSetValue::fill( const sal_Int32 _nType, const Reference< XColumn >& _rxColumn )
+{
+ detail::ColumnValue aColumnValue( _rxColumn );
+ impl_fill( _nType, true, aColumnValue );
+}
+
+
+void ORowSetValue::fill( sal_Int32 _nPos, sal_Int32 _nType, bool _bNullable, const Reference< XRow>& _xRow )
+{
+ detail::RowValue aRowValue( _xRow, _nPos );
+ impl_fill( _nType, _bNullable, aRowValue );
+}
+
+
+void ORowSetValue::fill(sal_Int32 _nPos,
+ sal_Int32 _nType,
+ const css::uno::Reference< css::sdbc::XRow>& _xRow)
+{
+ fill(_nPos,_nType,true,_xRow);
+}
+
+
+void ORowSetValue::impl_fill( const sal_Int32 _nType, bool _bNullable, const detail::IValueSource& _rValueSource )
+{
+ switch(_nType)
+ {
+ case DataType::CHAR:
+ case DataType::VARCHAR:
+ case DataType::DECIMAL:
+ case DataType::NUMERIC:
+ case DataType::LONGVARCHAR:
+ (*this) = _rValueSource.getString();
+ break;
+ case DataType::BIGINT:
+ if ( isSigned() )
+ (*this) = _rValueSource.getLong();
+ else
+ // TODO: this is rather horrible performance-wise
+ // but fixing it needs extending the css::sdbc::XRow API
+ // to have a getULong(), and needs updating all drivers :-|
+ // When doing that, add getUByte, getUShort, getUInt for symmetry/completeness
+ (*this) = _rValueSource.getString().toUInt64();
+ break;
+ case DataType::FLOAT:
+ (*this) = _rValueSource.getFloat();
+ break;
+ case DataType::DOUBLE:
+ case DataType::REAL:
+ (*this) = _rValueSource.getDouble();
+ break;
+ case DataType::DATE:
+ (*this) = _rValueSource.getDate();
+ break;
+ case DataType::TIME:
+ (*this) = _rValueSource.getTime();
+ break;
+ case DataType::TIMESTAMP:
+ (*this) = _rValueSource.getTimestamp();
+ break;
+ case DataType::BINARY:
+ case DataType::VARBINARY:
+ case DataType::LONGVARBINARY:
+ (*this) = _rValueSource.getBytes();
+ break;
+ case DataType::BIT:
+ case DataType::BOOLEAN:
+ (*this) = _rValueSource.getBoolean();
+ break;
+ case DataType::TINYINT:
+ if ( isSigned() )
+ (*this) = _rValueSource.getByte();
+ else
+ (*this) = _rValueSource.getShort();
+ break;
+ case DataType::SMALLINT:
+ if ( isSigned() )
+ (*this) = _rValueSource.getShort();
+ else
+ (*this) = _rValueSource.getInt();
+ break;
+ case DataType::INTEGER:
+ if ( isSigned() )
+ (*this) = _rValueSource.getInt();
+ else
+ (*this) = _rValueSource.getLong();
+ break;
+ case DataType::CLOB:
+ (*this) = css::uno::Any(_rValueSource.getClob());
+ setTypeKind(DataType::CLOB);
+ break;
+ case DataType::BLOB:
+ (*this) = css::uno::Any(_rValueSource.getBlob());
+ setTypeKind(DataType::BLOB);
+ break;
+ case DataType::OTHER:
+ (*this) = _rValueSource.getObject();
+ setTypeKind(DataType::OTHER);
+ break;
+ default:
+ SAL_WARN( "connectivity.commontools", "ORowSetValue::fill: unsupported type!" );
+ (*this) = _rValueSource.getObject();
+ break;
+ }
+ if ( _bNullable && _rValueSource.wasNull() )
+ setNull();
+ setTypeKind(_nType);
+}
+
+void ORowSetValue::fill(const Any& _rValue)
+{
+ switch (_rValue.getValueType().getTypeClass())
+ {
+ case TypeClass_VOID:
+ setNull(); break;
+ case TypeClass_BOOLEAN:
+ {
+ bool bValue( false );
+ _rValue >>= bValue;
+ (*this) = bValue;
+ break;
+ }
+ case TypeClass_CHAR:
+ {
+ sal_Unicode aDummy(0);
+ _rValue >>= aDummy;
+ (*this) = OUString(aDummy);
+ break;
+ }
+ case TypeClass_STRING:
+ {
+ OUString sDummy;
+ _rValue >>= sDummy;
+ (*this) = sDummy;
+ break;
+ }
+ case TypeClass_FLOAT:
+ {
+ float aDummy(0.0);
+ _rValue >>= aDummy;
+ (*this) = aDummy;
+ break;
+ }
+ case TypeClass_DOUBLE:
+ {
+ double aDummy(0.0);
+ _rValue >>= aDummy;
+ (*this) = aDummy;
+ break;
+ }
+ case TypeClass_BYTE:
+ {
+ sal_Int8 aDummy(0);
+ _rValue >>= aDummy;
+ (*this) = aDummy;
+ break;
+ }
+ case TypeClass_SHORT:
+ {
+ sal_Int16 aDummy(0);
+ _rValue >>= aDummy;
+ (*this) = aDummy;
+ break;
+ }
+ case TypeClass_UNSIGNED_SHORT:
+ {
+ sal_uInt16 nValue(0);
+ _rValue >>= nValue;
+ (*this) = nValue;
+ break;
+ }
+ case TypeClass_LONG:
+ {
+ sal_Int32 aDummy(0);
+ _rValue >>= aDummy;
+ (*this) = aDummy;
+ break;
+ }
+ case TypeClass_UNSIGNED_LONG:
+ {
+ sal_uInt32 nValue(0);
+ _rValue >>= nValue;
+ (*this) = static_cast<sal_Int64>(nValue);
+ setSigned(false);
+ break;
+ }
+ case TypeClass_HYPER:
+ {
+ sal_Int64 nValue(0);
+ _rValue >>= nValue;
+ (*this) = nValue;
+ break;
+ }
+ case TypeClass_UNSIGNED_HYPER:
+ {
+ sal_uInt64 nValue(0);
+ _rValue >>= nValue;
+ (*this) = nValue;
+ setSigned(false);
+ break;
+ }
+ case TypeClass_ENUM:
+ {
+ sal_Int32 enumValue( 0 );
+ ::cppu::enum2int( enumValue, _rValue );
+ (*this) = enumValue;
+ }
+ break;
+
+ case TypeClass_SEQUENCE:
+ {
+ Sequence<sal_Int8> aDummy;
+ if ( _rValue >>= aDummy )
+ (*this) = aDummy;
+ else
+ SAL_WARN( "connectivity.commontools", "ORowSetValue::fill: unsupported sequence type!" );
+ break;
+ }
+
+ case TypeClass_STRUCT:
+ {
+ css::util::Date aDate;
+ css::util::Time aTime;
+ css::util::DateTime aDateTime;
+ if ( _rValue >>= aDate )
+ {
+ (*this) = aDate;
+ }
+ else if ( _rValue >>= aTime )
+ {
+ (*this) = aTime;
+ }
+ else if ( _rValue >>= aDateTime )
+ {
+ (*this) = aDateTime;
+ }
+ else
+ SAL_WARN( "connectivity.commontools", "ORowSetValue::fill: unsupported structure!" );
+
+ break;
+ }
+ case TypeClass_INTERFACE:
+ {
+ Reference< XClob > xClob;
+ if ( _rValue >>= xClob )
+ {
+ (*this) = _rValue;
+ setTypeKind(DataType::CLOB);
+ }
+ else
+ {
+ Reference< XBlob > xBlob;
+ if ( _rValue >>= xBlob )
+ {
+ (*this) = _rValue;
+ setTypeKind(DataType::BLOB);
+ }
+ else
+ {
+ (*this) = _rValue;
+ }
+ }
+ }
+ break;
+
+ default:
+ SAL_WARN( "connectivity.commontools","Unknown type");
+ break;
+ }
+}
+
+} // namespace connectivity
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/commontools/ParameterSubstitution.cxx b/connectivity/source/commontools/ParameterSubstitution.cxx
new file mode 100644
index 0000000000..6fa5578080
--- /dev/null
+++ b/connectivity/source/commontools/ParameterSubstitution.cxx
@@ -0,0 +1,106 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#include <ParameterSubstitution.hxx>
+#include <connectivity/sqlparse.hxx>
+#include <comphelper/sequenceashashmap.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <utility>
+
+namespace connectivity
+{
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::sdbc;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star;
+
+ ParameterSubstitution::ParameterSubstitution(css::uno::Reference< css::uno::XComponentContext > _xContext ) : m_xContext(std::move(_xContext))
+ {
+ }
+ void SAL_CALL ParameterSubstitution::initialize( const uno::Sequence< uno::Any >& _aArguments )
+ {
+ ::osl::MutexGuard aGuard(m_aMutex);
+ comphelper::SequenceAsHashMap aArgs(_aArguments);
+ uno::Reference< sdbc::XConnection > xConnection;
+ xConnection = aArgs.getUnpackedValueOrDefault("ActiveConnection",xConnection);
+ m_xConnection = xConnection;
+ }
+
+ OUString SAL_CALL ParameterSubstitution::getImplementationName( )
+ {
+ return "org.openoffice.comp.helper.ParameterSubstitution";
+ }
+
+ sal_Bool SAL_CALL ParameterSubstitution::supportsService( const OUString& _rServiceName )
+ {
+ return cppu::supportsService(this, _rServiceName);
+ }
+
+ Sequence< OUString > SAL_CALL ParameterSubstitution::getSupportedServiceNames( )
+ {
+ return { "com.sun.star.sdb.ParameterSubstitution" };
+ }
+
+
+ OUString SAL_CALL ParameterSubstitution::substituteVariables( const OUString& _sText, sal_Bool /*bSubstRequired*/ )
+ {
+ OUString sRet = _sText;
+ uno::Reference< sdbc::XConnection > xConnection = m_xConnection;
+ if ( xConnection.is() )
+ {
+ try
+ {
+ OSQLParser aParser( m_xContext );
+ OUString sErrorMessage;
+ std::unique_ptr<OSQLParseNode> pNode = aParser.parseTree(sErrorMessage,_sText);
+ if(pNode)
+ { // special handling for parameters
+ OSQLParseNode::substituteParameterNames(pNode.get());
+ OUString sNewSql;
+ pNode->parseNodeToStr( sNewSql, xConnection );
+ sRet = sNewSql;
+ }
+ }
+ catch(const Exception&)
+ {
+ }
+ }
+ return sRet;
+ }
+
+ OUString SAL_CALL ParameterSubstitution::reSubstituteVariables( const OUString& _sText )
+ {
+ return _sText;
+ }
+
+ OUString SAL_CALL ParameterSubstitution::getSubstituteVariableValue( const OUString& /*variable*/ )
+ {
+ throw container::NoSuchElementException();
+ }
+
+
+} // connectivity
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+connectivity_dbtools_ParameterSubstitution_get_implementation(
+ css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new connectivity::ParameterSubstitution(context));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/commontools/RowFunctionParser.cxx b/connectivity/source/commontools/RowFunctionParser.cxx
new file mode 100644
index 0000000000..da4935dc61
--- /dev/null
+++ b/connectivity/source/commontools/RowFunctionParser.cxx
@@ -0,0 +1,442 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+// Makes parser a static resource,
+// we're synchronized externally.
+// But watch out, the parser might have
+// state not visible to this code!
+#define BOOST_SPIRIT_SINGLE_GRAMMAR_INSTANCE
+
+#if OSL_DEBUG_LEVEL >= 2 && defined(DBG_UTIL)
+#include <typeinfo>
+#define BOOST_SPIRIT_DEBUG
+#endif
+#include <boost/spirit/include/classic_core.hpp>
+#include <RowFunctionParser.hxx>
+#include <rtl/ustring.hxx>
+
+
+#if (OSL_DEBUG_LEVEL > 0)
+#include <iostream>
+#endif
+#include <algorithm>
+#include <stack>
+#include <utility>
+
+namespace connectivity
+{
+using namespace com::sun::star;
+
+namespace
+{
+
+
+// EXPRESSION NODES
+
+
+class ConstantValueExpression : public ExpressionNode
+{
+ ORowSetValueDecoratorRef maValue;
+
+public:
+
+ explicit ConstantValueExpression( ORowSetValueDecoratorRef aValue ) :
+ maValue(std::move( aValue ))
+ {
+ }
+ virtual ORowSetValueDecoratorRef evaluate(const ODatabaseMetaDataResultSet::ORow& /*_aRow*/ ) const override
+ {
+ return maValue;
+ }
+ virtual void fill(const ODatabaseMetaDataResultSet::ORow& /*_aRow*/ ) const override
+ {
+ }
+};
+
+
+/** ExpressionNode implementation for unary
+ function over two ExpressionNodes
+ */
+class BinaryFunctionExpression : public ExpressionNode
+{
+ const ExpressionFunct meFunct;
+ std::shared_ptr<ExpressionNode> mpFirstArg;
+ std::shared_ptr<ExpressionNode> mpSecondArg;
+
+public:
+
+ BinaryFunctionExpression( const ExpressionFunct eFunct, std::shared_ptr<ExpressionNode> xFirstArg, std::shared_ptr<ExpressionNode> xSecondArg ) :
+ meFunct( eFunct ),
+ mpFirstArg(std::move( xFirstArg )),
+ mpSecondArg(std::move( xSecondArg ))
+ {
+ }
+ virtual ORowSetValueDecoratorRef evaluate(const ODatabaseMetaDataResultSet::ORow& _aRow ) const override
+ {
+ ORowSetValueDecoratorRef aRet;
+ switch(meFunct)
+ {
+ case ExpressionFunct::Equation:
+ aRet = new ORowSetValueDecorator( ORowSetValue(mpFirstArg->evaluate(_aRow )->getValue() == mpSecondArg->evaluate(_aRow )->getValue()) );
+ break;
+ case ExpressionFunct::And:
+ aRet = new ORowSetValueDecorator( ORowSetValue(mpFirstArg->evaluate(_aRow )->getValue().getBool() && mpSecondArg->evaluate(_aRow )->getValue().getBool()) );
+ break;
+ case ExpressionFunct::Or:
+ aRet = new ORowSetValueDecorator( ORowSetValue(mpFirstArg->evaluate(_aRow )->getValue().getBool() || mpSecondArg->evaluate(_aRow )->getValue().getBool()) );
+ break;
+ default:
+ break;
+ }
+ return aRet;
+ }
+ virtual void fill(const ODatabaseMetaDataResultSet::ORow& _aRow ) const override
+ {
+ switch(meFunct)
+ {
+ case ExpressionFunct::Equation:
+ (*mpFirstArg->evaluate(_aRow )) = mpSecondArg->evaluate(_aRow )->getValue();
+ break;
+ default:
+ break;
+ }
+ }
+};
+
+
+// FUNCTION PARSER
+
+
+typedef const char* StringIteratorT;
+
+struct ParserContext
+{
+ typedef std::stack< std::shared_ptr<ExpressionNode> > OperandStack;
+
+ // stores a stack of not-yet-evaluated operands. This is used
+ // by the operators (i.e. '+', '*', 'sin' etc.) to pop their
+ // arguments from. If all arguments to an operator are constant,
+ // the operator pushes a precalculated result on the stack, and
+ // a composite ExpressionNode otherwise.
+ OperandStack maOperandStack;
+};
+
+typedef std::shared_ptr< ParserContext > ParserContextSharedPtr;
+
+/** Generate apriori constant value
+ */
+
+class ConstantFunctor
+{
+ ParserContextSharedPtr mpContext;
+
+public:
+
+ explicit ConstantFunctor( ParserContextSharedPtr xContext ) :
+ mpContext(std::move( xContext ))
+ {
+ }
+ void operator()( StringIteratorT rFirst,StringIteratorT rSecond) const
+ {
+ OUString sVal( rFirst, rSecond - rFirst, RTL_TEXTENCODING_UTF8 );
+ mpContext->maOperandStack.push( std::make_shared<ConstantValueExpression>( new ORowSetValueDecorator( sVal ) ) );
+ }
+};
+
+/** Generate parse-dependent-but-then-constant value
+ */
+class IntConstantFunctor
+{
+ ParserContextSharedPtr mpContext;
+
+public:
+ explicit IntConstantFunctor( ParserContextSharedPtr xContext ) :
+ mpContext(std::move( xContext ))
+ {
+ }
+ void operator()( sal_Int32 n ) const
+ {
+ mpContext->maOperandStack.push( std::make_shared<ConstantValueExpression>( new ORowSetValueDecorator( n ) ) );
+ }
+};
+
+/** Implements a binary function over two ExpressionNodes
+
+ @tpl Generator
+ Generator functor, to generate an ExpressionNode of
+ appropriate type
+
+ */
+class BinaryFunctionFunctor
+{
+ const ExpressionFunct meFunct;
+ ParserContextSharedPtr mpContext;
+
+public:
+
+ BinaryFunctionFunctor( const ExpressionFunct eFunct, ParserContextSharedPtr xContext ) :
+ meFunct( eFunct ),
+ mpContext(std::move( xContext ))
+ {
+ }
+
+ void operator()( StringIteratorT, StringIteratorT ) const
+ {
+ ParserContext::OperandStack& rNodeStack( mpContext->maOperandStack );
+
+ if( rNodeStack.size() < 2 )
+ throw ParseError( "Not enough arguments for binary operator" );
+
+ // retrieve arguments
+ std::shared_ptr<ExpressionNode> pSecondArg( std::move(rNodeStack.top()) );
+ rNodeStack.pop();
+ std::shared_ptr<ExpressionNode> pFirstArg( std::move(rNodeStack.top()) );
+ rNodeStack.pop();
+
+ // create combined ExpressionNode
+ auto pNode = std::make_shared<BinaryFunctionExpression>( meFunct, pFirstArg, pSecondArg );
+ // check for constness
+ rNodeStack.push( pNode );
+ }
+};
+/** ExpressionNode implementation for unary
+ function over one ExpressionNode
+ */
+class UnaryFunctionExpression : public ExpressionNode
+{
+ std::shared_ptr<ExpressionNode> mpArg;
+
+public:
+ explicit UnaryFunctionExpression( std::shared_ptr<ExpressionNode> xArg ) :
+ mpArg(std::move( xArg ))
+ {
+ }
+ virtual ORowSetValueDecoratorRef evaluate(const ODatabaseMetaDataResultSet::ORow& _aRow ) const override
+ {
+ return _aRow[mpArg->evaluate(_aRow )->getValue().getUInt32()];
+ }
+ virtual void fill(const ODatabaseMetaDataResultSet::ORow& /*_aRow*/ ) const override
+ {
+ }
+};
+
+class UnaryFunctionFunctor
+{
+ ParserContextSharedPtr mpContext;
+
+public:
+
+ explicit UnaryFunctionFunctor(ParserContextSharedPtr xContext)
+ : mpContext(std::move(xContext))
+ {
+ }
+ void operator()( StringIteratorT, StringIteratorT ) const
+ {
+
+ ParserContext::OperandStack& rNodeStack( mpContext->maOperandStack );
+
+ if( rNodeStack.empty() )
+ throw ParseError( "Not enough arguments for unary operator" );
+
+ // retrieve arguments
+ std::shared_ptr<ExpressionNode> pArg( std::move(rNodeStack.top()) );
+ rNodeStack.pop();
+
+ rNodeStack.push( std::make_shared<UnaryFunctionExpression>( pArg ) );
+ }
+};
+
+/* This class implements the following grammar (more or
+ less literally written down below, only slightly
+ obfuscated by the parser actions):
+
+ basic_expression =
+ number |
+ '(' additive_expression ')'
+
+ unary_expression =
+ basic_expression
+
+ multiplicative_expression =
+ unary_expression ( ( '*' unary_expression )* |
+ ( '/' unary_expression )* )
+
+ additive_expression =
+ multiplicative_expression ( ( '+' multiplicative_expression )* |
+ ( '-' multiplicative_expression )* )
+
+ */
+class ExpressionGrammar : public ::boost::spirit::classic::grammar< ExpressionGrammar >
+{
+public:
+ /** Create an arithmetic expression grammar
+
+ @param rParserContext
+ Contains context info for the parser
+ */
+ explicit ExpressionGrammar( ParserContextSharedPtr xParserContext ) :
+ mpParserContext(std::move( xParserContext ))
+ {
+ }
+
+ template< typename ScannerT > class definition
+ {
+ public:
+ // grammar definition
+ explicit definition( const ExpressionGrammar& self )
+ {
+ using ::boost::spirit::classic::space_p;
+ using ::boost::spirit::classic::range_p;
+ using ::boost::spirit::classic::lexeme_d;
+ using ::boost::spirit::classic::ch_p;
+ using ::boost::spirit::classic::int_p;
+ using ::boost::spirit::classic::as_lower_d;
+ using ::boost::spirit::classic::strlit;
+ using ::boost::spirit::classic::inhibit_case;
+
+
+ typedef inhibit_case<strlit<> > token_t;
+ token_t COLUMN = as_lower_d[ "column" ];
+ token_t OR_ = as_lower_d[ "or" ];
+ token_t AND_ = as_lower_d[ "and" ];
+
+ integer =
+ int_p
+ [IntConstantFunctor(self.getContext())];
+
+ argument =
+ integer
+ | lexeme_d[ +( range_p('a','z') | range_p('A','Z') | range_p('0','9') ) ]
+ [ ConstantFunctor(self.getContext()) ]
+ ;
+
+ unaryFunction =
+ (COLUMN >> '(' >> integer >> ')' )
+ [ UnaryFunctionFunctor( self.getContext()) ]
+ ;
+
+ assignment =
+ unaryFunction >> ch_p('=') >> argument
+ [ BinaryFunctionFunctor( ExpressionFunct::Equation, self.getContext()) ]
+ ;
+
+ andExpression =
+ assignment
+ | ( '(' >> orExpression >> ')' )
+ | ( assignment >> AND_ >> assignment ) [ BinaryFunctionFunctor( ExpressionFunct::And, self.getContext()) ]
+ ;
+
+ orExpression =
+ andExpression
+ | ( orExpression >> OR_ >> andExpression ) [ BinaryFunctionFunctor( ExpressionFunct::Or, self.getContext()) ]
+ ;
+
+ basicExpression =
+ orExpression
+ ;
+
+ BOOST_SPIRIT_DEBUG_RULE(basicExpression);
+ BOOST_SPIRIT_DEBUG_RULE(unaryFunction);
+ BOOST_SPIRIT_DEBUG_RULE(assignment);
+ BOOST_SPIRIT_DEBUG_RULE(argument);
+ BOOST_SPIRIT_DEBUG_RULE(integer);
+ BOOST_SPIRIT_DEBUG_RULE(orExpression);
+ BOOST_SPIRIT_DEBUG_RULE(andExpression);
+ }
+
+ const ::boost::spirit::classic::rule< ScannerT >& start() const
+ {
+ return basicExpression;
+ }
+
+ private:
+ // the constituents of the Spirit arithmetic expression grammar.
+ // For the sake of readability, without 'ma' prefix.
+ ::boost::spirit::classic::rule< ScannerT > basicExpression;
+ ::boost::spirit::classic::rule< ScannerT > unaryFunction;
+ ::boost::spirit::classic::rule< ScannerT > assignment;
+ ::boost::spirit::classic::rule< ScannerT > integer,argument;
+ ::boost::spirit::classic::rule< ScannerT > orExpression,andExpression;
+ };
+
+ const ParserContextSharedPtr& getContext() const
+ {
+ return mpParserContext;
+ }
+
+private:
+ ParserContextSharedPtr mpParserContext; // might get modified during parsing
+};
+
+const ParserContextSharedPtr& getParserContext()
+{
+ static ParserContextSharedPtr lcl_parserContext = std::make_shared<ParserContext>();
+
+ // clear node stack (since we reuse the static object, that's
+ // the whole point here)
+ while( !lcl_parserContext->maOperandStack.empty() )
+ lcl_parserContext->maOperandStack.pop();
+
+ return lcl_parserContext;
+}
+
+}
+
+std::shared_ptr<ExpressionNode> const & FunctionParser::parseFunction( const OUString& _sFunction)
+{
+ // TODO(Q1): Check if a combination of the RTL_UNICODETOTEXT_FLAGS_*
+ // gives better conversion robustness here (we might want to map space
+ // etc. to ASCII space here)
+ const OString& rAsciiFunction(
+ OUStringToOString( _sFunction, RTL_TEXTENCODING_ASCII_US ) );
+
+ StringIteratorT aStart( rAsciiFunction.getStr() );
+ StringIteratorT aEnd( rAsciiFunction.getStr()+rAsciiFunction.getLength() );
+
+ // static parser context, because the actual
+ // Spirit parser is also a static object
+ ParserContextSharedPtr pContext = getParserContext();
+
+ ExpressionGrammar aExpressionGrammer( pContext );
+
+ const ::boost::spirit::classic::parse_info<StringIteratorT> aParseInfo(
+ ::boost::spirit::classic::parse( aStart,
+ aEnd,
+ aExpressionGrammer,
+ ::boost::spirit::classic::space_p ) );
+
+#if (OSL_DEBUG_LEVEL > 0)
+ std::cout.flush(); // needed to keep stdout and cout in sync
+#endif
+
+ // input fully congested by the parser?
+ if( !aParseInfo.full )
+ throw ParseError( "RowFunctionParser::parseFunction(): string not fully parseable" );
+
+ // parser's state stack now must contain exactly _one_ ExpressionNode,
+ // which represents our formula.
+ if( pContext->maOperandStack.size() != 1 )
+ throw ParseError( "RowFunctionParser::parseFunction(): incomplete or empty expression" );
+
+ return pContext->maOperandStack.top();
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/commontools/TColumnsHelper.cxx b/connectivity/source/commontools/TColumnsHelper.cxx
new file mode 100644
index 0000000000..f81eca9f0a
--- /dev/null
+++ b/connectivity/source/commontools/TColumnsHelper.cxx
@@ -0,0 +1,208 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <connectivity/TColumnsHelper.hxx>
+#include <connectivity/sdbcx/VColumn.hxx>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <com/sun/star/sdbc/ColumnValue.hpp>
+#include <comphelper/types.hxx>
+#include <connectivity/dbtools.hxx>
+#include <TConnection.hxx>
+#include <connectivity/TTableHelper.hxx>
+
+using namespace ::comphelper;
+
+
+using namespace connectivity::sdbcx;
+using namespace connectivity;
+using namespace dbtools;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+
+namespace connectivity
+{
+ class OColumnsHelperImpl
+ {
+ public:
+ explicit OColumnsHelperImpl(bool _bCase)
+ : m_aColumnInfo(_bCase)
+ {
+ }
+ ColumnInformationMap m_aColumnInfo;
+ };
+}
+
+OColumnsHelper::OColumnsHelper( ::cppu::OWeakObject& _rParent
+ ,bool _bCase
+ ,::osl::Mutex& _rMutex
+ ,const ::std::vector< OUString> &_rVector
+ ,bool _bUseHardRef
+ ) : OCollection(_rParent,_bCase,_rMutex,_rVector,false,_bUseHardRef)
+ ,m_pTable(nullptr)
+{
+}
+
+OColumnsHelper::~OColumnsHelper()
+{
+}
+
+
+sdbcx::ObjectType OColumnsHelper::createObject(const OUString& _rName)
+{
+ OSL_ENSURE(m_pTable,"NO Table set. Error!");
+ Reference<XConnection> xConnection = m_pTable->getConnection();
+
+ if ( !m_pImpl )
+ m_pImpl.reset(new OColumnsHelperImpl(isCaseSensitive()));
+
+ bool bQueryInfo = true;
+ bool bAutoIncrement = false;
+ bool bIsCurrency = false;
+ sal_Int32 nDataType = DataType::OTHER;
+
+ ColumnInformationMap::const_iterator aFind = m_pImpl->m_aColumnInfo.find(_rName);
+ if ( aFind == m_pImpl->m_aColumnInfo.end() ) // we have to fill it
+ {
+ OUString sComposedName = ::dbtools::composeTableNameForSelect( xConnection, m_pTable );
+ collectColumnInformation(xConnection,sComposedName,u"*" ,m_pImpl->m_aColumnInfo);
+ aFind = m_pImpl->m_aColumnInfo.find(_rName);
+ }
+ if ( aFind != m_pImpl->m_aColumnInfo.end() )
+ {
+ bQueryInfo = false;
+ bAutoIncrement = aFind->second.first.first;
+ bIsCurrency = aFind->second.first.second;
+ nDataType = aFind->second.second;
+ } // if ( aFind != m_pImpl->m_aColumnInfo.end() )
+
+ sdbcx::ObjectType xRet;
+ const ColumnDesc* pColDesc = m_pTable->getColumnDescription(_rName);
+ if ( pColDesc )
+ {
+ Reference<XPropertySet> xPr = m_pTable;
+ const Reference<XNameAccess> xPrimaryKeyColumns = getPrimaryKeyColumns_throw(xPr);
+ sal_Int32 nField11 = pColDesc->nField11;
+ if ( nField11 != ColumnValue::NO_NULLS && xPrimaryKeyColumns.is() && xPrimaryKeyColumns->hasByName(_rName) )
+ {
+ nField11 = ColumnValue::NO_NULLS;
+ } // if ( xKeys.is() )
+ ::dbtools::OPropertyMap& rPropMap = OMetaConnection::getPropMap();
+ OUString aCatalog, aSchema, aTable;
+ m_pTable->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_CATALOGNAME)) >>= aCatalog;
+ m_pTable->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_SCHEMANAME)) >>= aSchema;
+ m_pTable->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_NAME)) >>= aTable;
+ rtl::Reference<connectivity::sdbcx::OColumn> pRet = new connectivity::sdbcx::OColumn(_rName,
+ pColDesc->aField6,
+ pColDesc->sField13,
+ pColDesc->sField12,
+ nField11,
+ pColDesc->nField7,
+ pColDesc->nField9,
+ pColDesc->nField5,
+ bAutoIncrement,
+ false,
+ bIsCurrency,
+ isCaseSensitive(),
+ aCatalog,
+ aSchema,
+ aTable);
+
+ xRet = pRet;
+ }
+ else
+ {
+
+ xRet = ::dbtools::createSDBCXColumn( m_pTable,
+ xConnection,
+ _rName,
+ isCaseSensitive(),
+ bQueryInfo,
+ bAutoIncrement,
+ bIsCurrency,
+ nDataType);
+ }
+ return xRet;
+}
+
+
+void OColumnsHelper::impl_refresh()
+{
+ if ( m_pTable )
+ {
+ m_pImpl->m_aColumnInfo.clear();
+ m_pTable->refreshColumns();
+ }
+}
+
+Reference< XPropertySet > OColumnsHelper::createDescriptor()
+{
+ return new OColumn(true);
+}
+
+// XAppend
+sdbcx::ObjectType OColumnsHelper::appendObject( const OUString& _rForName, const Reference< XPropertySet >& descriptor )
+{
+ ::osl::MutexGuard aGuard(m_rMutex);
+ OSL_ENSURE(m_pTable,"OColumnsHelper::appendByDescriptor: Table is null!");
+ if ( !m_pTable || m_pTable->isNew() )
+ return cloneDescriptor( descriptor );
+
+ Reference<XDatabaseMetaData> xMetaData = m_pTable->getConnection()->getMetaData();
+ OUString aSql = "ALTER TABLE " +
+ ::dbtools::composeTableName( xMetaData, m_pTable, ::dbtools::EComposeRule::InTableDefinitions, true ) +
+ " ADD " +
+ ::dbtools::createStandardColumnPart(descriptor,m_pTable->getConnection(),nullptr,m_pTable->getTypeCreatePattern());
+
+ Reference< XStatement > xStmt = m_pTable->getConnection()->createStatement( );
+ if ( xStmt.is() )
+ {
+ xStmt->execute(aSql);
+ ::comphelper::disposeComponent(xStmt);
+ }
+ return createObject( _rForName );
+}
+
+// XDrop
+void OColumnsHelper::dropObject(sal_Int32 /*_nPos*/, const OUString& _sElementName)
+{
+ OSL_ENSURE(m_pTable,"OColumnsHelper::dropByName: Table is null!");
+ if ( !m_pTable || m_pTable->isNew() )
+ return;
+
+ Reference<XDatabaseMetaData> xMetaData = m_pTable->getConnection()->getMetaData();
+ OUString aQuote = xMetaData->getIdentifierQuoteString( );
+ OUString aSql = "ALTER TABLE " +
+ ::dbtools::composeTableName( xMetaData, m_pTable, ::dbtools::EComposeRule::InTableDefinitions, true ) +
+ " DROP " +
+ ::dbtools::quoteName( aQuote,_sElementName);
+
+ Reference< XStatement > xStmt = m_pTable->getConnection()->createStatement( );
+ if ( xStmt.is() )
+ {
+ xStmt->execute(aSql);
+ ::comphelper::disposeComponent(xStmt);
+ }
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/commontools/TConnection.cxx b/connectivity/source/commontools/TConnection.cxx
new file mode 100644
index 0000000000..f35e8ca194
--- /dev/null
+++ b/connectivity/source/commontools/TConnection.cxx
@@ -0,0 +1,85 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <TConnection.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <comphelper/types.hxx>
+#include <connectivity/dbexception.hxx>
+
+using namespace connectivity;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::sdbc;
+using namespace com::sun::star::beans;
+using namespace ::osl;
+
+
+OMetaConnection::OMetaConnection()
+ : OMetaConnection_BASE(m_aMutex)
+ , m_nTextEncoding(RTL_TEXTENCODING_MS_1252)
+{
+}
+
+void OMetaConnection::disposing()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ m_xMetaData = WeakReference< XDatabaseMetaData>();
+ for (auto const& statement : m_aStatements)
+ {
+ try
+ {
+ Reference< XInterface > xStatement( statement.get() );
+ ::comphelper::disposeComponent( xStatement );
+ }
+ catch (const DisposedException&)
+ {
+ }
+ }
+ m_aStatements.clear();
+}
+//XUnoTunnel
+sal_Int64 SAL_CALL OMetaConnection::getSomething( const css::uno::Sequence< sal_Int8 >& rId )
+{
+ return comphelper::getSomethingImpl(rId, this);
+}
+
+const Sequence< sal_Int8 > & OMetaConnection::getUnoTunnelId()
+{
+ static const comphelper::UnoIdInit implId;
+ return implId.getSeq();
+}
+
+::dbtools::OPropertyMap& OMetaConnection::getPropMap()
+{
+ static ::dbtools::OPropertyMap s_aPropertyNameMap;
+ return s_aPropertyNameMap;
+}
+
+void OMetaConnection::throwGenericSQLException(TranslateId pErrorResourceId, const Reference< XInterface>& _xContext )
+{
+ OUString sErrorMessage;
+ if (pErrorResourceId)
+ sErrorMessage = m_aResources.getResourceString(pErrorResourceId);
+ Reference< XInterface> xContext = _xContext;
+ if ( !xContext.is() )
+ xContext = *this;
+ ::dbtools::throwGenericSQLException( sErrorMessage, xContext);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/commontools/TDatabaseMetaDataBase.cxx b/connectivity/source/commontools/TDatabaseMetaDataBase.cxx
new file mode 100644
index 0000000000..bd2b7a4671
--- /dev/null
+++ b/connectivity/source/commontools/TDatabaseMetaDataBase.cxx
@@ -0,0 +1,329 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <cstddef>
+
+#include <TDatabaseMetaDataBase.hxx>
+#include <RowFunctionParser.hxx>
+
+#include <comphelper/sequenceashashmap.hxx>
+#include <comphelper/evtlistenerhlp.hxx>
+#include <comphelper/types.hxx>
+#include <com/sun/star/lang/XComponent.hpp>
+#include <resource/sharedresources.hxx>
+#include <strings.hrc>
+#include <connectivity/dbexception.hxx>
+#include <sal/macros.h>
+
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::sdbc;
+using namespace com::sun::star::beans;
+using namespace comphelper;
+using namespace connectivity;
+
+
+ODatabaseMetaDataBase::ODatabaseMetaDataBase(const Reference< XConnection >& _rxConnection,const Sequence< PropertyValue >& _rInfo)
+ : m_aConnectionInfo(_rInfo)
+ ,m_isCatalogAtStart(false,false)
+ ,m_sCatalogSeparator(false,OUString())
+ ,m_sIdentifierQuoteString(false,OUString())
+ ,m_supportsCatalogsInTableDefinitions(false,false)
+ ,m_supportsSchemasInTableDefinitions(false,false)
+ ,m_supportsCatalogsInDataManipulation(false,false)
+ ,m_supportsSchemasInDataManipulation(false,false)
+ ,m_supportsMixedCaseQuotedIdentifiers(false,false)
+ ,m_supportsAlterTableWithAddColumn(false,false)
+ ,m_supportsAlterTableWithDropColumn(false,false)
+ ,m_MaxStatements(false,0)
+ ,m_MaxTablesInSelect(false,0)
+ ,m_storesMixedCaseQuotedIdentifiers(false,false)
+ , m_xConnection(_rxConnection)
+{
+ osl_atomic_increment( &m_refCount );
+ {
+ m_xListenerHelper = new OEventListenerHelper(this);
+ Reference<XComponent> xCom(m_xConnection,UNO_QUERY);
+ if(xCom.is())
+ xCom->addEventListener(m_xListenerHelper);
+ }
+ osl_atomic_decrement( &m_refCount );
+}
+
+ODatabaseMetaDataBase::~ODatabaseMetaDataBase()
+{
+}
+
+
+Sequence< PropertyValue > SAL_CALL ODatabaseMetaDataBase::getConnectionInfo( )
+{
+ return m_aConnectionInfo;
+}
+
+
+void SAL_CALL ODatabaseMetaDataBase::disposing( const EventObject& /*Source*/ )
+{
+ // cut off all references to the connection
+m_xConnection.clear();
+m_xListenerHelper.clear();
+}
+
+Reference< XResultSet > SAL_CALL ODatabaseMetaDataBase::getTypeInfo( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( m_aTypeInfoRows.empty() )
+ {
+ Reference< XResultSet > xRet = impl_getTypeInfo_throw();
+ Reference< XRow > xRow(xRet,UNO_QUERY);
+ ::comphelper::SequenceAsHashMap aMap(m_aConnectionInfo);
+ Sequence< Any > aTypeInfoSettings;
+ aTypeInfoSettings = aMap.getUnpackedValueOrDefault("TypeInfoSettings",aTypeInfoSettings);
+
+ if ( xRow.is() )
+ {
+ static const sal_Int32 pTypes[] = {
+ DataType::VARCHAR
+ ,DataType::INTEGER
+ ,DataType::INTEGER
+ ,DataType::VARCHAR
+ ,DataType::VARCHAR
+ ,DataType::VARCHAR
+ ,DataType::INTEGER
+ ,DataType::BOOLEAN
+ ,DataType::INTEGER
+ ,DataType::BOOLEAN
+ ,DataType::BOOLEAN
+ ,DataType::BOOLEAN
+ ,DataType::VARCHAR
+ ,DataType::INTEGER
+ ,DataType::INTEGER
+ ,DataType::INTEGER
+ ,DataType::INTEGER
+ ,DataType::INTEGER
+ };
+ std::vector<std::shared_ptr<ExpressionNode>> aConditions;
+ if ( aTypeInfoSettings.getLength() > 1 && ((aTypeInfoSettings.getLength() % 2) == 0) )
+ {
+ const Any* pIter = aTypeInfoSettings.getConstArray();
+ const Any* pEnd = pIter + aTypeInfoSettings.getLength();
+ try
+ {
+ for(;pIter != pEnd;++pIter)
+ aConditions.push_back(FunctionParser::parseFunction(::comphelper::getString(*pIter)));
+ }
+ catch(ParseError&)
+ {
+ ::connectivity::SharedResources aResources;
+ const OUString sError( aResources.getResourceString(STR_FORMULA_WRONG));
+ ::dbtools::throwGenericSQLException(sError,*this);
+ }
+ }
+
+ ::connectivity::ODatabaseMetaDataResultSet::ORows aTypeInfoRows;
+ while( xRet->next() )
+ {
+ ::connectivity::ODatabaseMetaDataResultSet::ORow aRow;
+ aRow.push_back(ODatabaseMetaDataResultSet::getEmptyValue());
+ const sal_Int32* pType = pTypes;
+ for (std::size_t i = 1; i <= std::size(pTypes); ++i,++pType)
+ {
+ ORowSetValue aValue;
+ aValue.fill(i,*pType,xRow);
+ aRow.push_back(new ORowSetValueDecorator(std::move(aValue)));
+ }
+
+ std::vector<std::shared_ptr<ExpressionNode>>::iterator aIter = aConditions.begin();
+ std::vector<std::shared_ptr<ExpressionNode>>::const_iterator aEnd = aConditions.end();
+ for (; aIter != aEnd; ++aIter)
+ {
+ if ( (*aIter)->evaluate(aRow)->getValue().getBool() )
+ {
+ ++aIter;
+ (*aIter)->fill(aRow);
+ }
+ else
+ ++aIter;
+ }
+ aTypeInfoRows.push_back(aRow);
+ }
+ m_aTypeInfoRows = aTypeInfoRows;
+ }
+ }
+ rtl::Reference<::connectivity::ODatabaseMetaDataResultSet> pResult = new ::connectivity::ODatabaseMetaDataResultSet(::connectivity::ODatabaseMetaDataResultSet::eTypeInfo);
+ pResult->setRows(std::vector(m_aTypeInfoRows));
+ return pResult;
+}
+
+Reference< XResultSet > SAL_CALL ODatabaseMetaDataBase::getExportedKeys(
+ const Any& /*catalog*/, const OUString& /*schema*/, const OUString& /*table*/ )
+{
+ return new ODatabaseMetaDataResultSet( ODatabaseMetaDataResultSet::eExportedKeys );
+}
+
+Reference< XResultSet > SAL_CALL ODatabaseMetaDataBase::getImportedKeys(
+ const Any& /*catalog*/, const OUString& /*schema*/, const OUString& /*table*/ )
+{
+ return new ODatabaseMetaDataResultSet( ODatabaseMetaDataResultSet::eImportedKeys );
+}
+
+Reference< XResultSet > SAL_CALL ODatabaseMetaDataBase::getPrimaryKeys(
+ const Any& /*catalog*/, const OUString& /*schema*/, const OUString& /*table*/ )
+{
+ return new ODatabaseMetaDataResultSet( ODatabaseMetaDataResultSet::ePrimaryKeys );
+}
+
+Reference< XResultSet > SAL_CALL ODatabaseMetaDataBase::getIndexInfo(
+ const Any& /*catalog*/, const OUString& /*schema*/, const OUString& /*table*/,
+ sal_Bool /*unique*/, sal_Bool /*approximate*/ )
+{
+ return new ODatabaseMetaDataResultSet( ODatabaseMetaDataResultSet::eIndexInfo );
+}
+
+Reference< XResultSet > SAL_CALL ODatabaseMetaDataBase::getBestRowIdentifier(
+ const Any& /*catalog*/, const OUString& /*schema*/, const OUString& /*table*/, sal_Int32 /*scope*/,
+ sal_Bool /*nullable*/ )
+{
+ return new ODatabaseMetaDataResultSet( ODatabaseMetaDataResultSet::eBestRowIdentifier );
+}
+
+Reference< XResultSet > SAL_CALL ODatabaseMetaDataBase::getCrossReference(
+ const Any& /*primaryCatalog*/, const OUString& /*primarySchema*/,
+ const OUString& /*primaryTable*/, const Any& /*foreignCatalog*/,
+ const OUString& /*foreignSchema*/, const OUString& /*foreignTable*/ )
+{
+ return new ODatabaseMetaDataResultSet( ODatabaseMetaDataResultSet::eCrossReference );
+}
+
+Reference< XConnection > SAL_CALL ODatabaseMetaDataBase::getConnection( )
+{
+ return m_xConnection;
+}
+
+Reference< XResultSet > SAL_CALL ODatabaseMetaDataBase::getProcedureColumns(
+ const Any& /*catalog*/, const OUString& /*schemaPattern*/,
+ const OUString& /*procedureNamePattern*/, const OUString& /*columnNamePattern*/ )
+{
+ return new ODatabaseMetaDataResultSet( ODatabaseMetaDataResultSet::eProcedureColumns );
+}
+
+Reference< XResultSet > SAL_CALL ODatabaseMetaDataBase::getProcedures(
+ const Any& /*catalog*/, const OUString& /*schemaPattern*/,
+ const OUString& /*procedureNamePattern*/ )
+{
+ return new ODatabaseMetaDataResultSet( ODatabaseMetaDataResultSet::eProcedures );
+}
+
+Reference< XResultSet > SAL_CALL ODatabaseMetaDataBase::getVersionColumns(
+ const Any& /*catalog*/, const OUString& /*schema*/, const OUString& /*table*/ )
+{
+ return new ODatabaseMetaDataResultSet( ODatabaseMetaDataResultSet::eVersionColumns );
+}
+
+Reference< XResultSet > SAL_CALL ODatabaseMetaDataBase::getSchemas( )
+{
+ return new ODatabaseMetaDataResultSet( ODatabaseMetaDataResultSet::eSchemas );
+}
+
+Reference< XResultSet > SAL_CALL ODatabaseMetaDataBase::getColumnPrivileges(
+ const Any& /*catalog*/, const OUString& /*schema*/, const OUString& /*table*/,
+ const OUString& /*columnNamePattern*/ )
+{
+ return new ODatabaseMetaDataResultSet( ODatabaseMetaDataResultSet::eColumnPrivileges );
+}
+
+Reference< XResultSet > SAL_CALL ODatabaseMetaDataBase::getTablePrivileges(
+ const Any& /*catalog*/, const OUString& /*schema*/, const OUString& /*table*/)
+{
+ return new ODatabaseMetaDataResultSet( ODatabaseMetaDataResultSet::eTablePrivileges );
+}
+
+Reference< XResultSet > SAL_CALL ODatabaseMetaDataBase::getCatalogs( )
+{
+ return new ODatabaseMetaDataResultSet( ODatabaseMetaDataResultSet::eCatalogs );
+}
+
+OUString SAL_CALL ODatabaseMetaDataBase::getIdentifierQuoteString( )
+{
+ return callImplMethod(m_sIdentifierQuoteString,std::function<OUString(ODatabaseMetaDataBase *)>(&ODatabaseMetaDataBase::impl_getIdentifierQuoteString_throw));
+}
+
+sal_Bool SAL_CALL ODatabaseMetaDataBase::isCatalogAtStart( )
+{
+ return callImplMethod(m_isCatalogAtStart,std::function<bool(ODatabaseMetaDataBase *)>(&ODatabaseMetaDataBase::impl_isCatalogAtStart_throw));
+}
+
+OUString SAL_CALL ODatabaseMetaDataBase::getCatalogSeparator( )
+{
+ return callImplMethod(m_sCatalogSeparator,std::function<OUString(ODatabaseMetaDataBase *)>(&ODatabaseMetaDataBase::impl_getCatalogSeparator_throw));
+}
+
+sal_Bool SAL_CALL ODatabaseMetaDataBase::supportsCatalogsInTableDefinitions( )
+{
+ return callImplMethod(m_supportsCatalogsInTableDefinitions,std::function<bool(ODatabaseMetaDataBase *)>(&ODatabaseMetaDataBase::impl_supportsCatalogsInTableDefinitions_throw));
+}
+
+sal_Bool SAL_CALL ODatabaseMetaDataBase::supportsSchemasInTableDefinitions( )
+{
+ return callImplMethod(m_supportsSchemasInTableDefinitions,std::function<bool(ODatabaseMetaDataBase *)>(&ODatabaseMetaDataBase::impl_supportsSchemasInTableDefinitions_throw));
+}
+
+sal_Bool SAL_CALL ODatabaseMetaDataBase::supportsCatalogsInDataManipulation( )
+{
+ return callImplMethod(m_supportsCatalogsInDataManipulation,std::function<bool(ODatabaseMetaDataBase *)>(&ODatabaseMetaDataBase::impl_supportsCatalogsInDataManipulation_throw));
+}
+
+sal_Bool SAL_CALL ODatabaseMetaDataBase::supportsSchemasInDataManipulation( )
+{
+ return callImplMethod(m_supportsSchemasInDataManipulation,std::function<bool(ODatabaseMetaDataBase *)>(&ODatabaseMetaDataBase::impl_supportsSchemasInDataManipulation_throw));
+}
+
+sal_Bool SAL_CALL ODatabaseMetaDataBase::supportsMixedCaseQuotedIdentifiers( )
+{
+ return callImplMethod(m_supportsMixedCaseQuotedIdentifiers,std::function<bool(ODatabaseMetaDataBase *)>(&ODatabaseMetaDataBase::impl_supportsMixedCaseQuotedIdentifiers_throw));
+}
+
+sal_Bool SAL_CALL ODatabaseMetaDataBase::supportsAlterTableWithAddColumn( )
+{
+ return callImplMethod(m_supportsAlterTableWithAddColumn,std::function<bool(ODatabaseMetaDataBase *)>(&ODatabaseMetaDataBase::impl_supportsAlterTableWithAddColumn_throw));
+}
+
+sal_Bool SAL_CALL ODatabaseMetaDataBase::supportsAlterTableWithDropColumn( )
+{
+ return callImplMethod(m_supportsAlterTableWithDropColumn,std::function<bool(ODatabaseMetaDataBase *)>(&ODatabaseMetaDataBase::impl_supportsAlterTableWithDropColumn_throw));
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaDataBase::getMaxStatements( )
+{
+ return callImplMethod(m_MaxStatements,std::function<sal_Int32(ODatabaseMetaDataBase *)>(&ODatabaseMetaDataBase::impl_getMaxStatements_throw));
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaDataBase::getMaxTablesInSelect( )
+{
+ return callImplMethod(m_MaxTablesInSelect,std::function<sal_Int32(ODatabaseMetaDataBase *)>(&ODatabaseMetaDataBase::impl_getMaxTablesInSelect_throw));
+}
+
+sal_Bool SAL_CALL ODatabaseMetaDataBase::storesMixedCaseQuotedIdentifiers( )
+{
+ return callImplMethod(m_storesMixedCaseQuotedIdentifiers,std::function<bool(ODatabaseMetaDataBase *)>(&ODatabaseMetaDataBase::impl_storesMixedCaseQuotedIdentifiers_throw));
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/commontools/TIndex.cxx b/connectivity/source/commontools/TIndex.cxx
new file mode 100644
index 0000000000..f7f891308e
--- /dev/null
+++ b/connectivity/source/commontools/TIndex.cxx
@@ -0,0 +1,100 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <TIndex.hxx>
+#include <TIndexColumns.hxx>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XResultSet.hpp>
+#include <connectivity/TTableHelper.hxx>
+#include <TConnection.hxx>
+
+using namespace connectivity;
+using namespace connectivity::sdbcx;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+
+OIndexHelper::OIndexHelper( OTableHelper* _pTable) : connectivity::sdbcx::OIndex(true)
+ , m_pTable(_pTable)
+{
+ construct();
+ std::vector< OUString> aVector;
+ m_pColumns.reset(new OIndexColumns(this,m_aMutex,aVector));
+}
+
+OIndexHelper::OIndexHelper( OTableHelper* _pTable,
+ const OUString& Name,
+ const OUString& Catalog,
+ bool _isUnique,
+ bool _isPrimaryKeyIndex,
+ bool _isClustered
+ ) : connectivity::sdbcx::OIndex(Name,
+ Catalog,
+ _isUnique,
+ _isPrimaryKeyIndex,
+ _isClustered,true)
+ ,m_pTable(_pTable)
+{
+ construct();
+ refreshColumns();
+}
+
+
+void OIndexHelper::refreshColumns()
+{
+ if ( !m_pTable )
+ return;
+
+ std::vector< OUString> aVector;
+ if ( !isNew() )
+ {
+ ::dbtools::OPropertyMap& rPropMap = OMetaConnection::getPropMap();
+ OUString aSchema,aTable;
+ m_pTable->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_SCHEMANAME)) >>= aSchema;
+ m_pTable->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_NAME)) >>= aTable;
+
+ Reference< XResultSet > xResult = m_pTable->getMetaData()->getIndexInfo(
+ m_pTable->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_CATALOGNAME)),
+ aSchema,aTable,false,false);
+
+ if ( xResult.is() )
+ {
+ Reference< XRow > xRow(xResult,UNO_QUERY);
+ OUString aColName;
+ while( xResult->next() )
+ {
+ if ( xRow->getString(6) == m_Name )
+ {
+ aColName = xRow->getString(9);
+ if ( !xRow->wasNull() )
+ aVector.push_back(aColName);
+ }
+ }
+ }
+ }
+ if(m_pColumns)
+ m_pColumns->reFill(aVector);
+ else
+ m_pColumns.reset(new OIndexColumns(this,m_aMutex,aVector));
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/commontools/TIndexColumns.cxx b/connectivity/source/commontools/TIndexColumns.cxx
new file mode 100644
index 0000000000..1db4426c18
--- /dev/null
+++ b/connectivity/source/commontools/TIndexColumns.cxx
@@ -0,0 +1,114 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <TIndexColumns.hxx>
+#include <sdbcx/VIndexColumn.hxx>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XResultSet.hpp>
+#include <TIndex.hxx>
+#include <connectivity/TTableHelper.hxx>
+#include <TConnection.hxx>
+
+using namespace connectivity;
+using namespace connectivity::sdbcx;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+
+OIndexColumns::OIndexColumns( OIndexHelper* _pIndex,
+ ::osl::Mutex& _rMutex,
+ const std::vector< OUString> &_rVector)
+ : connectivity::sdbcx::OCollection(*_pIndex,true,_rMutex,_rVector)
+ ,m_pIndex(_pIndex)
+{
+}
+
+sdbcx::ObjectType OIndexColumns::createObject(const OUString& _rName)
+{
+ ::dbtools::OPropertyMap& rPropMap = OMetaConnection::getPropMap();
+ OUString aCatalog, aSchema, aTable;
+ css::uno::Any Catalog(m_pIndex->getTable()->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_CATALOGNAME)));
+ Catalog >>= aCatalog;
+ m_pIndex->getTable()->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_SCHEMANAME)) >>= aSchema;
+ m_pIndex->getTable()->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_NAME)) >>= aTable;
+
+ Reference< XResultSet > xResult = m_pIndex->getTable()->getConnection()->getMetaData()->getIndexInfo(
+ Catalog, aSchema, aTable, false, false);
+
+ bool bAsc = true;
+ if ( xResult.is() )
+ {
+ Reference< XRow > xRow(xResult,UNO_QUERY);
+ while( xResult->next() )
+ {
+ if(xRow->getString(9) == _rName)
+ bAsc = xRow->getString(10) != "D";
+ }
+ }
+
+ xResult = m_pIndex->getTable()->getConnection()->getMetaData()->getColumns(
+ Catalog, aSchema, aTable, _rName);
+
+ sdbcx::ObjectType xRet;
+ if ( xResult.is() )
+ {
+ Reference< XRow > xRow(xResult,UNO_QUERY);
+ while( xResult->next() )
+ {
+ if ( xRow->getString(4) == _rName )
+ {
+ sal_Int32 nDataType = xRow->getInt(5);
+ OUString aTypeName(xRow->getString(6));
+ sal_Int32 nSize = xRow->getInt(7);
+ sal_Int32 nDec = xRow->getInt(9);
+ sal_Int32 nNull = xRow->getInt(11);
+ OUString aColumnDef(xRow->getString(13));
+
+ xRet = new OIndexColumn(bAsc,
+ _rName,
+ aTypeName,
+ aColumnDef,
+ nNull,
+ nSize,
+ nDec,
+ nDataType,
+ true,
+ aCatalog, aSchema, aTable);
+ break;
+ }
+ }
+ }
+
+ return xRet;
+}
+
+Reference< XPropertySet > OIndexColumns::createDescriptor()
+{
+ return new OIndexColumn(true);
+}
+
+void OIndexColumns::impl_refresh()
+{
+ m_pIndex->refreshColumns();
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/commontools/TIndexes.cxx b/connectivity/source/commontools/TIndexes.cxx
new file mode 100644
index 0000000000..2ba9124a51
--- /dev/null
+++ b/connectivity/source/commontools/TIndexes.cxx
@@ -0,0 +1,247 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <connectivity/TIndexes.hxx>
+#include <TIndex.hxx>
+#include <connectivity/TTableHelper.hxx>
+#include <com/sun/star/sdb/tools/XIndexAlteration.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XResultSet.hpp>
+#include <com/sun/star/sdbc/IndexType.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <connectivity/dbtools.hxx>
+#include <TConnection.hxx>
+#include <comphelper/extract.hxx>
+#include <comphelper/types.hxx>
+#include <rtl/ustrbuf.hxx>
+using namespace connectivity;
+using namespace connectivity::sdbcx;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+using namespace cppu;
+
+
+OIndexesHelper::OIndexesHelper(OTableHelper* _pTable,
+ ::osl::Mutex& _rMutex,
+ const std::vector< OUString> &_rVector
+ )
+ : OCollection(*_pTable,true,_rMutex,_rVector)
+ ,m_pTable(_pTable)
+{
+}
+
+
+sdbcx::ObjectType OIndexesHelper::createObject(const OUString& _rName)
+{
+ Reference< XConnection> xConnection = m_pTable->getConnection();
+ if ( !xConnection.is() )
+ return nullptr;
+
+ sdbcx::ObjectType xRet;
+ OUString aName,aQualifier;
+ sal_Int32 nLen = _rName.indexOf('.');
+ if ( nLen != -1 )
+ {
+ aQualifier = _rName.copy(0,nLen);
+ aName = _rName.copy(nLen+1);
+ }
+ else
+ aName = _rName;
+
+ ::dbtools::OPropertyMap& rPropMap = OMetaConnection::getPropMap();
+ OUString aSchema,aTable;
+ m_pTable->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_SCHEMANAME)) >>= aSchema;
+ m_pTable->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_NAME)) >>= aTable;
+
+ Any aCatalog = m_pTable->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_CATALOGNAME));
+ Reference< XResultSet > xResult = m_pTable->getMetaData()->getIndexInfo(aCatalog,aSchema,aTable,false,false);
+
+ if ( xResult.is() )
+ {
+ Reference< XRow > xRow(xResult,UNO_QUERY);
+ while( xResult->next() )
+ {
+ bool bUnique = !xRow->getBoolean(4);
+ if((aQualifier.isEmpty() || xRow->getString(5) == aQualifier ) && xRow->getString(6) == aName)
+ {
+ sal_Int32 nClustered = xRow->getShort(7);
+ bool bPrimarKeyIndex = false;
+ xRow.clear();
+ xResult.clear();
+ try
+ {
+ xResult = m_pTable->getMetaData()->getPrimaryKeys(aCatalog,aSchema,aTable);
+ xRow.set(xResult,UNO_QUERY);
+
+ if ( xRow.is() && xResult->next() ) // there can be only one primary key
+ {
+ bPrimarKeyIndex = xRow->getString(6) == aName;
+ }
+ }
+ catch(const Exception&)
+ {
+ }
+ xRet = new OIndexHelper(m_pTable,aName,aQualifier,bUnique,
+ bPrimarKeyIndex,
+ nClustered == IndexType::CLUSTERED);
+ break;
+ }
+ }
+ }
+
+ return xRet;
+}
+
+void OIndexesHelper::impl_refresh()
+{
+ m_pTable->refreshIndexes();
+}
+
+Reference< XPropertySet > OIndexesHelper::createDescriptor()
+{
+ return new OIndexHelper(m_pTable);
+}
+
+// XAppend
+sdbcx::ObjectType OIndexesHelper::appendObject( const OUString& _rForName, const Reference< XPropertySet >& descriptor )
+{
+ Reference< XConnection> xConnection = m_pTable->getConnection();
+ if ( !xConnection.is() )
+ return nullptr;
+ if ( m_pTable->isNew() )
+ return cloneDescriptor( descriptor );
+
+ if ( m_pTable->getIndexService().is() )
+ {
+ m_pTable->getIndexService()->addIndex(m_pTable,descriptor);
+ }
+ else
+ {
+ ::dbtools::OPropertyMap& rPropMap = OMetaConnection::getPropMap();
+ OUStringBuffer aSql( "CREATE " );
+ OUString aQuote = m_pTable->getMetaData()->getIdentifierQuoteString( );
+
+ if(comphelper::getBOOL(descriptor->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_ISUNIQUE))))
+ aSql.append("UNIQUE ");
+ aSql.append("INDEX ");
+
+
+ OUString aCatalog,aSchema,aTable;
+ dbtools::qualifiedNameComponents(m_pTable->getMetaData(),m_pTable->getName(),aCatalog,aSchema,aTable,::dbtools::EComposeRule::InDataManipulation);
+
+ OUString aComposedName = dbtools::composeTableName(m_pTable->getMetaData(),aCatalog,aSchema,aTable, true, ::dbtools::EComposeRule::InIndexDefinitions);
+ if (!_rForName.isEmpty() )
+ {
+ aSql.append( ::dbtools::quoteName( aQuote, _rForName )
+ + " ON "
+ + aComposedName
+ + " ( ");
+
+ Reference<XColumnsSupplier> xColumnSup(descriptor,UNO_QUERY);
+ Reference<XIndexAccess> xColumns(xColumnSup->getColumns(),UNO_QUERY);
+ Reference< XPropertySet > xColProp;
+ bool bAddIndexAppendix = ::dbtools::getBooleanDataSourceSetting( m_pTable->getConnection(), "AddIndexAppendix" );
+ sal_Int32 nCount = xColumns->getCount();
+ for(sal_Int32 i = 0 ; i < nCount; ++i)
+ {
+ xColProp.set(xColumns->getByIndex(i),UNO_QUERY);
+ aSql.append(::dbtools::quoteName( aQuote,comphelper::getString(xColProp->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_NAME)))));
+
+ if ( bAddIndexAppendix )
+ {
+
+ aSql.appendAscii(any2bool(xColProp->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_ISASCENDING)))
+ ?
+ " ASC"
+ :
+ " DESC");
+ }
+ aSql.append(",");
+ }
+ aSql[aSql.getLength() - 1] = ')';
+ }
+ else
+ {
+ aSql.append(aComposedName);
+
+ Reference<XColumnsSupplier> xColumnSup(descriptor,UNO_QUERY);
+ Reference<XIndexAccess> xColumns(xColumnSup->getColumns(),UNO_QUERY);
+ Reference< XPropertySet > xColProp;
+ if(xColumns->getCount() != 1)
+ throw SQLException();
+
+ xColumns->getByIndex(0) >>= xColProp;
+
+ aSql.append("."
+ + ::dbtools::quoteName( aQuote,comphelper::getString(xColProp->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_NAME)))));
+ }
+
+ Reference< XStatement > xStmt = m_pTable->getConnection()->createStatement( );
+ if ( xStmt.is() )
+ {
+ OUString sSql = aSql.makeStringAndClear();
+ xStmt->execute(sSql);
+ ::comphelper::disposeComponent(xStmt);
+ }
+ }
+
+ return createObject( _rForName );
+}
+
+// XDrop
+void OIndexesHelper::dropObject(sal_Int32 /*_nPos*/,const OUString& _sElementName)
+{
+ Reference< XConnection> xConnection = m_pTable->getConnection();
+ if( !xConnection.is() || m_pTable->isNew() )
+ return;
+
+ if ( m_pTable->getIndexService().is() )
+ {
+ m_pTable->getIndexService()->dropIndex(m_pTable,_sElementName);
+ }
+ else
+ {
+ OUString aName,aSchema;
+ sal_Int32 nLen = _sElementName.indexOf('.');
+ if(nLen != -1)
+ aSchema = _sElementName.copy(0,nLen);
+ aName = _sElementName.copy(nLen+1);
+
+ OUString aSql( "DROP INDEX " );
+
+ OUString aComposedName = dbtools::composeTableName( m_pTable->getMetaData(), m_pTable, ::dbtools::EComposeRule::InIndexDefinitions, true );
+ OUString sIndexName = dbtools::composeTableName( m_pTable->getMetaData(), OUString(), aSchema, aName, true, ::dbtools::EComposeRule::InIndexDefinitions );
+
+ aSql += sIndexName + " ON " + aComposedName;
+
+ Reference< XStatement > xStmt = m_pTable->getConnection()->createStatement( );
+ if ( xStmt.is() )
+ {
+ xStmt->execute(aSql);
+ ::comphelper::disposeComponent(xStmt);
+ }
+ }
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/commontools/TKey.cxx b/connectivity/source/commontools/TKey.cxx
new file mode 100644
index 0000000000..1341291abc
--- /dev/null
+++ b/connectivity/source/commontools/TKey.cxx
@@ -0,0 +1,107 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <TKey.hxx>
+#include <TKeyColumns.hxx>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XResultSet.hpp>
+#include <TConnection.hxx>
+#include <connectivity/TTableHelper.hxx>
+
+using namespace connectivity;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+
+OTableKeyHelper::OTableKeyHelper(OTableHelper* _pTable) : connectivity::sdbcx::OKey(true)
+ ,m_pTable(_pTable)
+{
+ construct();
+}
+
+OTableKeyHelper::OTableKeyHelper( OTableHelper* _pTable
+ ,const OUString& Name
+ ,const std::shared_ptr<sdbcx::KeyProperties>& _rProps
+ ) : connectivity::sdbcx::OKey(Name,_rProps,true)
+ ,m_pTable(_pTable)
+{
+ construct();
+ refreshColumns();
+}
+
+void OTableKeyHelper::refreshColumns()
+{
+ if ( !m_pTable )
+ return;
+
+ std::vector< OUString> aVector;
+ if ( !isNew() )
+ {
+ aVector = m_aProps->m_aKeyColumnNames;
+ if ( aVector.empty() )
+ {
+ ::dbtools::OPropertyMap& rPropMap = OMetaConnection::getPropMap();
+ OUString aSchema,aTable;
+ m_pTable->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_SCHEMANAME)) >>= aSchema;
+ m_pTable->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_NAME)) >>= aTable;
+
+ if ( !m_Name.isEmpty() ) // foreign key
+ {
+
+ Reference< XResultSet > xResult = m_pTable->getMetaData()->getImportedKeys(m_pTable->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_CATALOGNAME)),
+ aSchema,aTable);
+
+ if ( xResult.is() )
+ {
+ Reference< XRow > xRow(xResult,UNO_QUERY);
+ while( xResult->next() )
+ {
+ OUString aForeignKeyColumn = xRow->getString(8);
+ if(xRow->getString(12) == m_Name)
+ aVector.push_back(aForeignKeyColumn);
+ }
+ }
+ }
+
+ if ( aVector.empty() )
+ {
+ const Reference< XResultSet > xResult = m_pTable->getMetaData()->getPrimaryKeys(m_pTable->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_CATALOGNAME)),
+ aSchema,aTable);
+
+ if ( xResult.is() )
+ {
+ const Reference< XRow > xRow(xResult,UNO_QUERY);
+ while( xResult->next() )
+ aVector.push_back(xRow->getString(4));
+ } // if ( xResult.is() )
+ }
+ }
+ }
+
+
+ if ( m_pColumns )
+ m_pColumns->reFill(aVector);
+ else
+ m_pColumns.reset(new OKeyColumnsHelper(this,m_aMutex,aVector));
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/commontools/TKeyColumns.cxx b/connectivity/source/commontools/TKeyColumns.cxx
new file mode 100644
index 0000000000..0a2c02bb22
--- /dev/null
+++ b/connectivity/source/commontools/TKeyColumns.cxx
@@ -0,0 +1,132 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <TKeyColumns.hxx>
+#include <TKey.hxx>
+#include <sdbcx/VKeyColumn.hxx>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XResultSet.hpp>
+#include <TConnection.hxx>
+#include <connectivity/TTableHelper.hxx>
+
+using namespace connectivity;
+using namespace connectivity::sdbcx;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+
+
+OKeyColumnsHelper::OKeyColumnsHelper( OTableKeyHelper* _pKey,
+ ::osl::Mutex& _rMutex,
+ const std::vector< OUString> &_rVector)
+ : connectivity::sdbcx::OCollection(*_pKey,true,_rMutex,_rVector)
+ ,m_pKey(_pKey)
+{
+}
+
+sdbcx::ObjectType OKeyColumnsHelper::createObject(const OUString& _rName)
+{
+ ::dbtools::OPropertyMap& rPropMap = OMetaConnection::getPropMap();
+ OUString aCatalog, aSchema, aTable;
+ css::uno::Any Catalog(m_pKey->getTable()->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_CATALOGNAME)));
+ Catalog >>= aCatalog;
+ m_pKey->getTable()->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_SCHEMANAME)) >>= aSchema;
+ m_pKey->getTable()->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_NAME)) >>= aTable;
+
+ // first get the related column to _rName
+ Reference< XResultSet > xResult = m_pKey->getTable()->getMetaData()->getImportedKeys(
+ Catalog, aSchema, aTable);
+
+ OUString aRefColumnName;
+ if ( xResult.is() )
+ {
+ Reference< XRow > xRow(xResult,UNO_QUERY);
+ OUString aTemp;
+ while(xResult->next())
+ {
+ aTemp = xRow->getString(4);
+ if(xRow->getString(8) == _rName && m_pKey->getName() == xRow->getString(12))
+ {
+ aRefColumnName = aTemp;
+ break;
+ }
+ }
+ }
+
+ sdbcx::ObjectType xRet;
+
+ // now describe the column _rName and set his related column
+ xResult = m_pKey->getTable()->getMetaData()->getColumns(Catalog, aSchema, aTable, _rName);
+
+ if ( xResult.is() )
+ {
+ Reference< XRow > xRow(xResult,UNO_QUERY);
+ if ( xResult->next() )
+ {
+ if ( xRow->getString(4) == _rName )
+ {
+ sal_Int32 nDataType = xRow->getInt(5);
+ OUString aTypeName(xRow->getString(6));
+ sal_Int32 nSize = xRow->getInt(7);
+ sal_Int32 nDec = xRow->getInt(9);
+ sal_Int32 nNull = xRow->getInt(11);
+ OUString sColumnDef;
+ try
+ {
+ sColumnDef = xRow->getString(13);
+ }
+ catch(const SQLException&)
+ {
+ // sometimes we get an error when asking for this param
+ }
+
+ xRet = new OKeyColumn(aRefColumnName,
+ _rName,
+ aTypeName,
+ sColumnDef,
+ nNull,
+ nSize,
+ nDec,
+ nDataType,
+ isCaseSensitive(),
+ aCatalog,
+ aSchema,
+ aTable);
+ }
+ }
+ }
+
+ return xRet;
+}
+
+Reference< XPropertySet > OKeyColumnsHelper::createDescriptor()
+{
+ return new OKeyColumn(isCaseSensitive());
+}
+
+void OKeyColumnsHelper::impl_refresh()
+{
+ m_pKey->refreshColumns();
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/commontools/TKeys.cxx b/connectivity/source/commontools/TKeys.cxx
new file mode 100644
index 0000000000..e6e50f20a4
--- /dev/null
+++ b/connectivity/source/commontools/TKeys.cxx
@@ -0,0 +1,307 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <connectivity/TKeys.hxx>
+#include <TKey.hxx>
+#include <connectivity/TTableHelper.hxx>
+#include <com/sun/star/sdb/tools/XKeyAlteration.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XResultSet.hpp>
+#include <com/sun/star/sdbcx/KeyType.hpp>
+#include <com/sun/star/sdbc/KeyRule.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <connectivity/dbtools.hxx>
+#include <comphelper/types.hxx>
+#include <TConnection.hxx>
+
+namespace connectivity
+{
+using namespace comphelper;
+using namespace connectivity::sdbcx;
+using namespace dbtools;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+
+
+OKeysHelper::OKeysHelper( OTableHelper* _pTable,
+ ::osl::Mutex& _rMutex,
+ const ::std::vector< OUString>& _rVector
+ ) : OKeys_BASE(*_pTable,true,_rMutex,_rVector,true)
+ ,m_pTable(_pTable)
+{
+}
+
+sdbcx::ObjectType OKeysHelper::createObject(const OUString& _rName)
+{
+ sdbcx::ObjectType xRet;
+
+ if(!_rName.isEmpty())
+ {
+ xRet = new OTableKeyHelper(m_pTable,_rName,m_pTable->getKeyProperties(_rName));
+ }
+
+ if(!xRet.is()) // we have a primary key with a system name
+ {
+ xRet = new OTableKeyHelper(m_pTable,_rName,m_pTable->getKeyProperties(_rName));
+ }
+
+ return xRet;
+}
+
+void OKeysHelper::impl_refresh()
+{
+ m_pTable->refreshKeys();
+}
+
+Reference< XPropertySet > OKeysHelper::createDescriptor()
+{
+ return new OTableKeyHelper(m_pTable);
+}
+
+/** returns the keyrule string for the primary key
+*/
+static OUString getKeyRuleString(bool _bUpdate,sal_Int32 _nKeyRule)
+{
+ const char* pKeyRule = nullptr;
+ switch ( _nKeyRule )
+ {
+ case KeyRule::CASCADE:
+ pKeyRule = _bUpdate ? " ON UPDATE CASCADE " : " ON DELETE CASCADE ";
+ break;
+ case KeyRule::RESTRICT:
+ pKeyRule = _bUpdate ? " ON UPDATE RESTRICT " : " ON DELETE RESTRICT ";
+ break;
+ case KeyRule::SET_NULL:
+ pKeyRule = _bUpdate ? " ON UPDATE SET NULL " : " ON DELETE SET NULL ";
+ break;
+ case KeyRule::SET_DEFAULT:
+ pKeyRule = _bUpdate ? " ON UPDATE SET DEFAULT " : " ON DELETE SET DEFAULT ";
+ break;
+ default:
+ ;
+ }
+ OUString sRet;
+ if ( pKeyRule )
+ sRet = OUString::createFromAscii(pKeyRule);
+ return sRet;
+}
+
+void OKeysHelper::cloneDescriptorColumns( const sdbcx::ObjectType& _rSourceDescriptor, const sdbcx::ObjectType& _rDestDescriptor )
+{
+ Reference< XColumnsSupplier > xColSupp( _rSourceDescriptor, UNO_QUERY_THROW );
+ Reference< XIndexAccess > xSourceCols( xColSupp->getColumns(), UNO_QUERY_THROW );
+
+ xColSupp.set( _rDestDescriptor, UNO_QUERY_THROW );
+ Reference< XAppend > xDestAppend( xColSupp->getColumns(), UNO_QUERY_THROW );
+
+ sal_Int32 nCount = xSourceCols->getCount();
+ for ( sal_Int32 i=0; i< nCount; ++i )
+ {
+ Reference< XPropertySet > xColProp( xSourceCols->getByIndex(i), UNO_QUERY );
+ xDestAppend->appendByDescriptor( xColProp );
+ }
+}
+
+// XAppend
+sdbcx::ObjectType OKeysHelper::appendObject( const OUString& _rForName, const Reference< XPropertySet >& descriptor )
+{
+ Reference< XConnection> xConnection = m_pTable->getConnection();
+ if ( !xConnection.is() )
+ return nullptr;
+ if ( m_pTable->isNew() )
+ {
+ Reference< XPropertySet > xNewDescriptor( cloneDescriptor( descriptor ) );
+ cloneDescriptorColumns( descriptor, xNewDescriptor );
+ return xNewDescriptor;
+ }
+
+ const ::dbtools::OPropertyMap& rPropMap = OMetaConnection::getPropMap();
+ sal_Int32 nKeyType = getINT32(descriptor->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_TYPE)));
+ sal_Int32 nUpdateRule = 0, nDeleteRule = 0;
+ OUString sReferencedName;
+
+ if ( nKeyType == KeyType::FOREIGN )
+ {
+ descriptor->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_REFERENCEDTABLE)) >>= sReferencedName;
+ descriptor->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_UPDATERULE)) >>= nUpdateRule;
+ descriptor->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_DELETERULE)) >>= nDeleteRule;
+ }
+
+ if ( m_pTable->getKeyService().is() )
+ {
+ m_pTable->getKeyService()->addKey(m_pTable,descriptor);
+ }
+ else
+ {
+ // if we're here, we belong to a table which is not new, i.e. already exists in the database.
+ // In this case, really append the new index.
+ OUStringBuffer aSql("ALTER TABLE ");
+ OUString aQuote = m_pTable->getConnection()->getMetaData()->getIdentifierQuoteString( );
+
+ aSql.append(composeTableName( m_pTable->getConnection()->getMetaData(), m_pTable, ::dbtools::EComposeRule::InTableDefinitions, true )
+ + " ADD ");
+
+ if ( nKeyType == KeyType::PRIMARY )
+ {
+ aSql.append(" PRIMARY KEY (");
+ }
+ else if ( nKeyType == KeyType::FOREIGN )
+ {
+ aSql.append(" FOREIGN KEY (");
+ }
+ else
+ throw SQLException();
+
+ Reference<XColumnsSupplier> xColumnSup(descriptor,UNO_QUERY);
+ Reference<XIndexAccess> xColumns(xColumnSup->getColumns(),UNO_QUERY);
+ Reference< XPropertySet > xColProp;
+ for(sal_Int32 i = 0 ; i < xColumns->getCount() ; ++i)
+ {
+ if ( i > 0 )
+ aSql.append(",");
+ xColProp.set(xColumns->getByIndex(i), css::uno::UNO_QUERY);
+ aSql.append( ::dbtools::quoteName( aQuote,getString(xColProp->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_NAME)))) );
+
+ }
+ aSql.append(")");
+
+ if ( nKeyType == KeyType::FOREIGN )
+ {
+ aSql.append(" REFERENCES "
+ + ::dbtools::quoteTableName(m_pTable->getConnection()->getMetaData(),sReferencedName,::dbtools::EComposeRule::InTableDefinitions)
+ + " (");
+
+ for(sal_Int32 i=0;i<xColumns->getCount();++i)
+ {
+ if ( i > 0 )
+ aSql.append(",");
+ xColumns->getByIndex(i) >>= xColProp;
+ aSql.append(::dbtools::quoteName( aQuote,getString(xColProp->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_RELATEDCOLUMN)))));
+
+ }
+ aSql.append(")"
+ + getKeyRuleString(true ,nUpdateRule)
+ + getKeyRuleString(false ,nDeleteRule));
+ }
+
+ Reference< XStatement > xStmt = m_pTable->getConnection()->createStatement( );
+ xStmt->execute(aSql.makeStringAndClear());
+ }
+ // find the name which the database gave the new key
+ OUString sNewName( _rForName );
+ try
+ {
+ OUString aSchema,aTable;
+ m_pTable->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_SCHEMANAME)) >>= aSchema;
+ m_pTable->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_NAME)) >>= aTable;
+ Reference< XResultSet > xResult;
+ sal_Int32 nColumn = 12;
+ if ( nKeyType == KeyType::FOREIGN )
+ xResult = m_pTable->getMetaData()->getImportedKeys( m_pTable->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_CATALOGNAME))
+ ,aSchema
+ ,aTable);
+ else
+ {
+ xResult = m_pTable->getMetaData()->getPrimaryKeys( m_pTable->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_CATALOGNAME))
+ ,aSchema
+ ,aTable);
+ nColumn = 6;
+ }
+ if ( xResult.is() )
+ {
+ Reference< XRow > xRow(xResult,UNO_QUERY);
+ while( xResult->next() )
+ {
+ OUString sName = xRow->getString(nColumn);
+ if ( !m_pElements->exists(sName) ) // this name wasn't inserted yet so it must be the new one
+ {
+ descriptor->setPropertyValue( rPropMap.getNameByIndex( PROPERTY_ID_NAME ), Any( sName ) );
+ sNewName = sName;
+ break;
+ }
+ }
+ ::comphelper::disposeComponent(xResult);
+ }
+ }
+ catch(const SQLException&)
+ {
+ }
+
+ m_pTable->addKey(sNewName,std::make_shared<sdbcx::KeyProperties>(sReferencedName,nKeyType,nUpdateRule,nDeleteRule));
+
+ return createObject( sNewName );
+}
+
+OUString OKeysHelper::getDropForeignKey() const
+{
+ return " DROP CONSTRAINT ";
+}
+
+// XDrop
+void OKeysHelper::dropObject(sal_Int32 _nPos, const OUString& _sElementName)
+{
+ Reference< XConnection> xConnection = m_pTable->getConnection();
+ if ( !xConnection.is() || m_pTable->isNew() )
+ return;
+
+ Reference<XPropertySet> xKey(getObject(_nPos),UNO_QUERY);
+ if ( m_pTable->getKeyService().is() )
+ {
+ m_pTable->getKeyService()->dropKey(m_pTable,xKey);
+ }
+ else
+ {
+ OUStringBuffer aSql(
+ "ALTER TABLE "
+ + composeTableName( m_pTable->getConnection()->getMetaData(), m_pTable,::dbtools::EComposeRule::InTableDefinitions, true ));
+
+ sal_Int32 nKeyType = KeyType::PRIMARY;
+ if ( xKey.is() )
+ {
+ ::dbtools::OPropertyMap& rPropMap = OMetaConnection::getPropMap();
+ xKey->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_TYPE)) >>= nKeyType;
+ }
+ if ( KeyType::PRIMARY == nKeyType )
+ {
+ aSql.append(" DROP PRIMARY KEY");
+ }
+ else
+ {
+ aSql.append(getDropForeignKey());
+ const OUString aQuote = m_pTable->getConnection()->getMetaData()->getIdentifierQuoteString();
+ aSql.append( ::dbtools::quoteName( aQuote,_sElementName) );
+ }
+
+ Reference< XStatement > xStmt = m_pTable->getConnection()->createStatement( );
+ if ( xStmt.is() )
+ {
+ xStmt->execute(aSql.makeStringAndClear());
+ ::comphelper::disposeComponent(xStmt);
+ }
+ }
+}
+
+} // namespace connectivity
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/commontools/TPrivilegesResultSet.cxx b/connectivity/source/commontools/TPrivilegesResultSet.cxx
new file mode 100644
index 0000000000..928e9c016a
--- /dev/null
+++ b/connectivity/source/commontools/TPrivilegesResultSet.cxx
@@ -0,0 +1,140 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <TPrivilegesResultSet.hxx>
+
+using namespace connectivity;
+
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+
+OResultSetPrivileges::OResultSetPrivileges( const Reference< XDatabaseMetaData>& _rxMeta
+ , const Any& catalog
+ , const OUString& schemaPattern
+ , const OUString& tableNamePattern)
+ : ODatabaseMetaDataResultSet(eTablePrivileges)
+ , m_bResetValues(true)
+{
+ osl_atomic_increment( &m_refCount );
+ {
+ OUString sUserWorkingFor;
+ // we want all catalogues, all schemas, all tables
+ Sequence< OUString > sTableTypes {"VIEW", "TABLE", "%"}; // this last one is just to be sure to include anything else...
+ try
+ {
+ m_xTables = _rxMeta->getTables(catalog,schemaPattern,tableNamePattern,sTableTypes);
+ m_xRow.set(m_xTables,UNO_QUERY);
+
+ sUserWorkingFor = _rxMeta->getUserName();
+ }
+ catch(Exception&)
+ {
+ }
+
+ ODatabaseMetaDataResultSet::ORows aRows;
+ ODatabaseMetaDataResultSet::ORow aRow(8);
+ aRow[5] = new ORowSetValueDecorator(sUserWorkingFor);
+ aRow[6] = ODatabaseMetaDataResultSet::getSelectValue();
+ aRow[7] = new ORowSetValueDecorator(OUString("YES"));
+ aRows.push_back(aRow);
+ aRow[6] = ODatabaseMetaDataResultSet::getInsertValue();
+ aRows.push_back(aRow);
+ aRow[6] = ODatabaseMetaDataResultSet::getDeleteValue();
+ aRows.push_back(aRow);
+ aRow[6] = ODatabaseMetaDataResultSet::getUpdateValue();
+ aRows.push_back(aRow);
+ aRow[6] = ODatabaseMetaDataResultSet::getCreateValue();
+ aRows.push_back(aRow);
+ aRow[6] = ODatabaseMetaDataResultSet::getReadValue();
+ aRows.push_back(aRow);
+ aRow[6] = ODatabaseMetaDataResultSet::getAlterValue();
+ aRows.push_back(aRow);
+ aRow[6] = ODatabaseMetaDataResultSet::getDropValue();
+ aRows.push_back(aRow);
+ aRow[6] = new ORowSetValueDecorator(OUString("REFERENCE"));
+ aRows.push_back(aRow);
+
+ setRows(std::move(aRows));
+ }
+ osl_atomic_decrement( &m_refCount );
+}
+
+const ORowSetValue& OResultSetPrivileges::getValue(sal_Int32 columnIndex)
+{
+ switch(columnIndex)
+ {
+ case 1:
+ case 2:
+ case 3:
+ if ( m_xRow.is() && m_bResetValues )
+ {
+ (*m_aRowsIter)[1] = new ORowSetValueDecorator(m_xRow->getString(1));
+ if ( m_xRow->wasNull() )
+ (*m_aRowsIter)[1]->setNull();
+ (*m_aRowsIter)[2] = new ORowSetValueDecorator(m_xRow->getString(2));
+ if ( m_xRow->wasNull() )
+ (*m_aRowsIter)[2]->setNull();
+ (*m_aRowsIter)[3] = new ORowSetValueDecorator(m_xRow->getString(3));
+ if ( m_xRow->wasNull() )
+ (*m_aRowsIter)[3]->setNull();
+
+ m_bResetValues = false;
+ }
+ }
+ return ODatabaseMetaDataResultSet::getValue(columnIndex);
+}
+
+void SAL_CALL OResultSetPrivileges::disposing()
+{
+ ODatabaseMetaDataResultSet::disposing();
+ m_xTables.clear();
+ m_xRow.clear();
+}
+
+sal_Bool SAL_CALL OResultSetPrivileges::next( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed );
+
+ bool bReturn = false;
+ if ( m_xTables.is() )
+ {
+ if ( m_bBOF )
+ {
+ m_bResetValues = true;
+ if ( !m_xTables->next() )
+ return false;
+ }
+
+ bReturn = ODatabaseMetaDataResultSet::next();
+ if ( !bReturn )
+ {
+ m_bBOF = false;
+ m_bResetValues = bReturn = m_xTables->next();
+ }
+ }
+ return bReturn;
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/commontools/TSkipDeletedSet.cxx b/connectivity/source/commontools/TSkipDeletedSet.cxx
new file mode 100644
index 0000000000..701bd743f6
--- /dev/null
+++ b/connectivity/source/commontools/TSkipDeletedSet.cxx
@@ -0,0 +1,255 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <TSkipDeletedSet.hxx>
+#include <osl/diagnose.h>
+#include <sal/log.hxx>
+#include <algorithm>
+
+using namespace connectivity;
+
+OSkipDeletedSet::OSkipDeletedSet(IResultSetHelper* _pHelper)
+ : m_pHelper(_pHelper)
+ ,m_bDeletedVisible(false)
+{
+ m_aBookmarksPositions.reserve(256);
+}
+
+OSkipDeletedSet::~OSkipDeletedSet()
+{
+ m_aBookmarksPositions.clear();
+ //m_aBookmarks.clear();
+}
+
+bool OSkipDeletedSet::skipDeleted(IResultSetHelper::Movement _eCursorPosition, sal_Int32 _nOffset, bool _bRetrieveData)
+{
+ OSL_ENSURE(_eCursorPosition != IResultSetHelper::BOOKMARK,"OSkipDeletedSet::SkipDeleted can't be called for BOOKMARK");
+
+ IResultSetHelper::Movement eDelPosition = _eCursorPosition;
+ sal_Int32 nDelOffset = abs(_nOffset);
+
+ switch (_eCursorPosition)
+ {
+ case IResultSetHelper::ABSOLUTE1:
+ return moveAbsolute(_nOffset,_bRetrieveData);
+ case IResultSetHelper::FIRST: // set the movement when positioning failed
+ eDelPosition = IResultSetHelper::NEXT;
+ nDelOffset = 1;
+ break;
+ case IResultSetHelper::LAST:
+ eDelPosition = IResultSetHelper::PRIOR; // last row is invalid so position before
+ nDelOffset = 1;
+ break;
+ case IResultSetHelper::RELATIVE1:
+ eDelPosition = (_nOffset >= 0) ? IResultSetHelper::NEXT : IResultSetHelper::PRIOR;
+ break;
+ default:
+ break;
+ }
+
+ bool bDone = true;
+ bool bDataFound = false;
+
+ if (_eCursorPosition == IResultSetHelper::LAST)
+ {
+ SAL_INFO( "connectivity.commontools", "OSkipDeletedSet::skipDeleted: last" );
+ sal_Int32 nBookmark = 0;
+ // first position on the last known row
+ if ( m_aBookmarksPositions.empty() )
+ {
+ bDataFound = m_pHelper->move(IResultSetHelper::FIRST, 0, _bRetrieveData);
+ if(bDataFound && (m_bDeletedVisible || !m_pHelper->isRowDeleted()))
+ //m_aBookmarksPositions.push_back(m_aBookmarks.emplace( m_pHelper->getDriverPos(),m_aBookmarksPositions.size()+1)).first);
+ m_aBookmarksPositions.push_back(m_pHelper->getDriverPos());
+ }
+ else
+ {
+ // I already have a bookmark so we can positioned on that and look if it is the last one
+ nBookmark = (*m_aBookmarksPositions.rbegin())/*->first*/;
+
+ bDataFound = m_pHelper->move(IResultSetHelper::BOOKMARK, nBookmark, _bRetrieveData);
+ OSL_ENSURE((m_bDeletedVisible || !m_pHelper->isRowDeleted()),"A bookmark should not be deleted!");
+ }
+
+
+ // and then move forward until we are after the last row
+ while(bDataFound)
+ {
+ bDataFound = m_pHelper->move(IResultSetHelper::NEXT, 1, false); // we don't need the data here
+ if( bDataFound && ( m_bDeletedVisible || !m_pHelper->isRowDeleted()) )
+ { // we weren't on the last row we remember it and move on
+ m_aBookmarksPositions.push_back(m_pHelper->getDriverPos());
+ //m_aBookmarksPositions.push_back(m_aBookmarks.emplace( m_pHelper->getDriverPos(),m_aBookmarksPositions.size()+1)).first);
+ }
+ else if(!bDataFound && !m_aBookmarksPositions.empty() )
+ {
+ // i already know the last bookmark :-)
+ // now we only have to repositioning us to the last row
+ nBookmark = (*m_aBookmarksPositions.rbegin())/*->first*/;
+ bDataFound = m_pHelper->move(IResultSetHelper::BOOKMARK, nBookmark, _bRetrieveData);
+ break;
+ }
+ }
+ return bDataFound;
+ }
+ else if (_eCursorPosition != IResultSetHelper::RELATIVE1)
+ {
+ bDataFound = m_pHelper->move(_eCursorPosition, _nOffset, _bRetrieveData);
+ bDone = bDataFound && (m_bDeletedVisible || !m_pHelper->isRowDeleted());
+ }
+ else
+ {
+ bDataFound = m_pHelper->move(eDelPosition, 1, _bRetrieveData);
+ if (bDataFound && (m_bDeletedVisible || !m_pHelper->isRowDeleted()))
+ {
+ bDone = (--nDelOffset) == 0;
+ if ( !bDone )
+ m_aBookmarksPositions.push_back(m_pHelper->getDriverPos());
+ //m_aBookmarksPositions.push_back(m_aBookmarks.emplace( m_pHelper->getDriverPos(),m_aBookmarksPositions.size()+1)).first);
+ }
+ else
+ bDone = false;
+ }
+
+ while (bDataFound && !bDone) // Iterate until we are at the valid set
+ {
+ bDataFound = m_pHelper->move(eDelPosition, 1, _bRetrieveData);
+ if (_eCursorPosition != IResultSetHelper::RELATIVE1)
+ bDone = bDataFound && (m_bDeletedVisible || !m_pHelper->isRowDeleted());
+ else if (bDataFound && (m_bDeletedVisible || !m_pHelper->isRowDeleted()))
+ {
+ bDone = (--nDelOffset) == 0;
+ if ( !bDone )
+ m_aBookmarksPositions.push_back(m_pHelper->getDriverPos());
+ //m_aBookmarksPositions.push_back(m_aBookmarks.emplace( m_pHelper->getDriverPos(),m_aBookmarksPositions.size()+1)).first);
+ }
+ else
+ bDone = false;
+ }
+
+ if(bDataFound && bDone)
+ {
+ const sal_Int32 nDriverPos = m_pHelper->getDriverPos();
+ if ( m_bDeletedVisible )
+ {
+ if ( nDriverPos > static_cast<sal_Int32>(m_aBookmarksPositions.size()) )
+ m_aBookmarksPositions.push_back(nDriverPos);
+ }
+ else if ( std::find(m_aBookmarksPositions.begin(),m_aBookmarksPositions.end(),nDriverPos) == m_aBookmarksPositions.end() )
+ m_aBookmarksPositions.push_back(nDriverPos);
+ /*sal_Int32 nDriverPos = m_pHelper->getDriverPos();
+ if(m_aBookmarks.find(nDriverPos) == m_aBookmarks.end())
+ m_aBookmarksPositions.push_back(m_aBookmarks.emplace( nDriverPos,m_aBookmarksPositions.size()+1)).first);*/
+ }
+
+ return bDataFound;
+}
+
+bool OSkipDeletedSet::moveAbsolute(sal_Int32 _nPos,bool _bRetrieveData)
+{
+ bool bDataFound = false;
+ sal_Int32 nNewPos = _nPos;
+ if(nNewPos > 0)
+ {
+ if(static_cast<sal_Int32>(m_aBookmarksPositions.size()) < nNewPos)
+ {
+ // bookmark isn't known yet
+ // start at the last known position
+ sal_Int32 nCurPos = 0;
+ if ( m_aBookmarksPositions.empty() )
+ {
+ bDataFound = m_pHelper->move(IResultSetHelper::FIRST, 0, _bRetrieveData );
+ if(bDataFound && (m_bDeletedVisible || !m_pHelper->isRowDeleted()))
+ {
+ ++nCurPos;
+ m_aBookmarksPositions.push_back(m_pHelper->getDriverPos());
+ //m_aBookmarksPositions.push_back(m_aBookmarks.emplace( m_pHelper->getDriverPos(),m_aBookmarksPositions.size()+1)).first);
+ --nNewPos;
+ }
+ } // if ( m_aBookmarksPositions.empty() )
+ else
+ {
+ sal_Int32 nLastBookmark = *m_aBookmarksPositions.rbegin()/*->first*/;
+ nCurPos = /*(**/m_aBookmarksPositions.size()/*->second*/;
+ nNewPos = nNewPos - nCurPos;
+ bDataFound = m_pHelper->move(IResultSetHelper::BOOKMARK, nLastBookmark, _bRetrieveData);
+ }
+
+ // now move to that row we need and don't count deleted rows
+ while (bDataFound && nNewPos)
+ {
+ bDataFound = m_pHelper->move(IResultSetHelper::NEXT, 1, _bRetrieveData);
+ if(bDataFound && (m_bDeletedVisible || !m_pHelper->isRowDeleted()))
+ {
+ ++nCurPos;
+ m_aBookmarksPositions.push_back(m_pHelper->getDriverPos());
+ //m_aBookmarksPositions.push_back(m_aBookmarks.emplace( m_pHelper->getDriverPos(),m_aBookmarksPositions.size()+1)).first);
+ --nNewPos;
+ }
+ }
+ }
+ else
+ {
+ const sal_Int32 nBookmark = m_aBookmarksPositions[nNewPos-1]/*->first*/;
+ bDataFound = m_pHelper->move(IResultSetHelper::BOOKMARK,nBookmark, _bRetrieveData);
+ OSL_ENSURE((m_bDeletedVisible || !m_pHelper->isRowDeleted()),"moveAbsolute: row can't be deleted!");
+ }
+ }
+ else
+ {
+ ++nNewPos;
+ bDataFound = skipDeleted(IResultSetHelper::LAST,0,nNewPos == 0);
+
+ for(sal_Int32 i=nNewPos+1;bDataFound && i <= 0;++i)
+ bDataFound = skipDeleted(IResultSetHelper::PRIOR,1,i == 0);
+
+ }
+ return bDataFound;
+}
+
+void OSkipDeletedSet::clear()
+{
+ std::vector<sal_Int32>().swap(m_aBookmarksPositions);
+}
+
+sal_Int32 OSkipDeletedSet::getMappedPosition(sal_Int32 _nPos) const
+{
+ std::vector<sal_Int32>::const_iterator aFind = std::find(m_aBookmarksPositions.begin(),m_aBookmarksPositions.end(),_nPos);
+ if ( aFind != m_aBookmarksPositions.end() )
+ return (aFind - m_aBookmarksPositions.begin()) + 1;
+ OSL_FAIL("Why!");
+ return -1;
+}
+
+void OSkipDeletedSet::insertNewPosition(sal_Int32 _nPos)
+{
+ m_aBookmarksPositions.push_back(_nPos);
+}
+
+void OSkipDeletedSet::deletePosition(sal_Int32 _nBookmark)
+{
+ std::vector<sal_Int32>::iterator aFind = std::find(m_aBookmarksPositions.begin(),m_aBookmarksPositions.end(),_nBookmark);
+ if ( aFind != m_aBookmarksPositions.end() )
+ {
+ m_aBookmarksPositions.erase(aFind);
+ }
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/commontools/TSortIndex.cxx b/connectivity/source/commontools/TSortIndex.cxx
new file mode 100644
index 0000000000..44a883dc86
--- /dev/null
+++ b/connectivity/source/commontools/TSortIndex.cxx
@@ -0,0 +1,152 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <TSortIndex.hxx>
+#include <algorithm>
+#include <iterator>
+#include <o3tl/functional.hxx>
+
+using namespace connectivity;
+
+namespace {
+
+/// Functor object for class OSortIndex::TIntValuePairVector::value_type returntype is bool
+struct TKeyValueFunc
+{
+ OSortIndex* pIndex;
+
+ explicit TKeyValueFunc(OSortIndex* _pIndex) : pIndex(_pIndex)
+ {
+ }
+ // return false if compared values are equal otherwise true
+ bool operator()(const OSortIndex::TIntValuePairVector::value_type& lhs,const OSortIndex::TIntValuePairVector::value_type& rhs) const
+ {
+ const std::vector<OKeyType>& aKeyType = pIndex->getKeyType();
+ size_t i = 0;
+ for (auto const& elem : aKeyType)
+ {
+ const bool bGreater = pIndex->getAscending(i) != TAscendingOrder::ASC;
+ const bool bLess = !bGreater;
+
+ // compare depending for type
+ switch (elem)
+ {
+ case OKeyType::String:
+ {
+ sal_Int32 nRes = lhs.second->getKeyString(i).compareTo(rhs.second->getKeyString(i));
+ if (nRes < 0)
+ return bLess;
+ else if (nRes > 0)
+ return bGreater;
+ }
+ break;
+ case OKeyType::Double:
+ {
+ double d1 = lhs.second->getKeyDouble(i);
+ double d2 = rhs.second->getKeyDouble(i);
+
+ if (d1 < d2)
+ return bLess;
+ else if (d1 > d2)
+ return bGreater;
+ }
+ break;
+ case OKeyType::NONE:
+ break;
+ }
+ ++i;
+ }
+
+ // know we know that the values are equal
+ return false;
+ }
+};
+
+}
+
+::rtl::Reference<OKeySet> OSortIndex::CreateKeySet()
+{
+ Freeze();
+
+ ::rtl::Reference<OKeySet> pKeySet = new OKeySet();
+ pKeySet->reserve(m_aKeyValues.size());
+ std::transform(m_aKeyValues.begin()
+ ,m_aKeyValues.end()
+ ,std::back_inserter(*pKeySet)
+ ,::o3tl::select1st<TIntValuePairVector::value_type>());
+ pKeySet->setFrozen();
+ return pKeySet;
+}
+
+OSortIndex::OSortIndex( std::vector<OKeyType>&& _aKeyType,
+ std::vector<TAscendingOrder>&& _aAscending)
+ :m_aKeyType(std::move(_aKeyType))
+ ,m_aAscending(std::move(_aAscending))
+ ,m_bFrozen(false)
+{
+}
+
+OSortIndex::~OSortIndex()
+{
+}
+
+void OSortIndex::AddKeyValue(std::unique_ptr<OKeyValue> pKeyValue)
+{
+ assert(pKeyValue && "Can not be null here!");
+ if(m_bFrozen)
+ {
+ m_aKeyValues.push_back({pKeyValue->getValue(),nullptr});
+ }
+ else
+ m_aKeyValues.push_back({pKeyValue->getValue(),std::move(pKeyValue)});
+}
+
+void OSortIndex::Freeze()
+{
+ OSL_ENSURE(! m_bFrozen,"OSortIndex::Freeze: already frozen!");
+ // sorting:
+ if (m_aKeyType[0] != OKeyType::NONE)
+ // we will sort ourself when the first keyType say so
+ std::sort(m_aKeyValues.begin(),m_aKeyValues.end(),TKeyValueFunc(this));
+
+ for (auto & keyValue : m_aKeyValues)
+ {
+ keyValue.second.reset();
+ }
+
+ m_bFrozen = true;
+}
+
+
+OKeyValue::OKeyValue(sal_Int32 nVal)
+: m_nValue(nVal)
+{
+}
+
+OKeyValue::~OKeyValue()
+{
+}
+
+std::unique_ptr<OKeyValue> OKeyValue::createKeyValue(sal_Int32 _nVal)
+{
+ return std::unique_ptr<OKeyValue>(new OKeyValue(_nVal));
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/commontools/TTableHelper.cxx b/connectivity/source/commontools/TTableHelper.cxx
new file mode 100644
index 0000000000..31e2404694
--- /dev/null
+++ b/connectivity/source/commontools/TTableHelper.cxx
@@ -0,0 +1,610 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+#include <sal/log.hxx>
+
+#include <connectivity/TTableHelper.hxx>
+#include <com/sun/star/sdb/tools/XTableRename.hpp>
+#include <com/sun/star/sdb/tools/XTableAlteration.hpp>
+#include <com/sun/star/sdb/tools/XKeyAlteration.hpp>
+#include <com/sun/star/sdb/tools/XIndexAlteration.hpp>
+#include <sdbcx/VKey.hxx>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XResultSet.hpp>
+#include <com/sun/star/sdbcx/KeyType.hpp>
+#include <cppuhelper/implbase.hxx>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <comphelper/types.hxx>
+#include <connectivity/dbtools.hxx>
+#include <connectivity/sdbcx/VCollection.hxx>
+#include <unotools/sharedunocomponent.hxx>
+#include <TConnection.hxx>
+
+#include <o3tl/functional.hxx>
+
+#include <iterator>
+#include <set>
+
+using namespace ::comphelper;
+using namespace connectivity;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+
+namespace
+{
+ /// helper class for column property change events which holds the OComponentDefinition weak
+class OTableContainerListener:
+ public ::cppu::WeakImplHelper< XContainerListener >
+{
+ OTableHelper* m_pComponent;
+ std::map< OUString,bool> m_aRefNames;
+
+protected:
+ virtual ~OTableContainerListener() override {}
+public:
+ explicit OTableContainerListener(OTableHelper* _pComponent) : m_pComponent(_pComponent){}
+ // noncopyable
+ OTableContainerListener(const OTableContainerListener&) = delete;
+ const OTableContainerListener& operator=(const OTableContainerListener&) = delete;
+ virtual void SAL_CALL elementInserted( const css::container::ContainerEvent& /*Event*/ ) override
+ {
+ }
+ virtual void SAL_CALL elementRemoved( const css::container::ContainerEvent& Event ) override
+ {
+ // tdf#137745, perhaps connectivity::OTableHelper::disposing() has been called
+ // which called OTableContainerListener::clear(), so m_pComponent may be null
+ if (m_pComponent == nullptr)
+ return;
+
+ OUString sName;
+ Event.Accessor >>= sName;
+ if ( m_aRefNames.find(sName) != m_aRefNames.end() )
+ m_pComponent->refreshKeys();
+ }
+ virtual void SAL_CALL elementReplaced( const css::container::ContainerEvent& Event ) override
+ {
+ OUString sOldComposedName,sNewComposedName;
+ Event.ReplacedElement >>= sOldComposedName;
+ Event.Accessor >>= sNewComposedName;
+ if ( sOldComposedName != sNewComposedName && m_aRefNames.find(sOldComposedName) != m_aRefNames.end() )
+ m_pComponent->refreshKeys();
+ }
+ // XEventListener
+ virtual void SAL_CALL disposing( const EventObject& /*_rSource*/ ) override
+ {
+ }
+ void clear() { m_pComponent = nullptr; }
+ void add(const OUString& _sRefName) { m_aRefNames.emplace(_sRefName,true); }
+};
+}
+namespace connectivity
+{
+ static OUString lcl_getServiceNameForSetting(const Reference< css::sdbc::XConnection >& _xConnection,const OUString& i_sSetting)
+ {
+ OUString sSupportService;
+ Any aValue;
+ if ( ::dbtools::getDataSourceSetting(_xConnection,i_sSetting,aValue) )
+ {
+ aValue >>= sSupportService;
+ }
+ return sSupportService;
+ }
+ struct OTableHelperImpl
+ {
+ TKeyMap m_aKeys;
+ // helper services which can be provided by extensions
+ Reference< css::sdb::tools::XTableRename> m_xRename;
+ Reference< css::sdb::tools::XTableAlteration> m_xAlter;
+ Reference< css::sdb::tools::XKeyAlteration> m_xKeyAlter;
+ Reference< css::sdb::tools::XIndexAlteration> m_xIndexAlter;
+
+ Reference< css::sdbc::XDatabaseMetaData > m_xMetaData;
+ Reference< css::sdbc::XConnection > m_xConnection;
+ rtl::Reference<OTableContainerListener> m_xTablePropertyListener;
+ std::vector< ColumnDesc > m_aColumnDesc;
+ explicit OTableHelperImpl(const Reference< css::sdbc::XConnection >& _xConnection)
+ : m_xConnection(_xConnection)
+ {
+ try
+ {
+ m_xMetaData = m_xConnection->getMetaData();
+ Reference<XMultiServiceFactory> xFac(_xConnection,UNO_QUERY);
+ if ( xFac.is() )
+ {
+ m_xRename.set(xFac->createInstance(lcl_getServiceNameForSetting(m_xConnection,"TableRenameServiceName")),UNO_QUERY);
+ m_xAlter.set(xFac->createInstance(lcl_getServiceNameForSetting(m_xConnection,"TableAlterationServiceName")),UNO_QUERY);
+ m_xKeyAlter.set(xFac->createInstance(lcl_getServiceNameForSetting(m_xConnection,"KeyAlterationServiceName")),UNO_QUERY);
+ m_xIndexAlter.set(xFac->createInstance(lcl_getServiceNameForSetting(m_xConnection,"IndexAlterationServiceName")),UNO_QUERY);
+ }
+ }
+ catch(const Exception&)
+ {
+ }
+ }
+ };
+}
+
+OTableHelper::OTableHelper( sdbcx::OCollection* _pTables,
+ const Reference< XConnection >& _xConnection,
+ bool _bCase)
+ :OTable_TYPEDEF(_pTables,_bCase)
+ ,m_pImpl(new OTableHelperImpl(_xConnection))
+{
+}
+
+OTableHelper::OTableHelper( sdbcx::OCollection* _pTables,
+ const Reference< XConnection >& _xConnection,
+ bool _bCase,
+ const OUString& Name,
+ const OUString& Type,
+ const OUString& Description ,
+ const OUString& SchemaName,
+ const OUString& CatalogName
+ ) : OTable_TYPEDEF(_pTables,
+ _bCase,
+ Name,
+ Type,
+ Description,
+ SchemaName,
+ CatalogName)
+ ,m_pImpl(new OTableHelperImpl(_xConnection))
+{
+}
+
+OTableHelper::~OTableHelper()
+{
+}
+
+void SAL_CALL OTableHelper::disposing()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ if ( m_pImpl->m_xTablePropertyListener.is() )
+ {
+ m_pTables->removeContainerListener(m_pImpl->m_xTablePropertyListener);
+ m_pImpl->m_xTablePropertyListener->clear();
+ m_pImpl->m_xTablePropertyListener.clear();
+ }
+ OTable_TYPEDEF::disposing();
+
+ m_pImpl->m_xConnection = nullptr;
+ m_pImpl->m_xMetaData = nullptr;
+
+}
+
+
+namespace
+{
+ /** collects ColumnDesc's from a resultset produced by XDatabaseMetaData::getColumns
+ */
+ void lcl_collectColumnDescs_throw( const Reference< XResultSet >& _rxResult, std::vector< ColumnDesc >& _out_rColumns )
+ {
+ Reference< XRow > xRow( _rxResult, UNO_QUERY_THROW );
+ OUString sName;
+ OrdinalPosition nOrdinalPosition( 0 );
+ while ( _rxResult->next() )
+ {
+ sName = xRow->getString( 4 ); // COLUMN_NAME
+ sal_Int32 nField5 = xRow->getInt(5);
+ OUString aField6 = xRow->getString(6);
+ sal_Int32 nField7 = xRow->getInt(7)
+ , nField9 = xRow->getInt(9)
+ , nField11= xRow->getInt(11);
+ OUString sField12 = xRow->getString(12)
+ ,sField13 = xRow->getString(13);
+ nOrdinalPosition = xRow->getInt( 17 ); // ORDINAL_POSITION
+ _out_rColumns.push_back( ColumnDesc( sName,nField5,aField6,nField7,nField9,nField11,sField12,sField13, nOrdinalPosition ) );
+ }
+ }
+
+ /** checks a given array of ColumnDesc's whether it has reasonable ordinal positions. If not,
+ they will be normalized to be the array index.
+ */
+ void lcl_sanitizeColumnDescs( std::vector< ColumnDesc >& _rColumns )
+ {
+ if ( _rColumns.empty() )
+ return;
+
+ // collect all used ordinals
+ std::set< OrdinalPosition > aUsedOrdinals;
+ for ( const auto& collect : _rColumns )
+ aUsedOrdinals.insert( collect.nOrdinalPosition );
+
+ // we need to have as much different ordinals as we have different columns
+ bool bDuplicates = aUsedOrdinals.size() != _rColumns.size();
+ // and it needs to be a continuous range
+ size_t nOrdinalsRange = *aUsedOrdinals.rbegin() - *aUsedOrdinals.begin() + 1;
+ bool bGaps = nOrdinalsRange != _rColumns.size();
+
+ // if that's not the case, normalize it
+ if ( bGaps || bDuplicates )
+ {
+ OSL_FAIL( "lcl_sanitizeColumnDescs: database did provide invalid ORDINAL_POSITION values!" );
+
+ OrdinalPosition nNormalizedPosition = 1;
+ for ( auto& normalize : _rColumns )
+ normalize.nOrdinalPosition = nNormalizedPosition++;
+ return;
+ }
+
+ // what's left is that the range might not be from 1 to <column count>, but for instance
+ // 0 to <column count>-1.
+ size_t nOffset = *aUsedOrdinals.begin() - 1;
+ for ( auto& offset : _rColumns )
+ offset.nOrdinalPosition -= nOffset;
+ }
+}
+
+
+void OTableHelper::refreshColumns()
+{
+ ::std::vector< OUString> aVector;
+ if(!isNew())
+ {
+ Any aCatalog;
+ if ( !m_CatalogName.isEmpty() )
+ aCatalog <<= m_CatalogName;
+
+ ::utl::SharedUNOComponent< XResultSet > xResult( getMetaData()->getColumns(
+ aCatalog,
+ m_SchemaName,
+ m_Name,
+ "%"
+ ) );
+
+ // collect the column names, together with their ordinal position
+ m_pImpl->m_aColumnDesc.clear();
+ lcl_collectColumnDescs_throw( xResult, m_pImpl->m_aColumnDesc );
+
+ // ensure that the ordinal positions as obtained from the meta data do make sense
+ lcl_sanitizeColumnDescs( m_pImpl->m_aColumnDesc );
+
+ // sort by ordinal position
+ std::map< OrdinalPosition, OUString > aSortedColumns;
+ for (const auto& copy : m_pImpl->m_aColumnDesc)
+ aSortedColumns[ copy.nOrdinalPosition ] = copy.sName;
+
+ // copy them to aVector, now that we have the proper ordering
+ std::transform(
+ aSortedColumns.begin(),
+ aSortedColumns.end(),
+ std::insert_iterator< ::std::vector< OUString> >( aVector, aVector.begin() ),
+ ::o3tl::select2nd< std::map< OrdinalPosition, OUString >::value_type >()
+ );
+ }
+
+ if(m_xColumns)
+ m_xColumns->reFill(aVector);
+ else
+ m_xColumns.reset(createColumns(aVector));
+}
+
+const ColumnDesc* OTableHelper::getColumnDescription(const OUString& _sName) const
+{
+ const ColumnDesc* pRet = nullptr;
+ auto aIter = std::find_if(m_pImpl->m_aColumnDesc.begin(), m_pImpl->m_aColumnDesc.end(),
+ [&_sName](const ColumnDesc& rColumnDesc) { return rColumnDesc.sName == _sName; });
+ if (aIter != m_pImpl->m_aColumnDesc.end())
+ pRet = &*aIter;
+ return pRet;
+}
+
+void OTableHelper::refreshPrimaryKeys(::std::vector< OUString>& _rNames)
+{
+ Any aCatalog;
+ if ( !m_CatalogName.isEmpty() )
+ aCatalog <<= m_CatalogName;
+ Reference< XResultSet > xResult = getMetaData()->getPrimaryKeys(aCatalog,m_SchemaName,m_Name);
+
+ if ( xResult.is() )
+ {
+ auto pKeyProps = std::make_shared<sdbcx::KeyProperties>(OUString(),KeyType::PRIMARY,0,0);
+ OUString aPkName;
+ bool bAlreadyFetched = false;
+ const Reference< XRow > xRow(xResult,UNO_QUERY);
+ while ( xResult->next() )
+ {
+ pKeyProps->m_aKeyColumnNames.push_back(xRow->getString(4));
+ if ( !bAlreadyFetched )
+ {
+ aPkName = xRow->getString(6);
+ SAL_WARN_IF(xRow->wasNull(),"connectivity.commontools", "NULL Primary Key name");
+ SAL_WARN_IF(aPkName.isEmpty(),"connectivity.commontools", "empty Primary Key name");
+ bAlreadyFetched = true;
+ }
+ }
+
+ if(bAlreadyFetched)
+ {
+ SAL_WARN_IF(aPkName.isEmpty(),"connectivity.commontools", "empty Primary Key name");
+ SAL_WARN_IF(pKeyProps->m_aKeyColumnNames.empty(),"connectivity.commontools", "Primary Key has no columns");
+ m_pImpl->m_aKeys.emplace(aPkName,pKeyProps);
+ _rNames.push_back(aPkName);
+ }
+ } // if ( xResult.is() && xResult->next() )
+ ::comphelper::disposeComponent(xResult);
+}
+
+void OTableHelper::refreshForeignKeys(::std::vector< OUString>& _rNames)
+{
+ Any aCatalog;
+ if ( !m_CatalogName.isEmpty() )
+ aCatalog <<= m_CatalogName;
+ Reference< XResultSet > xResult = getMetaData()->getImportedKeys(aCatalog,m_SchemaName,m_Name);
+ Reference< XRow > xRow(xResult,UNO_QUERY);
+
+ if ( !xRow.is() )
+ return;
+
+ std::shared_ptr<sdbcx::KeyProperties> pKeyProps;
+ OUString aName,sCatalog,aSchema,sOldFKName;
+ while( xResult->next() )
+ {
+ // this must be outside the "if" because we have to call in a right order
+ sCatalog = xRow->getString(1);
+ if ( xRow->wasNull() )
+ sCatalog.clear();
+ aSchema = xRow->getString(2);
+ aName = xRow->getString(3);
+
+ const OUString sForeignKeyColumn = xRow->getString(8);
+ const sal_Int32 nUpdateRule = xRow->getInt(10);
+ const sal_Int32 nDeleteRule = xRow->getInt(11);
+ const OUString sFkName = xRow->getString(12);
+
+ if ( !sFkName.isEmpty() && !xRow->wasNull() )
+ {
+ if ( sOldFKName != sFkName )
+ {
+ if ( pKeyProps )
+ m_pImpl->m_aKeys.emplace(sOldFKName,pKeyProps);
+
+ const OUString sReferencedName = ::dbtools::composeTableName(getMetaData(),sCatalog,aSchema,aName,false,::dbtools::EComposeRule::InDataManipulation);
+ pKeyProps = std::make_shared<sdbcx::KeyProperties>(sReferencedName,KeyType::FOREIGN,nUpdateRule,nDeleteRule);
+ pKeyProps->m_aKeyColumnNames.push_back(sForeignKeyColumn);
+ _rNames.push_back(sFkName);
+ if ( m_pTables->hasByName(sReferencedName) )
+ {
+ if ( !m_pImpl->m_xTablePropertyListener.is() )
+ m_pImpl->m_xTablePropertyListener = new OTableContainerListener(this);
+ m_pTables->addContainerListener(m_pImpl->m_xTablePropertyListener);
+ m_pImpl->m_xTablePropertyListener->add(sReferencedName);
+ } // if ( m_pTables->hasByName(sReferencedName) )
+ sOldFKName = sFkName;
+ } // if ( sOldFKName != sFkName )
+ else if ( pKeyProps )
+ {
+ pKeyProps->m_aKeyColumnNames.push_back(sForeignKeyColumn);
+ }
+ }
+ } // while( xResult->next() )
+ if ( pKeyProps )
+ m_pImpl->m_aKeys.emplace(sOldFKName,pKeyProps);
+ ::comphelper::disposeComponent(xResult);
+}
+
+void OTableHelper::refreshKeys()
+{
+ m_pImpl->m_aKeys.clear();
+
+ ::std::vector< OUString> aNames;
+
+ if(!isNew())
+ {
+ refreshPrimaryKeys(aNames);
+ refreshForeignKeys(aNames);
+ m_xKeys.reset(createKeys(aNames));
+ } // if(!isNew())
+ else if (!m_xKeys )
+ m_xKeys.reset(createKeys(aNames));
+ /*if(m_pKeys)
+ m_pKeys->reFill(aVector);
+ else*/
+
+}
+
+void OTableHelper::refreshIndexes()
+{
+ ::std::vector< OUString> aVector;
+ if(!isNew())
+ {
+ // fill indexes
+ Any aCatalog;
+ if ( !m_CatalogName.isEmpty() )
+ aCatalog <<= m_CatalogName;
+ Reference< XResultSet > xResult = getMetaData()->getIndexInfo(aCatalog,m_SchemaName,m_Name,false,false);
+
+ if(xResult.is())
+ {
+ Reference< XRow > xRow(xResult,UNO_QUERY);
+ OUString sCatalogSep = getMetaData()->getCatalogSeparator();
+ OUString sPreviousRoundName;
+ while( xResult->next() )
+ {
+ OUString aName = xRow->getString(5);
+ if(!aName.isEmpty())
+ aName += sCatalogSep;
+ aName += xRow->getString(6);
+ if ( !aName.isEmpty() )
+ {
+ // don't insert the name if the last one we inserted was the same
+ if (sPreviousRoundName != aName)
+ aVector.push_back(aName);
+ }
+ sPreviousRoundName = aName;
+ }
+ ::comphelper::disposeComponent(xResult);
+ }
+ }
+
+ if(m_xIndexes)
+ m_xIndexes->reFill(aVector);
+ else
+ m_xIndexes.reset(createIndexes(aVector));
+}
+
+OUString OTableHelper::getRenameStart() const
+{
+ OUString sSql("RENAME ");
+ if ( m_Type == "VIEW" )
+ sSql += " VIEW ";
+ else
+ sSql += " TABLE ";
+
+ return sSql;
+}
+
+// XRename
+void SAL_CALL OTableHelper::rename( const OUString& newName )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(
+#ifdef __GNUC__
+ ::connectivity::sdbcx::OTableDescriptor_BASE::rBHelper.bDisposed
+#else
+ rBHelper.bDisposed
+#endif
+ );
+
+ if(!isNew())
+ {
+ if ( m_pImpl->m_xRename.is() )
+ {
+ m_pImpl->m_xRename->rename(this,newName);
+ }
+ else
+ {
+ OUString sSql = getRenameStart();
+
+ OUString sCatalog,sSchema,sTable;
+ ::dbtools::qualifiedNameComponents(getMetaData(),newName,sCatalog,sSchema,sTable,::dbtools::EComposeRule::InDataManipulation);
+
+ OUString sComposedName;
+ sComposedName = ::dbtools::composeTableName(getMetaData(),m_CatalogName,m_SchemaName,m_Name,true,::dbtools::EComposeRule::InDataManipulation);
+ sSql += sComposedName
+ + " TO ";
+ sComposedName = ::dbtools::composeTableName(getMetaData(),sCatalog,sSchema,sTable,true,::dbtools::EComposeRule::InDataManipulation);
+ sSql += sComposedName;
+
+ Reference< XStatement > xStmt = m_pImpl->m_xConnection->createStatement( );
+ if ( xStmt.is() )
+ {
+ xStmt->execute(sSql);
+ ::comphelper::disposeComponent(xStmt);
+ }
+ }
+
+ OTable_TYPEDEF::rename(newName);
+ }
+ else
+ ::dbtools::qualifiedNameComponents(getMetaData(),newName,m_CatalogName,m_SchemaName,m_Name,::dbtools::EComposeRule::InTableDefinitions);
+}
+
+Reference< XDatabaseMetaData> OTableHelper::getMetaData() const
+{
+ return m_pImpl->m_xMetaData;
+}
+
+void SAL_CALL OTableHelper::alterColumnByIndex( sal_Int32 index, const Reference< XPropertySet >& descriptor )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(
+#ifdef __GNUC__
+ ::connectivity::sdbcx::OTableDescriptor_BASE::rBHelper.bDisposed
+#else
+ rBHelper.bDisposed
+#endif
+ );
+
+ Reference< XPropertySet > xOld(
+ m_xColumns->getByIndex(index), css::uno::UNO_QUERY);
+ if(xOld.is())
+ alterColumnByName(getString(xOld->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME))),descriptor);
+}
+
+
+OUString SAL_CALL OTableHelper::getName()
+{
+ OUString sComposedName = ::dbtools::composeTableName(getMetaData(),m_CatalogName,m_SchemaName,m_Name,false,::dbtools::EComposeRule::InDataManipulation);
+ return sComposedName;
+}
+
+const OUString & OTableHelper::getTableName()
+{
+ return m_Name;
+}
+
+std::shared_ptr<sdbcx::KeyProperties> OTableHelper::getKeyProperties(const OUString& _sName) const
+{
+ std::shared_ptr<sdbcx::KeyProperties> pKeyProps;
+ TKeyMap::const_iterator aFind = m_pImpl->m_aKeys.find(_sName);
+ if ( aFind != m_pImpl->m_aKeys.end() )
+ {
+ pKeyProps = aFind->second;
+ }
+ else // only a fall back
+ {
+ OSL_FAIL("No key with the given name found");
+ pKeyProps = std::make_shared<sdbcx::KeyProperties>();
+ }
+
+ return pKeyProps;
+}
+
+void OTableHelper::addKey(const OUString& _sName,const std::shared_ptr<sdbcx::KeyProperties>& _aKeyProperties)
+{
+ m_pImpl->m_aKeys.emplace(_sName,_aKeyProperties);
+}
+
+OUString OTableHelper::getTypeCreatePattern() const
+{
+ return OUString();
+}
+
+Reference< XConnection> const & OTableHelper::getConnection() const
+{
+ return m_pImpl->m_xConnection;
+}
+
+Reference< css::sdb::tools::XTableRename> const & OTableHelper::getRenameService() const
+{
+ return m_pImpl->m_xRename;
+}
+
+Reference< css::sdb::tools::XTableAlteration> const & OTableHelper::getAlterService() const
+{
+ return m_pImpl->m_xAlter;
+}
+
+Reference< css::sdb::tools::XKeyAlteration> const & OTableHelper::getKeyService() const
+{
+ return m_pImpl->m_xKeyAlter;
+}
+
+Reference< css::sdb::tools::XIndexAlteration> const & OTableHelper::getIndexService() const
+{
+ return m_pImpl->m_xIndexAlter;
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/commontools/conncleanup.cxx b/connectivity/source/commontools/conncleanup.cxx
new file mode 100644
index 0000000000..7b703f093c
--- /dev/null
+++ b/connectivity/source/commontools/conncleanup.cxx
@@ -0,0 +1,230 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <connectivity/conncleanup.hxx>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/lang/XComponent.hpp>
+#include <com/sun/star/sdbc/XRowSet.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <osl/diagnose.h>
+#include <comphelper/diagnose_ex.hxx>
+
+
+namespace dbtools
+{
+
+
+ using namespace css::uno;
+ using namespace css::beans;
+ using namespace css::sdbc;
+ using namespace css::lang;
+
+ constexpr OUString ACTIVE_CONNECTION_PROPERTY_NAME = u"ActiveConnection"_ustr;
+
+ OAutoConnectionDisposer::OAutoConnectionDisposer(const Reference< XRowSet >& _rxRowSet, const Reference< XConnection >& _rxConnection)
+ :m_xRowSet( _rxRowSet )
+ ,m_bRSListening( false )
+ ,m_bPropertyListening( false )
+ {
+ Reference< XPropertySet > xProps(_rxRowSet, UNO_QUERY);
+ OSL_ENSURE(xProps.is(), "OAutoConnectionDisposer::OAutoConnectionDisposer: invalid rowset (no XPropertySet)!");
+
+ if (!xProps.is())
+ return;
+
+ try
+ {
+ xProps->setPropertyValue( ACTIVE_CONNECTION_PROPERTY_NAME, Any( _rxConnection ) );
+ m_xOriginalConnection = _rxConnection;
+ startPropertyListening( xProps );
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "connectivity.commontools", "OAutoConnectionDisposer::OAutoConnectionDisposer" );
+ }
+ }
+
+
+ void OAutoConnectionDisposer::startPropertyListening( const Reference< XPropertySet >& _rxRowSet )
+ {
+ try
+ {
+ _rxRowSet->addPropertyChangeListener( ACTIVE_CONNECTION_PROPERTY_NAME, this );
+ m_bPropertyListening = true;
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "connectivity.commontools", "OAutoConnectionDisposer::startPropertyListening" );
+ }
+ }
+
+
+ void OAutoConnectionDisposer::stopPropertyListening( const Reference< XPropertySet >& _rxEventSource )
+ {
+ // prevent deletion of ourself while we're herein
+ Reference< XInterface > xKeepAlive(getXWeak());
+
+ try
+ { // remove ourself as property change listener
+ OSL_ENSURE( _rxEventSource.is(), "OAutoConnectionDisposer::stopPropertyListening: invalid event source (no XPropertySet)!" );
+ if ( _rxEventSource.is() )
+ {
+ _rxEventSource->removePropertyChangeListener( ACTIVE_CONNECTION_PROPERTY_NAME, this );
+ m_bPropertyListening = false;
+ }
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "connectivity.commontools", "OAutoConnectionDisposer::stopPropertyListening" );
+ }
+ }
+
+
+ void OAutoConnectionDisposer::startRowSetListening()
+ {
+ OSL_ENSURE( !m_bRSListening, "OAutoConnectionDisposer::startRowSetListening: already listening!" );
+ try
+ {
+ if ( !m_bRSListening )
+ m_xRowSet->addRowSetListener( this );
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "connectivity.commontools", "OAutoConnectionDisposer::startRowSetListening" );
+ }
+ m_bRSListening = true;
+ }
+
+
+ void OAutoConnectionDisposer::stopRowSetListening()
+ {
+ OSL_ENSURE( m_bRSListening, "OAutoConnectionDisposer::stopRowSetListening: not listening!" );
+ try
+ {
+ m_xRowSet->removeRowSetListener( this );
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "connectivity.commontools", "OAutoConnectionDisposer::stopRowSetListening" );
+ }
+ m_bRSListening = false;
+ }
+
+
+ void SAL_CALL OAutoConnectionDisposer::propertyChange( const PropertyChangeEvent& _rEvent )
+ {
+ if ( _rEvent.PropertyName != ACTIVE_CONNECTION_PROPERTY_NAME )
+ return;
+
+// somebody set a new ActiveConnection
+
+ Reference< XConnection > xNewConnection;
+ _rEvent.NewValue >>= xNewConnection;
+
+ if ( isRowSetListening() )
+ {
+ // we're listening at the row set, this means that the row set does not have our
+ // m_xOriginalConnection as active connection anymore
+ // So there are two possibilities
+ // a. somebody sets a new connection which is not our original one
+ // b. somebody sets a new connection, which is exactly the original one
+ // a. we're not interested in a, but in b: In this case, we simply need to move to the state
+ // we had originally: listen for property changes, do not listen for row set changes, and
+ // do not dispose the connection until the row set does not need it anymore
+ if ( xNewConnection.get() == m_xOriginalConnection.get() )
+ {
+ stopRowSetListening();
+ }
+ }
+ else
+ {
+ // start listening at the row set. We're allowed to dispose the old connection as soon
+ // as the RowSet changed
+
+ // Unfortunately, the our database form implementations sometimes fire the change of their
+ // ActiveConnection twice. This is an error in forms/source/component/DatabaseForm.cxx, but
+ // changing this would require incompatible changes we can't do for a while.
+ // So for the moment, we have to live with it here.
+ //
+ // The only scenario where this doubled notification causes problems is when the connection
+ // of the form is reset to the one we're responsible for (m_xOriginalConnection), so we
+ // check this here.
+ //
+ // Yes, this is a HACK :(
+ if ( xNewConnection.get() != m_xOriginalConnection.get() )
+ {
+#if OSL_DEBUG_LEVEL > 0
+ Reference< XConnection > xOldConnection;
+ _rEvent.OldValue >>= xOldConnection;
+ OSL_ENSURE( xOldConnection.get() == m_xOriginalConnection.get(), "OAutoConnectionDisposer::propertyChange: unexpected (original) property value!" );
+#endif
+ startRowSetListening();
+ }
+ }
+ }
+
+
+ void SAL_CALL OAutoConnectionDisposer::disposing( const EventObject& _rSource )
+ {
+ // the rowset is being disposed, and nobody has set a new ActiveConnection in the meantime
+ if ( isRowSetListening() )
+ stopRowSetListening();
+
+ clearConnection();
+
+ if ( m_bPropertyListening )
+ stopPropertyListening( Reference< XPropertySet >( _rSource.Source, UNO_QUERY ) );
+ }
+
+ void OAutoConnectionDisposer::clearConnection()
+ {
+ try
+ {
+ // dispose the old connection
+ Reference< XComponent > xComp(m_xOriginalConnection, UNO_QUERY);
+ if (xComp.is())
+ xComp->dispose();
+ m_xOriginalConnection.clear();
+ }
+ catch(Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("connectivity.commontools", "OAutoConnectionDisposer::clearConnection");
+ }
+ }
+
+ void SAL_CALL OAutoConnectionDisposer::cursorMoved( const css::lang::EventObject& /*event*/ )
+ {
+ }
+
+ void SAL_CALL OAutoConnectionDisposer::rowChanged( const css::lang::EventObject& /*event*/ )
+ {
+ }
+
+ void SAL_CALL OAutoConnectionDisposer::rowSetChanged( const css::lang::EventObject& /*event*/ )
+ {
+ stopRowSetListening();
+ clearConnection();
+
+ }
+
+
+} // namespace dbtools
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/commontools/dbcharset.cxx b/connectivity/source/commontools/dbcharset.cxx
new file mode 100644
index 0000000000..381afa606e
--- /dev/null
+++ b/connectivity/source/commontools/dbcharset.cxx
@@ -0,0 +1,191 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <connectivity/dbcharset.hxx>
+#include <utility>
+#include <osl/diagnose.h>
+#include <rtl/tencinfo.h>
+
+
+namespace dbtools
+{
+
+ OCharsetMap::OCharsetMap()
+ {
+ }
+
+
+ void OCharsetMap::lateConstruct()
+ {
+ const rtl_TextEncoding eFirstEncoding = RTL_TEXTENCODING_DONTKNOW;
+ const rtl_TextEncoding eLastEncoding = 100; // TODO: a define in rtl/textenc.h would be fine here ...
+ OSL_ENSURE( 0 == eFirstEncoding, "OCharsetMap::OCharsetMap: somebody changed the numbers!" );
+
+ rtl_TextEncodingInfo aInfo; aInfo.StructSize = sizeof( rtl_TextEncodingInfo );
+ for ( rtl_TextEncoding eEncoding = eFirstEncoding; eEncoding < eLastEncoding; ++eEncoding )
+ {
+ if ( ( RTL_TEXTENCODING_DONTKNOW == eEncoding ) // this is always allowed - it has the special meaning "system encoding"
+ || ( rtl_getTextEncodingInfo( eEncoding, &aInfo )
+ && approveEncoding( eEncoding, aInfo )
+ )
+ )
+ {
+ m_aEncodings.insert( eEncoding );
+ }
+ }
+
+ OSL_ENSURE( find( RTL_TEXTENCODING_MS_1252 ) != end(), "OCharsetMap::lateConstruct: missing compatibility encoding ANSI!" );
+ OSL_ENSURE( find( RTL_TEXTENCODING_APPLE_ROMAN ) != end(), "OCharsetMap::lateConstruct: missing compatibility encoding macintosh!" );
+ OSL_ENSURE( find( RTL_TEXTENCODING_IBM_437 ) != end(), "OCharsetMap::lateConstruct: missing compatibility encoding IBM437!" );
+ OSL_ENSURE( find( RTL_TEXTENCODING_IBM_850) != end(), "OCharsetMap::lateConstruct: missing compatibility encoding IBM850!" );
+ OSL_ENSURE( find( RTL_TEXTENCODING_IBM_860 ) != end(), "OCharsetMap::lateConstruct: missing compatibility encoding IBM860!" );
+ OSL_ENSURE( find( RTL_TEXTENCODING_IBM_861 ) != end(), "OCharsetMap::lateConstruct: missing compatibility encoding IBM861!" );
+ OSL_ENSURE( find( RTL_TEXTENCODING_IBM_863 ) != end(), "OCharsetMap::lateConstruct: missing compatibility encoding IBM863!" );
+ OSL_ENSURE( find( RTL_TEXTENCODING_IBM_865 ) != end(), "OCharsetMap::lateConstruct: missing compatibility encoding IBM865!" );
+ OSL_ENSURE( find( RTL_TEXTENCODING_IBM_866 ) != end(), "OCharsetMap::lateConstruct: missing compatibility encoding IBM866!" );
+ OSL_ENSURE( find( RTL_TEXTENCODING_DONTKNOW ) != end(), "OCharsetMap::lateConstruct: missing compatibility encoding SYSTEM!" );
+ OSL_ENSURE( find( RTL_TEXTENCODING_UTF8 ) != end(), "OCharsetMap::lateConstruct: missing compatibility encoding UTF-8!" );
+ OSL_ENSURE( find( RTL_TEXTENCODING_BIG5_HKSCS ) != end(), "OCharsetMap::lateConstruct: missing compatibility encoding Big5-HKSCS!" );
+ }
+
+
+ bool OCharsetMap::approveEncoding( const rtl_TextEncoding _eEncoding, const rtl_TextEncodingInfo& _rInfo ) const
+ {
+ bool bIsMimeEncoding = 0 != ( _rInfo.Flags & RTL_TEXTENCODING_INFO_MIME );
+ OSL_ENSURE( !bIsMimeEncoding || rtl_getMimeCharsetFromTextEncoding( _eEncoding ),
+ "OCharsetMap::OCharsetMap: inconsistence in rtl!" );
+ return bIsMimeEncoding;
+ }
+
+
+ OCharsetMap::~OCharsetMap()
+ {
+ }
+
+
+ OCharsetMap::CharsetIterator OCharsetMap::begin() const
+ {
+ ensureConstructed( );
+ return CharsetIterator(this, m_aEncodings.begin() );
+ }
+
+
+ OCharsetMap::CharsetIterator OCharsetMap::find(const rtl_TextEncoding _eEncoding) const
+ {
+ ensureConstructed( );
+ return CharsetIterator( this, m_aEncodings.find( _eEncoding ) );
+ }
+
+
+ OCharsetMap::CharsetIterator OCharsetMap::findIanaName(std::u16string_view _rIanaName) const
+ {
+ ensureConstructed( );
+
+ rtl_TextEncoding eEncoding = RTL_TEXTENCODING_DONTKNOW;
+ if ( !_rIanaName.empty() )
+ {
+ // byte string conversion
+ OString sMimeByteString = OUStringToOString( _rIanaName, RTL_TEXTENCODING_ASCII_US );
+ // look up
+ eEncoding = rtl_getTextEncodingFromMimeCharset( sMimeByteString.getStr() );
+
+ if ( RTL_TEXTENCODING_DONTKNOW == eEncoding )
+ { // if we're here, the name is not empty, but unknown -> this is an invalid name
+ return end();
+ }
+ }
+
+ return find( eEncoding );
+ }
+
+
+ OCharsetMap::CharsetIterator OCharsetMap::end() const
+ {
+ ensureConstructed( );
+
+ return CharsetIterator( this, m_aEncodings.end() );
+ }
+
+
+ CharsetIteratorDerefHelper::CharsetIteratorDerefHelper( const CharsetIteratorDerefHelper& _rSource )
+ :m_eEncoding( _rSource.m_eEncoding )
+ ,m_aIanaName( _rSource.m_aIanaName )
+ {
+ }
+
+
+ CharsetIteratorDerefHelper:: CharsetIteratorDerefHelper(const rtl_TextEncoding _eEncoding, OUString _aIanaName )
+ :m_eEncoding( _eEncoding )
+ ,m_aIanaName(std::move( _aIanaName ))
+ {
+ }
+
+ OCharsetMap::CharsetIterator::CharsetIterator(const OCharsetMap* _pContainer, OCharsetMap::TextEncBag::const_iterator _aPos )
+ :m_pContainer( _pContainer )
+ ,m_aPos(std::move( _aPos ))
+ {
+ OSL_ENSURE( m_pContainer, "OCharsetMap::CharsetIterator::CharsetIterator : invalid container!" );
+ }
+
+ CharsetIteratorDerefHelper OCharsetMap::CharsetIterator::operator*() const
+ {
+ OSL_ENSURE( m_aPos != m_pContainer->m_aEncodings.end(), "OCharsetMap::CharsetIterator::operator*: invalid position!");
+
+ rtl_TextEncoding eEncoding = *m_aPos;
+ OUString sIanaName;
+
+ if ( RTL_TEXTENCODING_DONTKNOW != eEncoding )
+ { // it's not the virtual "system charset"
+ const char* pIanaName = rtl_getMimeCharsetFromTextEncoding( eEncoding );
+ OSL_ENSURE( pIanaName, "OCharsetMap::CharsetIterator: invalid mime name!" );
+ if ( pIanaName )
+ sIanaName = OUString::createFromAscii( pIanaName );
+ }
+ return CharsetIteratorDerefHelper( eEncoding, sIanaName );
+ }
+
+
+ const OCharsetMap::CharsetIterator& OCharsetMap::CharsetIterator::operator++()
+ {
+ OSL_ENSURE( m_aPos != m_pContainer->m_aEncodings.end(), "OCharsetMap::CharsetIterator::operator++ : invalid position!" );
+ if ( m_aPos != m_pContainer->m_aEncodings.end())
+ ++m_aPos;
+ return *this;
+ }
+
+
+ const OCharsetMap::CharsetIterator& OCharsetMap::CharsetIterator::operator--()
+ {
+ OSL_ENSURE( m_aPos != m_pContainer->m_aEncodings.begin(), "OCharsetMap::CharsetIterator::operator-- : invalid position!" );
+ if ( m_aPos != m_pContainer->m_aEncodings.begin() )
+ --m_aPos;
+ return *this;
+ }
+
+
+ bool operator==(const OCharsetMap::CharsetIterator& lhs, const OCharsetMap::CharsetIterator& rhs)
+ {
+ return ( lhs.m_pContainer == rhs.m_pContainer ) && ( lhs.m_aPos == rhs.m_aPos );
+ }
+
+
+} // namespace dbtools
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/commontools/dbconversion.cxx b/connectivity/source/commontools/dbconversion.cxx
new file mode 100644
index 0000000000..704e168ad7
--- /dev/null
+++ b/connectivity/source/commontools/dbconversion.cxx
@@ -0,0 +1,392 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <connectivity/dbconversion.hxx>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <com/sun/star/util/Date.hpp>
+#include <com/sun/star/util/Time.hpp>
+#include <com/sun/star/util/DateTime.hpp>
+#include <rtl/character.hxx>
+#include <rtl/math.hxx>
+#include <sal/log.hxx>
+#include <unotools/datetime.hxx>
+#include <comphelper/date.hxx>
+#include <o3tl/string_view.hxx>
+#include <sstream>
+#include <iomanip>
+
+namespace
+{
+ const sal_Int64 nanoSecInSec = 1000000000;
+ const sal_Int16 secInMin = 60;
+ const sal_Int16 minInHour = 60;
+
+ const sal_Int64 secMask = 1000000000;
+ const sal_Int64 minMask = 100000000000LL;
+ const sal_Int64 hourMask = 10000000000000LL;
+
+ const double fNanoSecondsPerDay = nanoSecInSec * secInMin * minInHour * 24.0;
+
+ // 32767-12-31 in "(days since 0001-01-01) + 1" format
+ const sal_Int32 maxDays = 11967896;
+ // -32768-01-01 in "(days since 0001-01-01) + 1" format
+ // Yes, I know it is currently unused. Will have to be used
+ // when we implement negative years. Writing down the correct
+ // value for future reference.
+ // *** Please don't remove just because it is unused ***
+ // Lionel Élie Mamane 2017-08-02
+ // const sal_Int32 minDays = -11968270;
+}
+
+
+namespace dbtools
+{
+
+
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::util;
+ using namespace ::com::sun::star::sdb;
+ using namespace ::com::sun::star::sdbc;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::beans;
+
+
+ css::util::Date const & DBTypeConversion::getStandardDate()
+ {
+ static css::util::Date STANDARD_DB_DATE(1,1,1900);
+ return STANDARD_DB_DATE;
+ }
+
+ OUString DBTypeConversion::toDateString(const css::util::Date& rDate)
+ {
+ std::ostringstream ostr;
+ using std::setw;
+ ostr.fill('0');
+ ostr << setw(4) << rDate.Year << "-"
+ << setw(2) << rDate.Month << "-"
+ << setw(2) << rDate.Day;
+ return OUString::createFromAscii(ostr.str());
+ }
+
+ OUString DBTypeConversion::toTimeStringS(const css::util::Time& rTime)
+ {
+ std::ostringstream ostr;
+ using std::setw;
+ ostr.fill('0');
+ ostr << setw(2) << rTime.Hours << ":"
+ << setw(2) << rTime.Minutes << ":"
+ << setw(2) << rTime.Seconds;
+ return OUString::createFromAscii(ostr.str());
+ }
+
+ OUString DBTypeConversion::toTimeString(const css::util::Time& rTime)
+ {
+ std::ostringstream ostr;
+ using std::setw;
+ ostr.fill('0');
+ ostr << setw(2) << rTime.Hours << ":"
+ << setw(2) << rTime.Minutes << ":"
+ << setw(2) << rTime.Seconds << "."
+ << setw(9) << rTime.NanoSeconds;
+ return OUString::createFromAscii(ostr.str());
+ }
+
+ OUString DBTypeConversion::toDateTimeString(const css::util::DateTime& _rDateTime)
+ {
+ css::util::Date aDate(_rDateTime.Day,_rDateTime.Month,_rDateTime.Year);
+ css::util::Time const aTime(_rDateTime.NanoSeconds, _rDateTime.Seconds,
+ _rDateTime.Minutes, _rDateTime.Hours, _rDateTime.IsUTC);
+ return toDateString(aDate) + " " + toTimeString(aTime);
+ }
+
+ css::util::Date DBTypeConversion::toDate(const sal_Int32 _nVal)
+ {
+ css::util::Date aReturn;
+ aReturn.Day = static_cast<sal_uInt16>(_nVal % 100);
+ aReturn.Month = static_cast<sal_uInt16>((_nVal / 100) % 100);
+ aReturn.Year = static_cast<sal_uInt16>(_nVal / 10000);
+ return aReturn;
+ }
+
+
+ css::util::Time DBTypeConversion::toTime(const sal_Int64 _nVal)
+ {
+ css::util::Time aReturn;
+ sal_uInt64 unVal = static_cast<sal_uInt64>(_nVal >= 0 ? _nVal : -_nVal);
+ aReturn.Hours = unVal / hourMask;
+ aReturn.Minutes = (unVal / minMask) % 100;
+ aReturn.Seconds = (unVal / secMask) % 100;
+ aReturn.NanoSeconds = unVal % secMask;
+ return aReturn;
+ }
+
+ sal_Int64 DBTypeConversion::getNsFromTime(const css::util::Time& rVal)
+ {
+ sal_Int32 nHour = rVal.Hours;
+ sal_Int32 nMin = rVal.Minutes;
+ sal_Int32 nSec = rVal.Seconds;
+ sal_Int32 nNanoSec = rVal.NanoSeconds;
+
+ return nNanoSec +
+ nSec * nanoSecInSec +
+ nMin * (secInMin * nanoSecInSec) +
+ nHour * (minInHour * secInMin * nanoSecInSec);
+ }
+
+ static sal_Int32 implRelativeToAbsoluteNull(const css::util::Date& _rDate)
+ {
+ if (_rDate.Day == 0 && _rDate.Month == 0 && _rDate.Year == 0)
+ {
+ // 0000-00-00 is *NOT* a valid date and passing it to the date
+ // conversion even when normalizing rightly asserts. Whatever we
+ // return here, it will be wrong. The old before commit
+ // 52ff16771ac160d27fd7beb78a4cfba22ad84f06 wrong implementation
+ // calculated -365 for that, effectively that would be a date of
+ // -0001-01-01 now but it was likely assumed that would be
+ // 0000-00-01 or even 0000-00-00 instead. Try if we get away with 0
+ // for -0001-12-31, the same that
+ // comphelper::date::convertDateToDaysNormalizing()
+ // would return if comphelper::date::normalize() wouldn't ignore
+ // such "empty" date.
+
+ return 0;
+ }
+ return comphelper::date::convertDateToDaysNormalizing( _rDate.Day, _rDate.Month, _rDate.Year);
+ }
+
+ sal_Int32 DBTypeConversion::toDays(const css::util::Date& _rVal, const css::util::Date& _rNullDate)
+ {
+ return implRelativeToAbsoluteNull(_rVal) - implRelativeToAbsoluteNull(_rNullDate);
+ }
+
+
+ double DBTypeConversion::toDouble(const css::util::Date& rVal, const css::util::Date& _rNullDate)
+ {
+ return static_cast<double>(toDays(rVal, _rNullDate));
+ }
+
+
+ double DBTypeConversion::toDouble(const css::util::Time& rVal)
+ {
+ return static_cast<double>(getNsFromTime(rVal)) / fNanoSecondsPerDay;
+ }
+
+
+ double DBTypeConversion::toDouble(const css::util::DateTime& _rVal, const css::util::Date& _rNullDate)
+ {
+ sal_Int64 nTime = toDays(css::util::Date(_rVal.Day, _rVal.Month, _rVal.Year), _rNullDate);
+ css::util::Time aTimePart;
+
+ aTimePart.Hours = _rVal.Hours;
+ aTimePart.Minutes = _rVal.Minutes;
+ aTimePart.Seconds = _rVal.Seconds;
+ aTimePart.NanoSeconds = _rVal.NanoSeconds;
+
+ return static_cast<double>(nTime) + toDouble(aTimePart);
+ }
+
+ static void addDays(const sal_Int32 nDays, css::util::Date& _rDate)
+ {
+ sal_Int64 nTempDays = implRelativeToAbsoluteNull(_rDate);
+
+ nTempDays += nDays;
+ if ( nTempDays > maxDays )
+ {
+ _rDate.Day = 31;
+ _rDate.Month = 12;
+ _rDate.Year = 9999;
+ }
+ // TODO: can we replace that check by minDays? Would allow dates BCE
+ else if ( nTempDays <= 0 )
+ {
+ _rDate.Day = 1;
+ _rDate.Month = 1;
+ _rDate.Year = 1;
+ }
+ else
+ comphelper::date::convertDaysToDate( nTempDays, _rDate.Day, _rDate.Month, _rDate.Year );
+ }
+
+ static void subDays(const sal_Int32 nDays, css::util::Date& _rDate )
+ {
+ sal_Int64 nTempDays = implRelativeToAbsoluteNull(_rDate);
+
+ nTempDays -= nDays;
+ if ( nTempDays > maxDays )
+ {
+ _rDate.Day = 31;
+ _rDate.Month = 12;
+ _rDate.Year = 9999;
+ }
+ // TODO: can we replace that check by minDays? Would allow dates BCE
+ else if ( nTempDays <= 0 )
+ {
+ _rDate.Day = 1;
+ _rDate.Month = 1;
+ _rDate.Year = 1;
+ }
+ else
+ comphelper::date::convertDaysToDate( nTempDays, _rDate.Day, _rDate.Month, _rDate.Year );
+ }
+
+ css::util::Date DBTypeConversion::toDate(const double dVal, const css::util::Date& _rNullDate)
+ {
+ css::util::Date aRet = _rNullDate;
+
+ if (dVal >= 0)
+ addDays(static_cast<sal_Int32>(dVal),aRet);
+ else
+ subDays(static_cast<sal_uInt32>(-dVal),aRet);
+ // x -= (sal_uInt32)(-nDays);
+
+ return aRet;
+ }
+
+ css::util::Time DBTypeConversion::toTime(const double dVal, short nDigits)
+ {
+ const double nDays = std::trunc(dVal);
+ double fSeconds((dVal - nDays) * (fNanoSecondsPerDay / nanoSecInSec));
+ fSeconds = ::rtl::math::round(fSeconds, nDigits);
+ sal_Int64 nNS = fSeconds * nanoSecInSec;
+
+ sal_Int16 nSign;
+ if ( nNS < 0 )
+ {
+ nNS *= -1;
+ nSign = -1;
+ }
+ else
+ nSign = 1;
+
+ css::util::Time aRet;
+ // normalize time
+ // we have to sal_Int32 here because otherwise we get an overflow
+ sal_Int64 nNanoSeconds = nNS;
+ sal_Int32 nSeconds = nNanoSeconds / nanoSecInSec;
+ sal_Int32 nMinutes = nSeconds / secInMin;
+
+ aRet.NanoSeconds = nNanoSeconds % nanoSecInSec;
+ aRet.Seconds = nSeconds % secInMin;
+ aRet.Hours = nMinutes / minInHour;
+ aRet.Minutes = nMinutes % minInHour;
+
+ // assemble time
+ sal_Int64 nTime = nSign *
+ (aRet.NanoSeconds +
+ aRet.Seconds * secMask +
+ aRet.Minutes * minMask +
+ aRet.Hours * hourMask);
+
+ if(nTime < 0)
+ {
+ aRet.NanoSeconds = nanoSecInSec-1;
+ aRet.Seconds = secInMin-1;
+ aRet.Minutes = minInHour-1;
+ aRet.Hours = 23;
+ }
+ return aRet;
+ }
+
+ css::util::DateTime DBTypeConversion::toDateTime(const double dVal, const css::util::Date& _rNullDate)
+ {
+ css::util::DateTime aRet;
+
+ if (!std::isfinite(dVal))
+ {
+ SAL_WARN("connectivity.commontools", "DateTime has invalid value: " << dVal);
+ return aRet;
+ }
+
+ css::util::Date aDate = toDate(dVal, _rNullDate);
+ // there is not enough precision in a double to have both a date
+ // and a time up to nanoseconds -> limit to microseconds to have
+ // correct rounding, that is e.g. 13:00:00.000000000 instead of
+ // 12:59:59.999999790
+ css::util::Time aTime = toTime(dVal, 6);
+
+ aRet.Day = aDate.Day;
+ aRet.Month = aDate.Month;
+ aRet.Year = aDate.Year;
+
+ aRet.NanoSeconds = aTime.NanoSeconds;
+ aRet.Minutes = aTime.Minutes;
+ aRet.Seconds = aTime.Seconds;
+ aRet.Hours = aTime.Hours;
+
+
+ return aRet;
+ }
+
+ css::util::Date DBTypeConversion::toDate(std::u16string_view _sSQLString)
+ {
+ // get the token out of a string
+ static const sal_Unicode sDateSep = '-';
+
+ sal_Int32 nIndex = 0;
+ sal_uInt16 nYear = 0,
+ nMonth = 0,
+ nDay = 0;
+ nYear = static_cast<sal_uInt16>(o3tl::toInt32(o3tl::getToken(_sSQLString, 0,sDateSep,nIndex)));
+ if(nIndex != -1)
+ {
+ nMonth = static_cast<sal_uInt16>(o3tl::toInt32(o3tl::getToken(_sSQLString, 0,sDateSep,nIndex)));
+ if(nIndex != -1)
+ nDay = static_cast<sal_uInt16>(o3tl::toInt32(o3tl::getToken(_sSQLString, 0,sDateSep,nIndex)));
+ }
+
+ return css::util::Date(nDay,nMonth,nYear);
+ }
+
+
+ css::util::DateTime DBTypeConversion::toDateTime(const OUString& _sSQLString)
+ {
+ //@see http://java.sun.com/j2se/1.4.2/docs/api/java/sql/Timestamp.html#valueOf(java.lang.String)
+ //@see http://java.sun.com/j2se/1.4.2/docs/api/java/sql/Date.html#valueOf(java.lang.String)
+ //@see http://java.sun.com/j2se/1.4.2/docs/api/java/sql/Time.html#valueOf(java.lang.String)
+
+ // the date part
+ css::util::Date aDate = toDate(_sSQLString);
+ css::util::Time aTime;
+ sal_Int32 nSeparation = _sSQLString.indexOf( ' ' );
+ if ( -1 != nSeparation )
+ {
+ const sal_Unicode *p = _sSQLString.getStr() + nSeparation;
+ const sal_Unicode *const begin = p;
+ while (rtl::isAsciiWhiteSpace(*p)) { ++p; }
+ nSeparation += p - begin;
+ aTime = toTime( _sSQLString.subView( nSeparation ) );
+ }
+
+ return css::util::DateTime(aTime.NanoSeconds, aTime.Seconds, aTime.Minutes, aTime.Hours,
+ aDate.Day, aDate.Month, aDate.Year, false);
+ }
+
+
+ css::util::Time DBTypeConversion::toTime(std::u16string_view _sSQLString)
+ {
+ css::util::Time aTime;
+ ::utl::ISO8601parseTime(_sSQLString, aTime);
+ return aTime;
+ }
+
+
+} // namespace dbtools
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/commontools/dbexception.cxx b/connectivity/source/commontools/dbexception.cxx
new file mode 100644
index 0000000000..bc5a9be808
--- /dev/null
+++ b/connectivity/source/commontools/dbexception.cxx
@@ -0,0 +1,485 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <connectivity/dbexception.hxx>
+#include <comphelper/types.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+#include <o3tl/any.hxx>
+#include <osl/diagnose.h>
+#include <com/sun/star/sdb/SQLContext.hpp>
+#include <com/sun/star/sdbc/SQLWarning.hpp>
+#include <com/sun/star/sdb/SQLErrorEvent.hpp>
+#include <strings.hrc>
+#include <resource/sharedresources.hxx>
+#include <comphelper/diagnose_ex.hxx>
+
+namespace dbtools
+{
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::sdb;
+ using namespace ::com::sun::star::sdbc;
+ using namespace ::comphelper;
+ using namespace ::connectivity;
+
+SQLExceptionInfo::SQLExceptionInfo()
+ :m_eType(TYPE::Undefined)
+{
+}
+
+
+SQLExceptionInfo::SQLExceptionInfo(const css::sdbc::SQLException& _rError)
+{
+ m_aContent <<= _rError;
+ implDetermineType();
+}
+
+
+SQLExceptionInfo::SQLExceptionInfo(const css::sdbc::SQLWarning& _rError)
+{
+ m_aContent <<= _rError;
+ implDetermineType();
+}
+
+
+SQLExceptionInfo::SQLExceptionInfo(const css::sdb::SQLContext& _rError)
+{
+ m_aContent <<= _rError;
+ implDetermineType();
+}
+
+
+SQLExceptionInfo::SQLExceptionInfo( const OUString& _rSimpleErrorMessage )
+{
+ SQLException aError(_rSimpleErrorMessage, {}, {}, 0, {});
+ m_aContent <<= aError;
+ implDetermineType();
+}
+
+SQLExceptionInfo& SQLExceptionInfo::operator=(const css::sdbc::SQLException& _rError)
+{
+ m_aContent <<= _rError;
+ implDetermineType();
+ return *this;
+}
+
+
+SQLExceptionInfo& SQLExceptionInfo::operator=(const css::sdbc::SQLWarning& _rError)
+{
+ m_aContent <<= _rError;
+ implDetermineType();
+ return *this;
+}
+
+
+SQLExceptionInfo& SQLExceptionInfo::operator=(const css::sdb::SQLContext& _rError)
+{
+ m_aContent <<= _rError;
+ implDetermineType();
+ return *this;
+}
+
+
+SQLExceptionInfo& SQLExceptionInfo::operator=(const css::sdb::SQLErrorEvent& _rErrorEvent)
+{
+ m_aContent = _rErrorEvent.Reason;
+ implDetermineType();
+ return *this;
+}
+
+
+SQLExceptionInfo& SQLExceptionInfo::operator=(const css::uno::Any& _rCaughtSQLException)
+{
+ m_aContent = _rCaughtSQLException;
+ implDetermineType();
+ return *this;
+}
+
+
+SQLExceptionInfo::SQLExceptionInfo(const css::uno::Any& _rError)
+{
+ const css::uno::Type& aSQLExceptionType = cppu::UnoType<css::sdbc::SQLException>::get();
+ bool bValid = isAssignableFrom(aSQLExceptionType, _rError.getValueType());
+ if (bValid)
+ m_aContent = _rError;
+ // no assertion here : if used with the NextException member of an SQLException bValid==sal_False is allowed.
+
+ implDetermineType();
+}
+
+
+void SQLExceptionInfo::implDetermineType()
+{
+ const Type& aSQLExceptionType = ::cppu::UnoType<SQLException>::get();
+ const Type& aSQLWarningType = ::cppu::UnoType<SQLWarning>::get();
+ const Type& aSQLContextType = ::cppu::UnoType<SQLContext>::get();
+
+ if ( isAssignableFrom( aSQLContextType, m_aContent.getValueType() ) )
+ m_eType = TYPE::SQLContext;
+ else if ( isAssignableFrom( aSQLWarningType, m_aContent.getValueType() ) )
+ m_eType = TYPE::SQLWarning;
+ else if ( isAssignableFrom( aSQLExceptionType, m_aContent.getValueType() ) )
+ m_eType = TYPE::SQLException;
+ else
+ {
+ m_eType = TYPE::Undefined;
+ m_aContent.clear();
+ }
+}
+
+
+bool SQLExceptionInfo::isKindOf(TYPE _eType) const
+{
+ switch (_eType)
+ {
+ case TYPE::SQLContext:
+ return (m_eType == TYPE::SQLContext);
+ case TYPE::SQLWarning:
+ return (m_eType == TYPE::SQLContext) || (m_eType == TYPE::SQLWarning);
+ case TYPE::SQLException:
+ return (m_eType == TYPE::SQLContext) || (m_eType == TYPE::SQLWarning) || (m_eType == TYPE::SQLException);
+ case TYPE::Undefined:
+ return (m_eType == TYPE::Undefined);
+ }
+ return false;
+}
+
+
+SQLExceptionInfo::operator const css::sdbc::SQLException*() const
+{
+ OSL_ENSURE(isKindOf(TYPE::SQLException), "SQLExceptionInfo::operator SQLException* : invalid call !");
+ return o3tl::doAccess<css::sdbc::SQLException>(m_aContent);
+}
+
+
+SQLExceptionInfo::operator const css::sdb::SQLContext*() const
+{
+ OSL_ENSURE(isKindOf(TYPE::SQLContext), "SQLExceptionInfo::operator SQLException* : invalid call !");
+ return o3tl::doAccess<css::sdb::SQLContext>(m_aContent);
+}
+
+
+void SQLExceptionInfo::prepend( const OUString& _rErrorMessage )
+{
+ SQLException aException(_rErrorMessage, {}, "S1000", 0, m_aContent);
+ m_aContent <<= aException;
+
+ m_eType = TYPE::SQLException;
+}
+
+// create the to-be-appended exception
+Any SQLExceptionInfo::createException(TYPE eType, const OUString& rErrorMessage, const OUString& rSQLState, const sal_Int32 nErrorCode)
+{
+ Any aAppend;
+ switch (eType)
+ {
+ case TYPE::SQLException:
+ aAppend <<= SQLException(rErrorMessage, {}, rSQLState, nErrorCode, {});
+ break;
+ case TYPE::SQLWarning:
+ aAppend <<= SQLWarning(rErrorMessage, {}, rSQLState, nErrorCode, {});
+ break;
+ case TYPE::SQLContext:
+ aAppend <<= SQLContext(rErrorMessage, {}, rSQLState, nErrorCode, {}, {});
+ break;
+ default:
+ TOOLS_WARN_EXCEPTION("connectivity.commontools", "SQLExceptionInfo::createException: invalid exception type: this will crash!");
+ break;
+ }
+
+ return aAppend;
+}
+
+// find the end of the exception chain
+SQLException* SQLExceptionInfo::getLastException(SQLException* pLastException)
+{
+ SQLException* pException = pLastException;
+ while (pException)
+ {
+ pException = const_cast<SQLException*>(o3tl::tryAccess<SQLException>(pException->NextException));
+ if (!pException)
+ break;
+ pLastException = pException;
+ }
+ return pLastException;
+}
+
+void SQLExceptionInfo::append( TYPE _eType, const OUString& _rErrorMessage, const OUString& _rSQLState, const sal_Int32 _nErrorCode )
+{
+ // create the to-be-appended exception
+ Any aAppend = createException(_eType, _rErrorMessage, _rSQLState, _nErrorCode);
+
+ // find the end of the current chain
+ SQLException* pLastException = getLastException(const_cast<SQLException*>(o3tl::tryAccess<SQLException>(m_aContent)));
+
+ // append
+ if (pLastException)
+ pLastException->NextException = aAppend;
+ else
+ {
+ m_aContent = aAppend;
+ m_eType = _eType;
+ }
+}
+
+void SQLExceptionInfo::doThrow()
+{
+ if ( m_aContent.getValueTypeClass() == TypeClass_EXCEPTION )
+ ::cppu::throwException( m_aContent );
+ throw RuntimeException();
+}
+
+SQLExceptionIteratorHelper::SQLExceptionIteratorHelper( const SQLExceptionInfo& _rChainStart )
+ :m_pCurrent( nullptr )
+ ,m_eCurrentType( SQLExceptionInfo::TYPE::Undefined )
+{
+ if ( _rChainStart.isValid() )
+ {
+ m_pCurrent = _rChainStart;
+ m_eCurrentType = _rChainStart.getType();
+ }
+}
+
+
+SQLExceptionIteratorHelper::SQLExceptionIteratorHelper( const css::sdbc::SQLException& _rChainStart )
+ :m_pCurrent( &_rChainStart )
+ ,m_eCurrentType( SQLExceptionInfo::TYPE::SQLException )
+{
+}
+
+
+void SQLExceptionIteratorHelper::current( SQLExceptionInfo& _out_rInfo ) const
+{
+ switch ( m_eCurrentType )
+ {
+ case SQLExceptionInfo::TYPE::SQLException:
+ _out_rInfo = *m_pCurrent;
+ break;
+
+ case SQLExceptionInfo::TYPE::SQLWarning:
+ _out_rInfo = *static_cast< const SQLWarning* >( m_pCurrent );
+ break;
+
+ case SQLExceptionInfo::TYPE::SQLContext:
+ _out_rInfo = *static_cast< const SQLContext* >( m_pCurrent );
+ break;
+
+ default:
+ _out_rInfo = Any();
+ break;
+ }
+}
+
+
+const css::sdbc::SQLException* SQLExceptionIteratorHelper::next()
+{
+ OSL_ENSURE( hasMoreElements(), "SQLExceptionIteratorHelper::next : invalid call (please use hasMoreElements)!" );
+
+ const css::sdbc::SQLException* pReturn = m_pCurrent;
+ if ( !m_pCurrent )
+ return pReturn;
+
+ // check for the next element within the chain
+ const Type aTypeException( ::cppu::UnoType< SQLException >::get() );
+
+ Type aNextElementType = m_pCurrent->NextException.getValueType();
+ if ( !isAssignableFrom( aTypeException, aNextElementType ) )
+ {
+ // no SQLException at all in the next chain element
+ m_pCurrent = nullptr;
+ m_eCurrentType = SQLExceptionInfo::TYPE::Undefined;
+ return pReturn;
+ }
+
+ m_pCurrent = o3tl::doAccess< SQLException >( m_pCurrent->NextException );
+
+ // no finally determine the proper type of the exception
+ const Type aTypeContext( ::cppu::UnoType< SQLContext >::get() );
+ if ( isAssignableFrom( aTypeContext, aNextElementType ) )
+ {
+ m_eCurrentType = SQLExceptionInfo::TYPE::SQLContext;
+ return pReturn;
+ }
+
+ const Type aTypeWarning( ::cppu::UnoType< SQLWarning >::get() );
+ if ( isAssignableFrom( aTypeWarning, aNextElementType ) )
+ {
+ m_eCurrentType = SQLExceptionInfo::TYPE::SQLWarning;
+ return pReturn;
+ }
+
+ // a simple SQLException
+ m_eCurrentType = SQLExceptionInfo::TYPE::SQLException;
+ return pReturn;
+}
+
+
+void SQLExceptionIteratorHelper::next( SQLExceptionInfo& _out_rInfo )
+{
+ current( _out_rInfo );
+ next();
+}
+
+
+void throwFunctionSequenceException(const Reference< XInterface >& Context, const Any& Next)
+{
+ ::connectivity::SharedResources aResources;
+ throw SQLException(
+ aResources.getResourceString(STR_ERRORMSG_SEQUENCE),
+ Context,
+ getStandardSQLState( StandardSQLState::FUNCTION_SEQUENCE_ERROR ),
+ 0,
+ Next
+ );
+}
+
+void throwInvalidIndexException(const css::uno::Reference< css::uno::XInterface >& Context,
+ const css::uno::Any& Next)
+{
+ ::connectivity::SharedResources aResources;
+ throw SQLException(
+ aResources.getResourceString(STR_INVALID_INDEX),
+ Context,
+ getStandardSQLState( StandardSQLState::INVALID_DESCRIPTOR_INDEX ),
+ 0,
+ Next
+ );
+}
+
+void throwFunctionNotSupportedSQLException(const OUString& _rFunctionName,
+ const css::uno::Reference<css::uno::XInterface>& _rxContext)
+{
+ ::connectivity::SharedResources aResources;
+ const OUString sError( aResources.getResourceStringWithSubstitution(
+ STR_UNSUPPORTED_FUNCTION,
+ "$functionname$", _rFunctionName
+ ) );
+ throw SQLException(
+ sError,
+ _rxContext,
+ getStandardSQLState( StandardSQLState::FUNCTION_NOT_SUPPORTED ),
+ 0,
+ css::uno::Any()
+ );
+}
+
+void throwFunctionNotSupportedRuntimeException(const OUString& _rFunctionName,
+ const css::uno::Reference<css::uno::XInterface>& _rxContext)
+{
+ ::connectivity::SharedResources aResources;
+ const OUString sError( aResources.getResourceStringWithSubstitution(
+ STR_UNSUPPORTED_FUNCTION,
+ "$functionname$", _rFunctionName
+ ) );
+ throw RuntimeException(
+ sError,
+ _rxContext
+ );
+}
+
+void throwGenericSQLException(const OUString& _rMsg, const css::uno::Reference< css::uno::XInterface >& _rxSource)
+{
+ throwGenericSQLException(_rMsg, _rxSource, Any());
+}
+
+
+void throwGenericSQLException(const OUString& _rMsg, const Reference< XInterface >& _rxSource, const Any& _rNextException)
+{
+ throw SQLException( _rMsg, _rxSource, getStandardSQLState( StandardSQLState::GENERAL_ERROR ), 0, _rNextException);
+}
+
+void throwFeatureNotImplementedSQLException( const OUString& _rFeatureName, const Reference< XInterface >& _rxContext, const Any& _rNextException )
+{
+ ::connectivity::SharedResources aResources;
+ const OUString sError( aResources.getResourceStringWithSubstitution(
+ STR_UNSUPPORTED_FEATURE,
+ "$featurename$", _rFeatureName
+ ) );
+
+ throw SQLException(
+ sError,
+ _rxContext,
+ getStandardSQLState( StandardSQLState::FEATURE_NOT_IMPLEMENTED ),
+ 0,
+ _rNextException
+ );
+}
+
+void throwFeatureNotImplementedRuntimeException(const OUString& _rFeatureName, const Reference< XInterface >& _rxContext)
+{
+ ::connectivity::SharedResources aResources;
+ const OUString sError( aResources.getResourceStringWithSubstitution(
+ STR_UNSUPPORTED_FEATURE,
+ "$featurename$", _rFeatureName
+ ) );
+
+ throw RuntimeException(sError, _rxContext);
+}
+
+void throwInvalidColumnException( const OUString& _rColumnName, const Reference< XInterface >& _rxContext)
+{
+ ::connectivity::SharedResources aResources;
+ OUString sErrorMessage( aResources.getResourceStringWithSubstitution(
+ STR_INVALID_COLUMNNAME,
+ "$columnname$",_rColumnName) );
+ throwSQLException( sErrorMessage, StandardSQLState::COLUMN_NOT_FOUND, _rxContext );
+}
+
+void throwSQLException( const OUString& _rMessage, const OUString& _rSQLState,
+ const Reference< XInterface >& _rxContext, const sal_Int32 _nErrorCode )
+{
+ throw SQLException(
+ _rMessage,
+ _rxContext,
+ _rSQLState,
+ _nErrorCode,
+ Any()
+ );
+}
+
+
+void throwSQLException( const OUString& _rMessage, StandardSQLState _eSQLState,
+ const Reference< XInterface >& _rxContext, const sal_Int32 _nErrorCode )
+{
+ throwSQLException( _rMessage, getStandardSQLState( _eSQLState ), _rxContext, _nErrorCode );
+}
+
+
+OUString getStandardSQLState( StandardSQLState _eState )
+{
+ switch ( _eState )
+ {
+ case StandardSQLState::INVALID_DESCRIPTOR_INDEX: return "07009";
+ case StandardSQLState::INVALID_CURSOR_STATE: return "24000";
+ case StandardSQLState::COLUMN_NOT_FOUND: return "42S22";
+ case StandardSQLState::GENERAL_ERROR: return "HY000";
+ case StandardSQLState::INVALID_SQL_DATA_TYPE: return "HY004";
+ case StandardSQLState::FUNCTION_SEQUENCE_ERROR: return "HY010";
+ case StandardSQLState::INVALID_CURSOR_POSITION: return "HY109";
+ case StandardSQLState::FEATURE_NOT_IMPLEMENTED: return "HYC00";
+ case StandardSQLState::FUNCTION_NOT_SUPPORTED: return "IM001";
+ case StandardSQLState::CONNECTION_DOES_NOT_EXIST: return "08003";
+ default: return "HY001"; // General Error
+ }
+}
+
+
+} // namespace dbtools
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/commontools/dbmetadata.cxx b/connectivity/source/commontools/dbmetadata.cxx
new file mode 100644
index 0000000000..8983ee25ba
--- /dev/null
+++ b/connectivity/source/commontools/dbmetadata.cxx
@@ -0,0 +1,443 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <connectivity/dbmetadata.hxx>
+#include <connectivity/dbexception.hxx>
+#include <connectivity/DriversConfig.hxx>
+#include <strings.hrc>
+#include <resource/sharedresources.hxx>
+
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+#include <com/sun/star/container/XChild.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/sdb/BooleanComparisonMode.hpp>
+#include <com/sun/star/sdbc/XDatabaseMetaData2.hpp>
+#include <com/sun/star/sdbcx/XUsersSupplier.hpp>
+#include <com/sun/star/sdbcx/XDataDefinitionSupplier.hpp>
+#include <com/sun/star/sdbc/DriverManager.hpp>
+
+#include <comphelper/diagnose_ex.hxx>
+#include <comphelper/namedvaluecollection.hxx>
+#include <comphelper/processfactory.hxx>
+#include <sal/log.hxx>
+
+#include <optional>
+
+
+namespace dbtools
+{
+
+
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::sdbc::XConnection;
+ using ::com::sun::star::sdbc::XDatabaseMetaData;
+ using ::com::sun::star::sdbc::XDatabaseMetaData2;
+ using ::com::sun::star::lang::IllegalArgumentException;
+ using ::com::sun::star::uno::Exception;
+ using ::com::sun::star::uno::Any;
+ using ::com::sun::star::uno::XComponentContext;
+ using ::com::sun::star::container::XChild;
+ using ::com::sun::star::uno::UNO_QUERY_THROW;
+ using ::com::sun::star::beans::XPropertySet;
+ using ::com::sun::star::uno::UNO_QUERY;
+ using ::com::sun::star::sdbcx::XUsersSupplier;
+ using ::com::sun::star::sdbcx::XDataDefinitionSupplier;
+ using ::com::sun::star::sdbc::DriverManager;
+ using ::com::sun::star::sdbc::XDriverManager2;
+ using ::com::sun::star::uno::UNO_SET_THROW;
+
+ namespace BooleanComparisonMode = ::com::sun::star::sdb::BooleanComparisonMode;
+
+ struct DatabaseMetaData_Impl
+ {
+ Reference< XConnection > xConnection;
+ Reference< XDatabaseMetaData > xConnectionMetaData;
+ ::connectivity::DriversConfig aDriverConfig;
+
+ ::std::optional< OUString > sCachedIdentifierQuoteString;
+ ::std::optional< OUString > sCachedCatalogSeparator;
+
+ DatabaseMetaData_Impl()
+ : aDriverConfig( ::comphelper::getProcessComponentContext() )
+ {
+ }
+ };
+
+
+ namespace
+ {
+
+ void lcl_construct( DatabaseMetaData_Impl& _metaDataImpl, const Reference< XConnection >& _connection )
+ {
+ _metaDataImpl.xConnection = _connection;
+ if ( !_metaDataImpl.xConnection.is() )
+ return;
+
+ _metaDataImpl.xConnectionMetaData = _connection->getMetaData();
+ if ( !_metaDataImpl.xConnectionMetaData.is() )
+ throw IllegalArgumentException();
+ }
+
+
+ void lcl_checkConnected( const DatabaseMetaData_Impl& _metaDataImpl )
+ {
+ if ( !_metaDataImpl.xConnection.is() || !_metaDataImpl.xConnectionMetaData.is() )
+ {
+ ::connectivity::SharedResources aResources;
+ const OUString sError( aResources.getResourceString(STR_NO_CONNECTION_GIVEN));
+ throwSQLException( sError, StandardSQLState::CONNECTION_DOES_NOT_EXIST, nullptr );
+ }
+ }
+
+
+ bool lcl_getDriverSetting( const OUString& _asciiName, const DatabaseMetaData_Impl& _metaData, Any& _out_setting )
+ {
+ lcl_checkConnected( _metaData );
+ const ::comphelper::NamedValueCollection& rDriverMetaData = _metaData.aDriverConfig.getMetaData( _metaData.xConnectionMetaData->getURL() );
+ if ( !rDriverMetaData.has( _asciiName ) )
+ return false;
+ _out_setting = rDriverMetaData.get( _asciiName );
+ return true;
+ }
+
+
+ bool lcl_getConnectionSetting(const OUString& _asciiName, const DatabaseMetaData_Impl& _metaData, Any& _out_setting )
+ {
+ try
+ {
+ Reference< XChild > xConnectionAsChild( _metaData.xConnection, UNO_QUERY );
+ if ( xConnectionAsChild.is() )
+ {
+ Reference< XPropertySet > xDataSource( xConnectionAsChild->getParent(), UNO_QUERY_THROW );
+ Reference< XPropertySet > xDataSourceSettings(
+ xDataSource->getPropertyValue("Settings"),
+ UNO_QUERY_THROW );
+
+ _out_setting = xDataSourceSettings->getPropertyValue( _asciiName );
+ }
+ else
+ {
+ Reference< XDatabaseMetaData2 > xExtendedMetaData( _metaData.xConnectionMetaData, UNO_QUERY_THROW );
+ _out_setting = ::comphelper::NamedValueCollection::get( xExtendedMetaData->getConnectionInfo(), _asciiName );
+ return _out_setting.hasValue();
+ }
+ return true;
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("connectivity.commontools");
+ }
+ return false;
+ }
+
+
+ const OUString& lcl_getConnectionStringSetting(
+ const DatabaseMetaData_Impl& _metaData, ::std::optional< OUString >& _cachedSetting,
+ OUString (SAL_CALL XDatabaseMetaData::*_getter)() )
+ {
+ if ( !_cachedSetting )
+ {
+ lcl_checkConnected( _metaData );
+ try
+ {
+ _cachedSetting = (_metaData.xConnectionMetaData.get()->*_getter)();
+ }
+ catch( const Exception& ) { DBG_UNHANDLED_EXCEPTION("connectivity.commontools"); }
+ }
+ return *_cachedSetting;
+ }
+ }
+
+ DatabaseMetaData::DatabaseMetaData()
+ :m_pImpl( new DatabaseMetaData_Impl )
+ {
+ }
+
+ DatabaseMetaData::DatabaseMetaData( const Reference< XConnection >& _connection )
+ :m_pImpl( new DatabaseMetaData_Impl )
+ {
+ lcl_construct( *m_pImpl, _connection );
+ }
+
+
+ DatabaseMetaData::DatabaseMetaData( const DatabaseMetaData& _copyFrom )
+ :m_pImpl( new DatabaseMetaData_Impl( *_copyFrom.m_pImpl ) )
+ {
+ }
+
+ DatabaseMetaData::DatabaseMetaData(DatabaseMetaData&& _copyFrom) noexcept
+ :m_pImpl(std::move(_copyFrom.m_pImpl))
+ {
+ }
+
+ DatabaseMetaData& DatabaseMetaData::operator=( const DatabaseMetaData& _copyFrom )
+ {
+ if ( this == &_copyFrom )
+ return *this;
+
+ m_pImpl.reset( new DatabaseMetaData_Impl( *_copyFrom.m_pImpl ) );
+ return *this;
+ }
+
+ DatabaseMetaData& DatabaseMetaData::operator=(DatabaseMetaData&& _copyFrom) noexcept
+ {
+ m_pImpl = std::move(_copyFrom.m_pImpl);
+ return *this;
+ }
+
+ DatabaseMetaData::~DatabaseMetaData()
+ {
+ }
+
+ bool DatabaseMetaData::isConnected() const
+ {
+ return m_pImpl->xConnection.is();
+ }
+
+
+ bool DatabaseMetaData::supportsSubqueriesInFrom() const
+ {
+ lcl_checkConnected( *m_pImpl );
+
+ bool bSupportsSubQueries = false;
+ try
+ {
+ sal_Int32 maxTablesInselect = m_pImpl->xConnectionMetaData->getMaxTablesInSelect();
+ bSupportsSubQueries = ( maxTablesInselect > 1 ) || ( maxTablesInselect == 0 );
+ // TODO: is there a better way to determine this? The above is not really true. More precise,
+ // it's a *very* generous heuristics ...
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("connectivity.commontools");
+ }
+ return bSupportsSubQueries;
+ }
+
+
+ bool DatabaseMetaData::supportsPrimaryKeys() const
+ {
+ lcl_checkConnected( *m_pImpl );
+
+ bool bDoesSupportPrimaryKeys = false;
+ try
+ {
+ Any setting;
+ if ( !( lcl_getConnectionSetting( "PrimaryKeySupport", *m_pImpl, setting ) )
+ || !( setting >>= bDoesSupportPrimaryKeys )
+ )
+ bDoesSupportPrimaryKeys = m_pImpl->xConnectionMetaData->supportsCoreSQLGrammar()
+ || m_pImpl->xConnectionMetaData->supportsANSI92EntryLevelSQL();
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("connectivity.commontools");
+ }
+ return bDoesSupportPrimaryKeys;
+ }
+
+
+ const OUString& DatabaseMetaData::getIdentifierQuoteString() const
+ {
+ return lcl_getConnectionStringSetting( *m_pImpl, m_pImpl->sCachedIdentifierQuoteString, &XDatabaseMetaData::getIdentifierQuoteString );
+ }
+
+
+ const OUString& DatabaseMetaData::getCatalogSeparator() const
+ {
+ return lcl_getConnectionStringSetting( *m_pImpl, m_pImpl->sCachedCatalogSeparator, &XDatabaseMetaData::getCatalogSeparator );
+ }
+
+
+ bool DatabaseMetaData::restrictIdentifiersToSQL92() const
+ {
+ lcl_checkConnected( *m_pImpl );
+
+ bool restrict( false );
+ Any setting;
+ if ( lcl_getConnectionSetting( "EnableSQL92Check", *m_pImpl, setting ) )
+ if( ! (setting >>= restrict) )
+ SAL_WARN("connectivity.commontools", "restrictIdentifiersToSQL92: unable to assign EnableSQL92Check");
+ return restrict;
+ }
+
+
+ bool DatabaseMetaData::generateASBeforeCorrelationName() const
+ {
+ bool doGenerate( false );
+ Any setting;
+ if ( lcl_getConnectionSetting( "GenerateASBeforeCorrelationName", *m_pImpl, setting ) )
+ if( ! (setting >>= doGenerate) )
+ SAL_WARN("connectivity.commontools", "generateASBeforeCorrelationName: unable to assign GenerateASBeforeCorrelationName");
+ return doGenerate;
+ }
+
+ bool DatabaseMetaData::shouldEscapeDateTime() const
+ {
+ bool doGenerate( true );
+ Any setting;
+ if ( lcl_getConnectionSetting( "EscapeDateTime", *m_pImpl, setting ) )
+ if( ! (setting >>= doGenerate) )
+ SAL_WARN("connectivity.commontools", "shouldEscapeDateTime: unable to assign EscapeDateTime");
+ return doGenerate;
+ }
+
+ bool DatabaseMetaData::shouldSubstituteParameterNames() const
+ {
+ bool doSubstitute( true );
+ Any setting;
+ if ( lcl_getConnectionSetting( "ParameterNameSubstitution", *m_pImpl, setting ) )
+ if( ! (setting >>= doSubstitute) )
+ SAL_WARN("connectivity.commontools", "shouldSubstituteParameterNames: unable to assign ParameterNameSubstitution");
+ return doSubstitute;
+ }
+
+ bool DatabaseMetaData::isAutoIncrementPrimaryKey() const
+ {
+ bool is( true );
+ Any setting;
+ if ( lcl_getDriverSetting( "AutoIncrementIsPrimaryKey", *m_pImpl, setting ) )
+ if( ! (setting >>= is) )
+ SAL_WARN("connectivity.commontools", "isAutoIncrementPrimaryKey: unable to assign AutoIncrementIsPrimaryKey");
+ return is;
+ }
+
+ sal_Int32 DatabaseMetaData::getBooleanComparisonMode() const
+ {
+ sal_Int32 mode( BooleanComparisonMode::EQUAL_INTEGER );
+ Any setting;
+ if ( lcl_getConnectionSetting( "BooleanComparisonMode", *m_pImpl, setting ) )
+ if( ! (setting >>= mode) )
+ SAL_WARN("connectivity.commontools", "getBooleanComparisonMode: unable to assign BooleanComparisonMode");
+ return mode;
+ }
+
+ bool DatabaseMetaData::supportsRelations() const
+ {
+ lcl_checkConnected( *m_pImpl );
+ bool bSupport = false;
+ try
+ {
+ bSupport = m_pImpl->xConnectionMetaData->supportsIntegrityEnhancementFacility();
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("connectivity.commontools");
+ }
+ try
+ {
+ if ( !bSupport )
+ {
+ const OUString url = m_pImpl->xConnectionMetaData->getURL();
+ bSupport = url.startsWith("sdbc:mysql");
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("connectivity.commontools");
+ }
+ return bSupport;
+ }
+
+
+ bool DatabaseMetaData::supportsColumnAliasInOrderBy() const
+ {
+ bool doGenerate( true );
+ Any setting;
+ if ( lcl_getConnectionSetting( "ColumnAliasInOrderBy", *m_pImpl, setting ) )
+ if( ! (setting >>= doGenerate) )
+ SAL_WARN("connectivity.commontools", "supportsColumnAliasInOrderBy: unable to assign ColumnAliasInOrderBy");
+ return doGenerate;
+ }
+
+
+ bool DatabaseMetaData::supportsUserAdministration( const Reference<XComponentContext>& _rContext ) const
+ {
+ lcl_checkConnected( *m_pImpl );
+
+ bool isSupported( false );
+ try
+ {
+ // find the XUsersSupplier interface
+ // - either directly at the connection
+ Reference< XUsersSupplier > xUsersSupp( m_pImpl->xConnection, UNO_QUERY );
+ if ( !xUsersSupp.is() )
+ {
+ // - or at the driver manager
+ Reference< XDriverManager2 > xDriverManager = DriverManager::create( _rContext );
+ Reference< XDataDefinitionSupplier > xDriver( xDriverManager->getDriverByURL( m_pImpl->xConnectionMetaData->getURL() ), UNO_QUERY );
+ if ( xDriver.is() )
+ xUsersSupp.set( xDriver->getDataDefinitionByConnection( m_pImpl->xConnection ), UNO_QUERY );
+ }
+
+ isSupported = ( xUsersSupp.is() && xUsersSupp->getUsers().is() );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("connectivity.commontools");
+ }
+ return isSupported;
+ }
+
+
+ bool DatabaseMetaData::displayEmptyTableFolders() const
+ {
+ bool doDisplay( true );
+#ifdef IMPLEMENTED_LATER
+ Any setting;
+ if ( lcl_getConnectionSetting( "DisplayEmptyTableFolders", *m_pImpl, setting ) )
+ if( ! (setting >>= doDisplay) )
+ SAL_WARN("connectivity.commontools", "displayEmptyTableFolders: unable to assign DisplayEmptyTableFolders");
+#else
+ try
+ {
+ Reference< XDatabaseMetaData > xMeta( m_pImpl->xConnectionMetaData, UNO_SET_THROW );
+ OUString sConnectionURL( xMeta->getURL() );
+ doDisplay = sConnectionURL.startsWith( "sdbc:mysql:mysqlc" );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("connectivity.commontools");
+ }
+#endif
+ return doDisplay;
+ }
+
+ bool DatabaseMetaData::supportsThreads() const
+ {
+ bool bSupported( true );
+ try
+ {
+ Reference< XDatabaseMetaData > xMeta( m_pImpl->xConnectionMetaData, UNO_SET_THROW );
+ OUString sConnectionURL( xMeta->getURL() );
+ bSupported = !sConnectionURL.startsWith( "sdbc:mysql:mysqlc" );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("connectivity.commontools");
+ }
+ return bSupported;
+ }
+
+
+} // namespace dbtools
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/commontools/dbtools.cxx b/connectivity/source/commontools/dbtools.cxx
new file mode 100644
index 0000000000..885e28c751
--- /dev/null
+++ b/connectivity/source/commontools/dbtools.cxx
@@ -0,0 +1,2074 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <connectivity/CommonTools.hxx>
+#include <TConnection.hxx>
+#include <ParameterCont.hxx>
+
+#include <com/sun/star/awt/XWindow.hpp>
+#include <com/sun/star/beans/NamedValue.hpp>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/container/XChild.hpp>
+#include <com/sun/star/form/FormComponentType.hpp>
+#include <com/sun/star/io/XInputStream.hpp>
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/sdb/DatabaseContext.hpp>
+#include <com/sun/star/sdb/BooleanComparisonMode.hpp>
+#include <com/sun/star/sdb/CommandType.hpp>
+#include <com/sun/star/sdb/ErrorMessageDialog.hpp>
+#include <com/sun/star/sdb/ParametersRequest.hpp>
+#include <com/sun/star/sdb/RowSetVetoException.hpp>
+#include <com/sun/star/sdb/SQLContext.hpp>
+#include <com/sun/star/sdb/XCompletedConnection.hpp>
+#include <com/sun/star/sdb/XInteractionSupplyParameters.hpp>
+#include <com/sun/star/sdb/XOfficeDatabaseDocument.hpp>
+#include <com/sun/star/sdb/XParametersSupplier.hpp>
+#include <com/sun/star/sdb/XQueriesSupplier.hpp>
+#include <com/sun/star/sdb/XSingleSelectQueryComposer.hpp>
+#include <com/sun/star/sdbc/ConnectionPool.hpp>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <com/sun/star/sdbc/XDataSource.hpp>
+#include <com/sun/star/sdbc/XParameters.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XRowSet.hpp>
+#include <com/sun/star/sdbc/XRowUpdate.hpp>
+#include <com/sun/star/sdbcx/KeyType.hpp>
+#include <com/sun/star/sdbcx/Privilege.hpp>
+#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
+#include <com/sun/star/sdbcx/XKeysSupplier.hpp>
+#include <com/sun/star/sdbcx/XTablesSupplier.hpp>
+#include <com/sun/star/task/InteractionHandler.hpp>
+#include <com/sun/star/ui/dialogs/XExecutableDialog.hpp>
+#include <com/sun/star/util/NumberFormat.hpp>
+#include <com/sun/star/util/NumberFormatsSupplier.hpp>
+#include <com/sun/star/util/XNumberFormatTypes.hpp>
+
+#include <comphelper/extract.hxx>
+#include <comphelper/interaction.hxx>
+#include <comphelper/property.hxx>
+#include <comphelper/propertysequence.hxx>
+#include <comphelper/types.hxx>
+#include <connectivity/conncleanup.hxx>
+#include <connectivity/dbconversion.hxx>
+#include <connectivity/dbexception.hxx>
+#include <connectivity/dbtools.hxx>
+#include <connectivity/statementcomposer.hxx>
+#include <o3tl/any.hxx>
+#include <o3tl/safeint.hxx>
+#include <osl/diagnose.h>
+#include <rtl/ustrbuf.hxx>
+#include <sal/log.hxx>
+#include <comphelper/diagnose_ex.hxx>
+#include <tools/stream.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <strings.hrc>
+#include <resource/sharedresources.hxx>
+
+#include <algorithm>
+#include <iterator>
+#include <set>
+
+using namespace ::comphelper;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::io;
+using namespace ::com::sun::star::awt;
+using namespace ::com::sun::star::ui::dialogs;
+using namespace ::com::sun::star::util;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::task;
+using namespace ::com::sun::star::form;
+using namespace connectivity;
+
+namespace dbtools
+{
+
+namespace
+{
+ typedef sal_Bool (SAL_CALL XDatabaseMetaData::*FMetaDataSupport)();
+}
+
+sal_Int32 getDefaultNumberFormat(const Reference< XPropertySet >& _xColumn,
+ const Reference< XNumberFormatTypes >& _xTypes,
+ const Locale& _rLocale)
+{
+ OSL_ENSURE(_xTypes.is() && _xColumn.is(), "dbtools::getDefaultNumberFormat: invalid arg !");
+ if (!_xTypes.is() || !_xColumn.is())
+ return NumberFormat::UNDEFINED;
+
+ sal_Int32 nDataType = 0;
+ sal_Int32 nScale = 0;
+ try
+ {
+ // determine the datatype of the column
+ _xColumn->getPropertyValue("Type") >>= nDataType;
+
+ if (DataType::NUMERIC == nDataType || DataType::DECIMAL == nDataType)
+ _xColumn->getPropertyValue("Scale") >>= nScale;
+ }
+ catch (Exception&)
+ {
+ return NumberFormat::UNDEFINED;
+ }
+ return getDefaultNumberFormat(nDataType,
+ nScale,
+ ::cppu::any2bool(_xColumn->getPropertyValue("IsCurrency")),
+ _xTypes,
+ _rLocale);
+}
+
+sal_Int32 getDefaultNumberFormat(sal_Int32 _nDataType,
+ sal_Int32 _nScale,
+ bool _bIsCurrency,
+ const Reference< XNumberFormatTypes >& _xTypes,
+ const Locale& _rLocale)
+{
+ OSL_ENSURE(_xTypes.is() , "dbtools::getDefaultNumberFormat: invalid arg !");
+ if (!_xTypes.is())
+ return NumberFormat::UNDEFINED;
+
+ sal_Int32 nFormat = 0;
+ sal_Int32 nNumberType = _bIsCurrency ? NumberFormat::CURRENCY : NumberFormat::NUMBER;
+ switch (_nDataType)
+ {
+ case DataType::BIT:
+ case DataType::BOOLEAN:
+ nFormat = _xTypes->getStandardFormat(NumberFormat::LOGICAL, _rLocale);
+ break;
+ case DataType::TINYINT:
+ case DataType::SMALLINT:
+ case DataType::INTEGER:
+ case DataType::BIGINT:
+ case DataType::FLOAT:
+ case DataType::REAL:
+ case DataType::DOUBLE:
+ case DataType::NUMERIC:
+ case DataType::DECIMAL:
+ {
+ try
+ {
+ nFormat = _xTypes->getStandardFormat(static_cast<sal_Int16>(nNumberType), _rLocale);
+ if(_nScale > 0)
+ {
+ // generate a new format if necessary
+ Reference< XNumberFormats > xFormats(_xTypes, UNO_QUERY);
+ OUString sNewFormat = xFormats->generateFormat( 0, _rLocale, false, false, static_cast<sal_Int16>(_nScale), 1);
+
+ // and add it to the formatter if necessary
+ nFormat = xFormats->queryKey(sNewFormat, _rLocale, false);
+ if (nFormat == sal_Int32(-1))
+ nFormat = xFormats->addNew(sNewFormat, _rLocale);
+ }
+ }
+ catch (Exception&)
+ {
+ nFormat = _xTypes->getStandardFormat(static_cast<sal_Int16>(nNumberType), _rLocale);
+ }
+ } break;
+ case DataType::CHAR:
+ case DataType::VARCHAR:
+ case DataType::LONGVARCHAR:
+ case DataType::CLOB:
+ nFormat = _xTypes->getStandardFormat(NumberFormat::TEXT, _rLocale);
+ break;
+ case DataType::DATE:
+ nFormat = _xTypes->getStandardFormat(NumberFormat::DATE, _rLocale);
+ break;
+ case DataType::TIME:
+ nFormat = _xTypes->getStandardFormat(NumberFormat::TIME, _rLocale);
+ break;
+ case DataType::TIMESTAMP:
+ nFormat = _xTypes->getStandardFormat(NumberFormat::DATETIME, _rLocale);
+ break;
+ case DataType::BINARY:
+ case DataType::VARBINARY:
+ case DataType::LONGVARBINARY:
+ case DataType::SQLNULL:
+ case DataType::OTHER:
+ case DataType::OBJECT:
+ case DataType::DISTINCT:
+ case DataType::STRUCT:
+ case DataType::ARRAY:
+ case DataType::BLOB:
+ case DataType::REF:
+ default:
+ nFormat = _xTypes->getStandardFormat(NumberFormat::UNDEFINED, _rLocale);
+ }
+ return nFormat;
+}
+
+static Reference< XConnection> findConnection(const Reference< XInterface >& xParent)
+{
+ Reference< XConnection> xConnection(xParent, UNO_QUERY);
+ if (!xConnection.is())
+ {
+ Reference< XChild> xChild(xParent, UNO_QUERY);
+ if (xChild.is())
+ xConnection = findConnection(xChild->getParent());
+ }
+ return xConnection;
+}
+
+static Reference< XDataSource> getDataSource_allowException(
+ const OUString& _rsTitleOrPath,
+ const Reference< XComponentContext >& _rxContext )
+{
+ ENSURE_OR_RETURN( !_rsTitleOrPath.isEmpty(), "getDataSource_allowException: invalid arg !", nullptr );
+
+ Reference< XDatabaseContext> xDatabaseContext = DatabaseContext::create(_rxContext);
+
+ return Reference< XDataSource >( xDatabaseContext->getByName( _rsTitleOrPath ), UNO_QUERY );
+}
+
+Reference< XDataSource > getDataSource(
+ const OUString& _rsTitleOrPath,
+ const Reference< XComponentContext >& _rxContext )
+{
+ Reference< XDataSource > xDS;
+ try
+ {
+ xDS = getDataSource_allowException( _rsTitleOrPath, _rxContext );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("connectivity.commontools");
+ }
+
+ return xDS;
+}
+
+static Reference< XConnection > getConnection_allowException(
+ const OUString& _rsTitleOrPath,
+ const OUString& _rsUser,
+ const OUString& _rsPwd,
+ const Reference< XComponentContext>& _rxContext,
+ const Reference< XWindow >& _rxParent)
+{
+ Reference< XDataSource> xDataSource( getDataSource_allowException(_rsTitleOrPath, _rxContext) );
+ Reference<XConnection> xConnection;
+ if (xDataSource.is())
+ {
+
+ //set ParentWindow for dialog, but just for the duration of this
+ //call, undo at end of scope
+ Reference<XInitialization> xIni(xDataSource, UNO_QUERY);
+ if (xIni.is())
+ {
+ Sequence< Any > aArgs{ Any(NamedValue( "ParentWindow", Any(_rxParent) )) };
+ xIni->initialize(aArgs);
+ }
+
+ // do it with interaction handler
+ if(_rsUser.isEmpty() || _rsPwd.isEmpty())
+ {
+ Reference<XPropertySet> xProp(xDataSource,UNO_QUERY);
+ OUString sPwd, sUser;
+ bool bPwdReq = false;
+ try
+ {
+ xProp->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PASSWORD)) >>= sPwd;
+ bPwdReq = ::cppu::any2bool(xProp->getPropertyValue("IsPasswordRequired"));
+ xProp->getPropertyValue("User") >>= sUser;
+ }
+ catch(Exception&)
+ {
+ OSL_FAIL("dbtools::getConnection: error while retrieving data source properties!");
+ }
+ if(bPwdReq && sPwd.isEmpty())
+ { // password required, but empty -> connect using an interaction handler
+ Reference<XCompletedConnection> xConnectionCompletion(xProp, UNO_QUERY);
+ if (xConnectionCompletion.is())
+ { // instantiate the default SDB interaction handler
+ Reference< XInteractionHandler > xHandler =
+ InteractionHandler::createWithParent(_rxContext, _rxParent);
+ xConnection = xConnectionCompletion->connectWithCompletion(xHandler);
+ }
+ }
+ else
+ xConnection = xDataSource->getConnection(sUser, sPwd);
+ }
+ if(!xConnection.is()) // try to get one if not already have one, just to make sure
+ xConnection = xDataSource->getConnection(_rsUser, _rsPwd);
+
+ if (xIni.is())
+ {
+ Sequence< Any > aArgs{ Any(NamedValue( "ParentWindow", Any(Reference<XWindow>()) )) };
+ xIni->initialize(aArgs);
+ }
+
+ }
+ return xConnection;
+}
+
+Reference< XConnection> getConnection_withFeedback(const OUString& _rDataSourceName,
+ const OUString& _rUser, const OUString& _rPwd, const Reference< XComponentContext>& _rxContext,
+ const Reference< XWindow >& _rxParent)
+{
+ Reference< XConnection > xReturn;
+ try
+ {
+ xReturn = getConnection_allowException(_rDataSourceName, _rUser, _rPwd, _rxContext, _rxParent);
+ }
+ catch(SQLException&)
+ {
+ // allowed to pass
+ throw;
+ }
+ catch(Exception&)
+ {
+ TOOLS_WARN_EXCEPTION( "connectivity.commontools", "::dbtools::getConnection_withFeedback: unexpected (non-SQL) exception caught!");
+ }
+ return xReturn;
+}
+
+Reference< XConnection> getConnection(const Reference< XRowSet>& _rxRowSet)
+{
+ Reference< XConnection> xReturn;
+ Reference< XPropertySet> xRowSetProps(_rxRowSet, UNO_QUERY);
+ if (xRowSetProps.is())
+ xRowSetProps->getPropertyValue("ActiveConnection") >>= xReturn;
+ return xReturn;
+}
+
+// helper function which allows to implement both the connectRowset and the ensureRowSetConnection semantics
+// if connectRowset (which is deprecated) is removed, this function and one of its parameters are
+// not needed anymore, the whole implementation can be moved into ensureRowSetConnection then)
+static SharedConnection lcl_connectRowSet(const Reference< XRowSet>& _rxRowSet, const Reference< XComponentContext >& _rxContext,
+ bool _bAttachAutoDisposer, const Reference< XWindow >& _rxParent)
+{
+ SharedConnection xConnection;
+
+ do
+ {
+ Reference< XPropertySet> xRowSetProps(_rxRowSet, UNO_QUERY);
+ if ( !xRowSetProps.is() )
+ break;
+
+ // 1. already connected?
+ Reference< XConnection > xExistingConn(
+ xRowSetProps->getPropertyValue("ActiveConnection"),
+ UNO_QUERY );
+
+ if ( xExistingConn.is()
+ // 2. embedded in a database?
+ || isEmbeddedInDatabase( _rxRowSet, xExistingConn )
+ // 3. is there a connection in the parent hierarchy?
+ || ( xExistingConn = findConnection( _rxRowSet ) ).is()
+ )
+ {
+ xRowSetProps->setPropertyValue("ActiveConnection", Any( xExistingConn ) );
+ // no auto disposer needed, since we did not create the connection
+
+ xConnection.reset( xExistingConn, SharedConnection::NoTakeOwnership );
+ break;
+ }
+
+ // build a connection with its current settings (4. data source name, or 5. URL)
+
+ static constexpr OUString sUserProp( u"User"_ustr );
+ OUString sDataSourceName;
+ xRowSetProps->getPropertyValue("DataSourceName") >>= sDataSourceName;
+ OUString sURL;
+ xRowSetProps->getPropertyValue("URL") >>= sURL;
+
+ Reference< XConnection > xPureConnection;
+ if (!sDataSourceName.isEmpty())
+ { // the row set's data source property is set
+ // -> try to connect, get user and pwd setting for that
+ OUString sUser, sPwd;
+
+ if (hasProperty(sUserProp, xRowSetProps))
+ xRowSetProps->getPropertyValue(sUserProp) >>= sUser;
+ if (hasProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PASSWORD), xRowSetProps))
+ xRowSetProps->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PASSWORD)) >>= sPwd;
+
+ xPureConnection = getConnection_allowException( sDataSourceName, sUser, sPwd, _rxContext, _rxParent );
+ }
+ else if (!sURL.isEmpty())
+ { // the row set has no data source, but a connection url set
+ // -> try to connection with that url
+ Reference< XConnectionPool > xDriverManager;
+ try {
+ xDriverManager = ConnectionPool::create( _rxContext );
+ } catch( const Exception& ) { }
+ if (xDriverManager.is())
+ {
+ OUString sUser, sPwd;
+ if (hasProperty(sUserProp, xRowSetProps))
+ xRowSetProps->getPropertyValue(sUserProp) >>= sUser;
+ if (hasProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PASSWORD), xRowSetProps))
+ xRowSetProps->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PASSWORD)) >>= sPwd;
+ if (!sUser.isEmpty())
+ { // use user and pwd together with the url
+ auto aInfo(::comphelper::InitPropertySequence({
+ { "user", Any(sUser) },
+ { "password", Any(sPwd) }
+ }));
+ xPureConnection = xDriverManager->getConnectionWithInfo( sURL, aInfo );
+ }
+ else
+ // just use the url
+ xPureConnection = xDriverManager->getConnection( sURL );
+ }
+ }
+ xConnection.reset(
+ xPureConnection,
+ _bAttachAutoDisposer ? SharedConnection::NoTakeOwnership : SharedConnection::TakeOwnership
+ /* take ownership if and only if we're *not* going to auto-dispose the connection */
+ );
+
+ // now if we created a connection, forward it to the row set
+ if ( xConnection.is() )
+ {
+ try
+ {
+ if ( _bAttachAutoDisposer )
+ {
+ new OAutoConnectionDisposer( _rxRowSet, xConnection );
+ }
+ else
+ xRowSetProps->setPropertyValue(
+ "ActiveConnection",
+ Any( xConnection.getTyped() )
+ );
+ }
+ catch(Exception&)
+ {
+ TOOLS_WARN_EXCEPTION( "connectivity.commontools", "EXception when we set the new active connection!");
+ }
+ }
+ }
+ while ( false );
+
+ return xConnection;
+}
+
+Reference< XConnection> connectRowset(const Reference< XRowSet>& _rxRowSet, const Reference< XComponentContext >& _rxContext, const Reference< XWindow >& _rxParent)
+{
+ SharedConnection xConnection = lcl_connectRowSet( _rxRowSet, _rxContext, true, _rxParent );
+ return xConnection.getTyped();
+}
+
+SharedConnection ensureRowSetConnection(const Reference< XRowSet>& _rxRowSet, const Reference< XComponentContext>& _rxContext, const Reference< XWindow >& _rxParent)
+{
+ return lcl_connectRowSet( _rxRowSet, _rxContext, false/*bUseAutoConnectionDisposer*/, _rxParent );
+}
+
+Reference< XNameAccess> getTableFields(const Reference< XConnection>& _rxConn,const OUString& _rName)
+{
+ Reference< XComponent > xDummy;
+ return getFieldsByCommandDescriptor( _rxConn, CommandType::TABLE, _rName, xDummy );
+}
+
+Reference< XNameAccess> getPrimaryKeyColumns_throw(const Any& i_aTable)
+{
+ const Reference< XPropertySet > xTable(i_aTable,UNO_QUERY_THROW);
+ return getPrimaryKeyColumns_throw(xTable);
+}
+
+Reference< XNameAccess> getPrimaryKeyColumns_throw(const Reference< XPropertySet >& i_xTable)
+{
+ Reference<XNameAccess> xKeyColumns;
+ const Reference<XKeysSupplier> xKeySup(i_xTable,UNO_QUERY);
+ if ( xKeySup.is() )
+ {
+ const Reference<XIndexAccess> xKeys = xKeySup->getKeys();
+ if ( xKeys.is() )
+ {
+ ::dbtools::OPropertyMap& rPropMap = OMetaConnection::getPropMap();
+ const OUString& sPropName = rPropMap.getNameByIndex(PROPERTY_ID_TYPE);
+ Reference<XPropertySet> xProp;
+ const sal_Int32 nCount = xKeys->getCount();
+ for(sal_Int32 i = 0;i< nCount;++i)
+ {
+ xProp.set(xKeys->getByIndex(i),UNO_QUERY_THROW);
+ sal_Int32 nKeyType = 0;
+ xProp->getPropertyValue(sPropName) >>= nKeyType;
+ if(KeyType::PRIMARY == nKeyType)
+ {
+ const Reference<XColumnsSupplier> xKeyColsSup(xProp,UNO_QUERY_THROW);
+ xKeyColumns = xKeyColsSup->getColumns();
+ break;
+ }
+ }
+ }
+ }
+
+ return xKeyColumns;
+}
+
+namespace
+{
+ enum FieldLookupState
+ {
+ HANDLE_TABLE, HANDLE_QUERY, HANDLE_SQL, RETRIEVE_OBJECT, RETRIEVE_COLUMNS, DONE, FAILED
+ };
+}
+
+Reference< XNameAccess > getFieldsByCommandDescriptor( const Reference< XConnection >& _rxConnection,
+ const sal_Int32 _nCommandType, const OUString& _rCommand,
+ Reference< XComponent >& _rxKeepFieldsAlive, SQLExceptionInfo* _pErrorInfo )
+{
+ OSL_PRECOND( _rxConnection.is(), "::dbtools::getFieldsByCommandDescriptor: invalid connection!" );
+ OSL_PRECOND( ( CommandType::TABLE == _nCommandType ) || ( CommandType::QUERY == _nCommandType ) || ( CommandType::COMMAND == _nCommandType ),
+ "::dbtools::getFieldsByCommandDescriptor: invalid command type!" );
+ OSL_PRECOND( !_rCommand.isEmpty(), "::dbtools::getFieldsByCommandDescriptor: invalid command (empty)!" );
+
+ Reference< XNameAccess > xFields;
+
+ // reset the error
+ if ( _pErrorInfo )
+ *_pErrorInfo = SQLExceptionInfo();
+ // reset the ownership holder
+ _rxKeepFieldsAlive.clear();
+
+ // go for the fields
+ try
+ {
+ // some kind of state machine to ease the sharing of code
+ FieldLookupState eState = FAILED;
+ switch ( _nCommandType )
+ {
+ case CommandType::TABLE:
+ eState = HANDLE_TABLE;
+ break;
+ case CommandType::QUERY:
+ eState = HANDLE_QUERY;
+ break;
+ case CommandType::COMMAND:
+ eState = HANDLE_SQL;
+ break;
+ }
+
+ // needed in various states:
+ Reference< XNameAccess > xObjectCollection;
+ Reference< XColumnsSupplier > xSupplyColumns;
+
+ // go!
+ while ( ( DONE != eState ) && ( FAILED != eState ) )
+ {
+ switch ( eState )
+ {
+ case HANDLE_TABLE:
+ {
+ // initial state for handling the tables
+
+ // get the table objects
+ Reference< XTablesSupplier > xSupplyTables( _rxConnection, UNO_QUERY );
+ if ( xSupplyTables.is() )
+ xObjectCollection = xSupplyTables->getTables();
+ // if something went wrong 'til here, then this will be handled in the next state
+
+ // next state: get the object
+ eState = RETRIEVE_OBJECT;
+ }
+ break;
+
+ case HANDLE_QUERY:
+ {
+ // initial state for handling the tables
+
+ // get the table objects
+ Reference< XQueriesSupplier > xSupplyQueries( _rxConnection, UNO_QUERY );
+ if ( xSupplyQueries.is() )
+ xObjectCollection = xSupplyQueries->getQueries();
+ // if something went wrong 'til here, then this will be handled in the next state
+
+ // next state: get the object
+ eState = RETRIEVE_OBJECT;
+ }
+ break;
+
+ case RETRIEVE_OBJECT:
+ // here we should have an object (aka query or table) collection, and are going
+ // to retrieve the desired object
+
+ // next state: default to FAILED
+ eState = FAILED;
+
+ OSL_ENSURE( xObjectCollection.is(), "::dbtools::getFieldsByCommandDescriptor: invalid connection (no sdb.Connection, or no Tables-/QueriesSupplier)!");
+ if ( xObjectCollection.is() && xObjectCollection->hasByName( _rCommand ) )
+ {
+ xObjectCollection->getByName( _rCommand ) >>= xSupplyColumns;
+ // (xSupplyColumns being NULL will be handled in the next state)
+
+ // next: go for the columns
+ eState = RETRIEVE_COLUMNS;
+ }
+ break;
+
+ case RETRIEVE_COLUMNS:
+ OSL_ENSURE( xSupplyColumns.is(), "::dbtools::getFieldsByCommandDescriptor: could not retrieve the columns supplier!" );
+
+ // next state: default to FAILED
+ eState = FAILED;
+
+ if ( xSupplyColumns.is() )
+ {
+ xFields = xSupplyColumns->getColumns();
+ // that's it
+ eState = DONE;
+ }
+ break;
+
+ case HANDLE_SQL:
+ {
+ OUString sStatementToExecute( _rCommand );
+
+ // well, the main problem here is to handle statements which contain a parameter
+ // If we would simply execute a parametrized statement, then this will fail because
+ // we cannot supply any parameter values.
+ // Thus, we try to analyze the statement, and to append a WHERE 0=1 filter criterion
+ // This should cause every driver to not really execute the statement, but to return
+ // an empty result set with the proper structure. We then can use this result set
+ // to retrieve the columns.
+
+ try
+ {
+ Reference< XMultiServiceFactory > xComposerFac( _rxConnection, UNO_QUERY );
+
+ if ( xComposerFac.is() )
+ {
+ Reference< XSingleSelectQueryComposer > xComposer(xComposerFac->createInstance("com.sun.star.sdb.SingleSelectQueryComposer"),UNO_QUERY);
+ if ( xComposer.is() )
+ {
+ xComposer->setQuery( sStatementToExecute );
+
+ // Now set the filter to a dummy restriction which will result in an empty
+ // result set.
+ xComposer->setFilter( "0=1" );
+ sStatementToExecute = xComposer->getQuery( );
+ }
+ }
+ }
+ catch( const Exception& )
+ {
+ // silent this error, this was just a try. If we're here, we did not change sStatementToExecute,
+ // so it will still be _rCommand, which then will be executed without being touched
+ }
+
+ // now execute
+ Reference< XPreparedStatement > xStatement = _rxConnection->prepareStatement( sStatementToExecute );
+ // transfer ownership of this temporary object to the caller
+ _rxKeepFieldsAlive.set(xStatement, css::uno::UNO_QUERY);
+
+ // set the "MaxRows" to 0. This is just in case our attempt to append a 0=1 filter
+ // failed - in this case, the MaxRows restriction should at least ensure that there
+ // is no data returned (which would be potentially expensive)
+ Reference< XPropertySet > xStatementProps( xStatement,UNO_QUERY );
+ try
+ {
+ if ( xStatementProps.is() )
+ xStatementProps->setPropertyValue( "MaxRows", Any( sal_Int32( 0 ) ) );
+ }
+ catch( const Exception& )
+ {
+ OSL_FAIL( "::dbtools::getFieldsByCommandDescriptor: could not set the MaxRows!" );
+ // oh damn. Not much of a chance to recover, we will no retrieve the complete
+ // full blown result set
+ }
+
+ xSupplyColumns.set(xStatement->executeQuery(), css::uno::UNO_QUERY);
+ // this should have given us a result set which does not contain any data, but
+ // the structural information we need
+
+ // so the next state is to get the columns
+ eState = RETRIEVE_COLUMNS;
+ }
+ break;
+
+ default:
+ OSL_FAIL( "::dbtools::getFieldsByCommandDescriptor: oops! unhandled state here!" );
+ eState = FAILED;
+ }
+ }
+ }
+ catch( const SQLContext& e ) { if ( _pErrorInfo ) *_pErrorInfo = SQLExceptionInfo( e ); }
+ catch( const SQLWarning& e ) { if ( _pErrorInfo ) *_pErrorInfo = SQLExceptionInfo( e ); }
+ catch( const SQLException& e ) { if ( _pErrorInfo ) *_pErrorInfo = SQLExceptionInfo( e ); }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "connectivity.commontools", "::dbtools::getFieldsByCommandDescriptor: caught an exception while retrieving the fields!" );
+ }
+
+ return xFields;
+}
+
+Sequence< OUString > getFieldNamesByCommandDescriptor( const Reference< XConnection >& _rxConnection,
+ const sal_Int32 _nCommandType, const OUString& _rCommand,
+ SQLExceptionInfo* _pErrorInfo )
+{
+ // get the container for the fields
+ Reference< XComponent > xKeepFieldsAlive;
+ Reference< XNameAccess > xFieldContainer = getFieldsByCommandDescriptor( _rxConnection, _nCommandType, _rCommand, xKeepFieldsAlive, _pErrorInfo );
+
+ // get the names of the fields
+ Sequence< OUString > aNames;
+ if ( xFieldContainer.is() )
+ aNames = xFieldContainer->getElementNames();
+
+ // clean up any temporary objects which have been created
+ disposeComponent( xKeepFieldsAlive );
+
+ // outta here
+ return aNames;
+}
+
+SQLException prependErrorInfo( const SQLException& _rChainedException, const Reference< XInterface >& _rxContext,
+ const OUString& _rAdditionalError, const StandardSQLState _eSQLState )
+{
+ return SQLException( _rAdditionalError, _rxContext,
+ _eSQLState == StandardSQLState::ERROR_UNSPECIFIED ? OUString() : getStandardSQLState( _eSQLState ),
+ 0, Any( _rChainedException ) );
+}
+
+namespace
+{
+ struct NameComponentSupport
+ {
+ const bool bCatalogs;
+ const bool bSchemas;
+
+ NameComponentSupport( const bool _bCatalogs, const bool _bSchemas )
+ :bCatalogs( _bCatalogs )
+ ,bSchemas( _bSchemas )
+ {
+ }
+ };
+
+ NameComponentSupport lcl_getNameComponentSupport( const Reference< XDatabaseMetaData >& _rxMetaData, EComposeRule _eComposeRule )
+ {
+ OSL_PRECOND( _rxMetaData.is(), "lcl_getNameComponentSupport: invalid meta data!" );
+
+ FMetaDataSupport pCatalogCall = &XDatabaseMetaData::supportsCatalogsInDataManipulation;
+ FMetaDataSupport pSchemaCall = &XDatabaseMetaData::supportsSchemasInDataManipulation;
+ bool bIgnoreMetaData = false;
+
+ switch ( _eComposeRule )
+ {
+ case EComposeRule::InTableDefinitions:
+ pCatalogCall = &XDatabaseMetaData::supportsCatalogsInTableDefinitions;
+ pSchemaCall = &XDatabaseMetaData::supportsSchemasInTableDefinitions;
+ break;
+ case EComposeRule::InIndexDefinitions:
+ pCatalogCall = &XDatabaseMetaData::supportsCatalogsInIndexDefinitions;
+ pSchemaCall = &XDatabaseMetaData::supportsSchemasInIndexDefinitions;
+ break;
+ case EComposeRule::InProcedureCalls:
+ pCatalogCall = &XDatabaseMetaData::supportsCatalogsInProcedureCalls;
+ pSchemaCall = &XDatabaseMetaData::supportsSchemasInProcedureCalls;
+ break;
+ case EComposeRule::InPrivilegeDefinitions:
+ pCatalogCall = &XDatabaseMetaData::supportsCatalogsInPrivilegeDefinitions;
+ pSchemaCall = &XDatabaseMetaData::supportsSchemasInPrivilegeDefinitions;
+ break;
+ case EComposeRule::Complete:
+ bIgnoreMetaData = true;
+ break;
+ case EComposeRule::InDataManipulation:
+ // already properly set above
+ break;
+ }
+ return NameComponentSupport(
+ bIgnoreMetaData || (_rxMetaData.get()->*pCatalogCall)(),
+ bIgnoreMetaData || (_rxMetaData.get()->*pSchemaCall)()
+ );
+ }
+}
+
+static OUString impl_doComposeTableName( const Reference< XDatabaseMetaData >& _rxMetaData,
+ const OUString& _rCatalog, const OUString& _rSchema, const OUString& _rName,
+ bool _bQuote, EComposeRule _eComposeRule )
+{
+ OSL_ENSURE(_rxMetaData.is(), "impl_doComposeTableName : invalid meta data !");
+ if ( !_rxMetaData.is() )
+ return OUString();
+ OSL_ENSURE(!_rName.isEmpty(), "impl_doComposeTableName : at least the name should be non-empty !");
+
+ const OUString sQuoteString = _rxMetaData->getIdentifierQuoteString();
+ const NameComponentSupport aNameComps( lcl_getNameComponentSupport( _rxMetaData, _eComposeRule ) );
+
+ OUStringBuffer aComposedName;
+
+ OUString sCatalogSep;
+ bool bCatalogAtStart = true;
+ if ( !_rCatalog.isEmpty() && aNameComps.bCatalogs )
+ {
+ sCatalogSep = _rxMetaData->getCatalogSeparator();
+ bCatalogAtStart = _rxMetaData->isCatalogAtStart();
+
+ if ( bCatalogAtStart && !sCatalogSep.isEmpty())
+ {
+ aComposedName.append( _bQuote ? quoteName( sQuoteString, _rCatalog ) : _rCatalog );
+ aComposedName.append( sCatalogSep );
+ }
+ }
+
+ if ( !_rSchema.isEmpty() && aNameComps.bSchemas )
+ {
+ aComposedName.append(
+ (_bQuote ? quoteName( sQuoteString, _rSchema ) : _rSchema )
+ + "." );
+ }
+
+ aComposedName.append( _bQuote ? quoteName( sQuoteString, _rName ) : _rName );
+
+ if ( !_rCatalog.isEmpty()
+ && !bCatalogAtStart
+ && !sCatalogSep.isEmpty()
+ && aNameComps.bCatalogs
+ )
+ {
+ aComposedName.append( sCatalogSep );
+ aComposedName.append( _bQuote ? quoteName( sQuoteString, _rCatalog ) : _rCatalog );
+ }
+
+ return aComposedName.makeStringAndClear();
+}
+
+OUString quoteTableName(const Reference< XDatabaseMetaData>& _rxMeta
+ , const OUString& _rName
+ , EComposeRule _eComposeRule)
+{
+ OUString sCatalog, sSchema, sTable;
+ qualifiedNameComponents(_rxMeta,_rName,sCatalog,sSchema,sTable,_eComposeRule);
+ return impl_doComposeTableName( _rxMeta, sCatalog, sSchema, sTable, true, _eComposeRule );
+}
+
+void qualifiedNameComponents(const Reference< XDatabaseMetaData >& _rxConnMetaData, const OUString& _rQualifiedName, OUString& _rCatalog, OUString& _rSchema, OUString& _rName,EComposeRule _eComposeRule)
+{
+ OSL_ENSURE(_rxConnMetaData.is(), "QualifiedNameComponents : invalid meta data!");
+
+ NameComponentSupport aNameComps( lcl_getNameComponentSupport( _rxConnMetaData, _eComposeRule ) );
+
+ OUString sSeparator = _rxConnMetaData->getCatalogSeparator();
+
+ OUString sName(_rQualifiedName);
+ // do we have catalogs?
+ if ( aNameComps.bCatalogs )
+ {
+ if (_rxConnMetaData->isCatalogAtStart())
+ {
+ // search for the catalog name at the beginning
+ sal_Int32 nIndex = sName.indexOf(sSeparator);
+ if (-1 != nIndex)
+ {
+ _rCatalog = sName.copy(0, nIndex);
+ sName = sName.copy(nIndex + 1);
+ }
+ }
+ else
+ {
+ // Catalog name at the end
+ sal_Int32 nIndex = sName.lastIndexOf(sSeparator);
+ if (-1 != nIndex)
+ {
+ _rCatalog = sName.copy(nIndex + 1);
+ sName = sName.copy(0, nIndex);
+ }
+ }
+ }
+
+ if ( aNameComps.bSchemas )
+ {
+ sal_Int32 nIndex = sName.indexOf('.');
+ // OSL_ENSURE(-1 != nIndex, "QualifiedNameComponents: no schema separator!");
+ if ( nIndex != -1 )
+ _rSchema = sName.copy(0, nIndex);
+ sName = sName.copy(nIndex + 1);
+ }
+
+ _rName = sName;
+}
+
+Reference< XNumberFormatsSupplier> getNumberFormats(
+ const Reference< XConnection>& _rxConn,
+ bool _bAlloweDefault,
+ const Reference< XComponentContext>& _rxContext)
+{
+ // ask the parent of the connection (should be a DatabaseAccess)
+ Reference< XNumberFormatsSupplier> xReturn;
+ Reference< XChild> xConnAsChild(_rxConn, UNO_QUERY);
+ static constexpr OUString sPropFormatsSupplier( u"NumberFormatsSupplier"_ustr );
+ if (xConnAsChild.is())
+ {
+ Reference< XPropertySet> xConnParentProps(xConnAsChild->getParent(), UNO_QUERY);
+ if (xConnParentProps.is() && hasProperty(sPropFormatsSupplier, xConnParentProps))
+ xConnParentProps->getPropertyValue(sPropFormatsSupplier) >>= xReturn;
+ }
+ else if(_bAlloweDefault && _rxContext.is())
+ {
+ xReturn = NumberFormatsSupplier::createWithDefaultLocale( _rxContext );
+ }
+ return xReturn;
+}
+
+void TransferFormComponentProperties(
+ const Reference< XPropertySet>& xOldProps,
+ const Reference< XPropertySet>& xNewProps,
+ const Locale& _rLocale)
+{
+try
+{
+ OSL_ENSURE( xOldProps.is() && xNewProps.is(), "TransferFormComponentProperties: invalid source/dest!" );
+ if ( !xOldProps.is() || !xNewProps.is() )
+ return;
+
+ // First we copy all the Props, that are available in source and target and have the same description
+ Reference< XPropertySetInfo> xOldInfo( xOldProps->getPropertySetInfo());
+ Reference< XPropertySetInfo> xNewInfo( xNewProps->getPropertySetInfo());
+
+ const Sequence< Property> aOldProperties = xOldInfo->getProperties();
+ const Sequence< Property> aNewProperties = xNewInfo->getProperties();
+
+ static constexpr OUString sPropFormatsSupplier(u"FormatsSupplier"_ustr);
+ static constexpr OUString sPropCurrencySymbol(u"CurrencySymbol"_ustr);
+ static constexpr OUString sPropDecimals(u"Decimals"_ustr);
+ static constexpr OUString sPropEffectiveMin(u"EffectiveMin"_ustr);
+ static constexpr OUString sPropEffectiveMax(u"EffectiveMax"_ustr);
+ static constexpr OUString sPropEffectiveDefault(u"EffectiveDefault"_ustr);
+ static constexpr OUString sPropDefaultText(u"DefaultText"_ustr);
+ static constexpr OUString sPropDefaultDate(u"DefaultDate"_ustr);
+ static constexpr OUString sPropDefaultTime(u"DefaultTime"_ustr);
+ static constexpr OUString sPropValueMin(u"ValueMin"_ustr);
+ static constexpr OUString sPropValueMax(u"ValueMax"_ustr);
+ static constexpr OUString sPropDecimalAccuracy(u"DecimalAccuracy"_ustr);
+ static constexpr OUString sPropClassId(u"ClassId"_ustr);
+ static constexpr OUString sFormattedServiceName( u"com.sun.star.form.component.FormattedField"_ustr );
+
+ for (const Property& rOldProp : aOldProperties)
+ {
+ if ( rOldProp.Name != "DefaultControl" && rOldProp.Name != "LabelControl" )
+ {
+ // binary search
+ const Property* pResult = std::lower_bound(
+ aNewProperties.begin(), aNewProperties.end(), rOldProp, ::comphelper::PropertyCompareByName());
+
+ if ( ( pResult != aNewProperties.end() )
+ && ( pResult->Name == rOldProp.Name )
+ && ( (pResult->Attributes & PropertyAttribute::READONLY) == 0 )
+ && ( pResult->Type.equals(rOldProp.Type)) )
+ { // Attributes match and the property is not read-only
+ try
+ {
+ xNewProps->setPropertyValue(pResult->Name, xOldProps->getPropertyValue(pResult->Name));
+ }
+ catch(IllegalArgumentException const &)
+ {
+ TOOLS_WARN_EXCEPTION( "connectivity.commontools", "TransferFormComponentProperties : could not transfer the value for property \""
+ << pResult->Name << "\"");
+ }
+ }
+ }
+ }
+
+ // for formatted fields (either old or new) we have some special treatments
+ Reference< XServiceInfo > xSI( xOldProps, UNO_QUERY );
+ bool bOldIsFormatted = xSI.is() && xSI->supportsService( sFormattedServiceName );
+ xSI.set( xNewProps, UNO_QUERY );
+ bool bNewIsFormatted = xSI.is() && xSI->supportsService( sFormattedServiceName );
+
+ if (!bOldIsFormatted && !bNewIsFormatted)
+ return; // nothing to do
+
+ if (bOldIsFormatted && bNewIsFormatted)
+ // if both fields are formatted we do no conversions
+ return;
+
+ if (bOldIsFormatted)
+ {
+ // get some properties from the selected format and put them in the new Set
+ Any aFormatKey( xOldProps->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FORMATKEY)) );
+ if (aFormatKey.hasValue())
+ {
+ Reference< XNumberFormatsSupplier> xSupplier;
+ xOldProps->getPropertyValue(sPropFormatsSupplier) >>= xSupplier;
+ if (xSupplier.is())
+ {
+ Reference< XNumberFormats> xFormats(xSupplier->getNumberFormats());
+ Reference< XPropertySet> xFormat(xFormats->getByKey(getINT32(aFormatKey)));
+ if (hasProperty(sPropCurrencySymbol, xFormat))
+ {
+ Any aVal( xFormat->getPropertyValue(sPropCurrencySymbol) );
+ if (aVal.hasValue() && hasProperty(sPropCurrencySymbol, xNewProps))
+ // If the source value hasn't been set then don't copy it
+ // so we don't overwrite the default value
+ xNewProps->setPropertyValue(sPropCurrencySymbol, aVal);
+ }
+ if (hasProperty(sPropDecimals, xFormat) && hasProperty(sPropDecimals, xNewProps))
+ xNewProps->setPropertyValue(sPropDecimals, xFormat->getPropertyValue(sPropDecimals));
+ }
+ }
+
+ // a potential Min-Max-Conversion
+ Any aEffectiveMin( xOldProps->getPropertyValue(sPropEffectiveMin) );
+ if (aEffectiveMin.hasValue())
+ { // Unlike the ValueMin the EffectiveMin can be void
+ if (hasProperty(sPropValueMin, xNewProps))
+ {
+ OSL_ENSURE(aEffectiveMin.getValueType().getTypeClass() == TypeClass_DOUBLE,
+ "TransferFormComponentProperties : invalid property type !");
+ xNewProps->setPropertyValue(sPropValueMin, aEffectiveMin);
+ }
+ }
+ Any aEffectiveMax( xOldProps->getPropertyValue(sPropEffectiveMax) );
+ if (aEffectiveMax.hasValue())
+ { // analog
+ if (hasProperty(sPropValueMax, xNewProps))
+ {
+ OSL_ENSURE(aEffectiveMax.getValueType().getTypeClass() == TypeClass_DOUBLE,
+ "TransferFormComponentProperties : invalid property type !");
+ xNewProps->setPropertyValue(sPropValueMax, aEffectiveMax);
+ }
+ }
+
+ // then we can still convert and copy the default values
+ Any aEffectiveDefault( xOldProps->getPropertyValue(sPropEffectiveDefault) );
+ if (aEffectiveDefault.hasValue())
+ {
+ bool bIsString = aEffectiveDefault.getValueType().getTypeClass() == TypeClass_STRING;
+ OSL_ENSURE(bIsString || aEffectiveDefault.getValueType().getTypeClass() == TypeClass_DOUBLE,
+ "TransferFormComponentProperties : invalid property type !");
+ // The Effective-Properties should always be void or string or double...
+
+ if (hasProperty(sPropDefaultDate, xNewProps) && !bIsString)
+ { // (to convert an OUString into a date will not always succeed, because it might be bound to a text-column,
+ // but we can work with a double)
+ Date aDate = DBTypeConversion::toDate(getDouble(aEffectiveDefault));
+ xNewProps->setPropertyValue(sPropDefaultDate, Any(aDate));
+ }
+
+ if (hasProperty(sPropDefaultTime, xNewProps) && !bIsString)
+ { // Completely analogous to time
+ css::util::Time aTime = DBTypeConversion::toTime(getDouble(aEffectiveDefault));
+ xNewProps->setPropertyValue(sPropDefaultTime, Any(aTime));
+ }
+
+ if (hasProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DEFAULTVALUE), xNewProps) && !bIsString)
+ { // Here we can simply pass the double
+ xNewProps->setPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DEFAULTVALUE), aEffectiveDefault);
+ }
+
+ if (hasProperty(sPropDefaultText, xNewProps) && bIsString)
+ { // and here the OUString
+ xNewProps->setPropertyValue(sPropDefaultText, aEffectiveDefault);
+ }
+
+ // nyi: The translation between doubles and OUString would offer more alternatives
+ }
+ }
+
+ // The other direction: the new Control shall be formatted
+ if (bNewIsFormatted)
+ {
+ // first the formatting
+ // we can't set a Supplier, so the new Set must bring one in
+ Reference< XNumberFormatsSupplier> xSupplier;
+ xNewProps->getPropertyValue(sPropFormatsSupplier) >>= xSupplier;
+ if (xSupplier.is())
+ {
+ Reference< XNumberFormats> xFormats(xSupplier->getNumberFormats());
+
+ // Set number of decimals
+ sal_Int16 nDecimals = 2;
+ if (hasProperty(sPropDecimalAccuracy, xOldProps))
+ xOldProps->getPropertyValue(sPropDecimalAccuracy) >>= nDecimals;
+
+ // base format (depending on the ClassId of the old Set)
+ sal_Int32 nBaseKey = 0;
+ if (hasProperty(sPropClassId, xOldProps))
+ {
+ Reference< XNumberFormatTypes> xTypeList(xFormats, UNO_QUERY);
+ if (xTypeList.is())
+ {
+ sal_Int16 nClassId = 0;
+ xOldProps->getPropertyValue(sPropClassId) >>= nClassId;
+ switch (nClassId)
+ {
+ case FormComponentType::DATEFIELD :
+ nBaseKey = xTypeList->getStandardFormat(NumberFormat::DATE, _rLocale);
+ break;
+
+ case FormComponentType::TIMEFIELD :
+ nBaseKey = xTypeList->getStandardFormat(NumberFormat::TIME, _rLocale);
+ break;
+
+ case FormComponentType::CURRENCYFIELD :
+ nBaseKey = xTypeList->getStandardFormat(NumberFormat::CURRENCY, _rLocale);
+ break;
+ }
+ }
+ }
+
+ // With this we can generate a new format ...
+ OUString sNewFormat = xFormats->generateFormat(nBaseKey, _rLocale, false, false, nDecimals, 0);
+ // No thousands separator, negative numbers are not in red, no leading zeros
+
+ // ... and add at FormatsSupplier (if needed)
+ sal_Int32 nKey = xFormats->queryKey(sNewFormat, _rLocale, false);
+ if (nKey == sal_Int32(-1))
+ { // not added yet in my formatter ...
+ nKey = xFormats->addNew(sNewFormat, _rLocale);
+ }
+
+ xNewProps->setPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FORMATKEY), Any(nKey));
+ }
+
+ // min-/max-Value
+ Any aNewMin, aNewMax;
+ if (hasProperty(sPropValueMin, xOldProps))
+ aNewMin = xOldProps->getPropertyValue(sPropValueMin);
+ if (hasProperty(sPropValueMax, xOldProps))
+ aNewMax = xOldProps->getPropertyValue(sPropValueMax);
+ xNewProps->setPropertyValue(sPropEffectiveMin, aNewMin);
+ xNewProps->setPropertyValue(sPropEffectiveMax, aNewMax);
+
+ // Default-Value
+ Any aNewDefault;
+ if (hasProperty(sPropDefaultDate, xOldProps))
+ {
+ Any aDate( xOldProps->getPropertyValue(sPropDefaultDate) );
+ if (aDate.hasValue())
+ aNewDefault <<= DBTypeConversion::toDouble(*o3tl::doAccess<Date>(aDate));
+ }
+
+ if (hasProperty(sPropDefaultTime, xOldProps))
+ {
+ Any aTime( xOldProps->getPropertyValue(sPropDefaultTime) );
+ if (aTime.hasValue())
+ aNewDefault <<= DBTypeConversion::toDouble(*o3tl::doAccess<Time>(aTime));
+ }
+
+ // double or OUString will be copied directly
+ if (hasProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DEFAULTVALUE), xOldProps))
+ aNewDefault = xOldProps->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DEFAULTVALUE));
+ if (hasProperty(sPropDefaultText, xOldProps))
+ aNewDefault = xOldProps->getPropertyValue(sPropDefaultText);
+
+ if (aNewDefault.hasValue())
+ xNewProps->setPropertyValue(sPropEffectiveDefault, aNewDefault);
+ }
+}
+catch(const Exception&)
+{
+ TOOLS_WARN_EXCEPTION( "connectivity.commontools", "TransferFormComponentProperties" );
+}
+}
+
+bool canInsert(const Reference< XPropertySet>& _rxCursorSet)
+{
+ return (_rxCursorSet.is() && (getINT32(_rxCursorSet->getPropertyValue("Privileges")) & Privilege::INSERT) != 0);
+}
+
+bool canUpdate(const Reference< XPropertySet>& _rxCursorSet)
+{
+ return (_rxCursorSet.is() && (getINT32(_rxCursorSet->getPropertyValue("Privileges")) & Privilege::UPDATE) != 0);
+}
+
+bool canDelete(const Reference< XPropertySet>& _rxCursorSet)
+{
+ return (_rxCursorSet.is() && (getINT32(_rxCursorSet->getPropertyValue("Privileges")) & Privilege::DELETE) != 0);
+}
+
+Reference< XDataSource> findDataSource(const Reference< XInterface >& _xParent)
+{
+ Reference< XOfficeDatabaseDocument> xDatabaseDocument(_xParent, UNO_QUERY);
+ Reference< XDataSource> xDataSource;
+ if ( xDatabaseDocument.is() )
+ xDataSource = xDatabaseDocument->getDataSource();
+ if ( !xDataSource.is() )
+ xDataSource.set(_xParent, UNO_QUERY);
+ if (!xDataSource.is())
+ {
+ Reference< XChild> xChild(_xParent, UNO_QUERY);
+ if ( xChild.is() )
+ xDataSource = findDataSource(xChild->getParent());
+ }
+ return xDataSource;
+}
+
+static Reference< XSingleSelectQueryComposer > getComposedRowSetStatement( const Reference< XPropertySet >& _rxRowSet, const Reference< XComponentContext >& _rxContext, const Reference< XWindow >& _rxParent )
+{
+ Reference< XSingleSelectQueryComposer > xComposer;
+ try
+ {
+ Reference< XConnection> xConn = connectRowset( Reference< XRowSet >( _rxRowSet, UNO_QUERY ), _rxContext, _rxParent );
+ if ( xConn.is() ) // implies _rxRowSet.is()
+ {
+ // build the statement the row set is based on (can't use the ActiveCommand property of the set
+ // as this reflects the status after the last execute, not the currently set properties)
+
+ sal_Int32 nCommandType = CommandType::COMMAND;
+ OUString sCommand;
+ bool bEscapeProcessing = false;
+
+ OSL_VERIFY( _rxRowSet->getPropertyValue("CommandType") >>= nCommandType );
+ OSL_VERIFY( _rxRowSet->getPropertyValue("Command") >>= sCommand );
+ OSL_VERIFY( _rxRowSet->getPropertyValue("EscapeProcessing") >>= bEscapeProcessing );
+
+ StatementComposer aComposer( xConn, sCommand, nCommandType, bEscapeProcessing );
+ // append sort
+ aComposer.setOrder( getString( _rxRowSet->getPropertyValue("Order") ) );
+
+ // append filter
+ bool bApplyFilter = true;
+ _rxRowSet->getPropertyValue("ApplyFilter") >>= bApplyFilter;
+ if ( bApplyFilter )
+ {
+ aComposer.setFilter( getString( _rxRowSet->getPropertyValue("Filter") ) );
+ aComposer.setHavingClause( getString( _rxRowSet->getPropertyValue("HavingClause") ) );
+ }
+
+ aComposer.getQuery();
+
+ xComposer = aComposer.getComposer();
+ aComposer.setDisposeComposer( false );
+ }
+ }
+ catch( const SQLException& )
+ {
+ throw;
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("connectivity.commontools");
+ }
+
+ return xComposer;
+}
+
+Reference< XSingleSelectQueryComposer > getCurrentSettingsComposer(
+ const Reference< XPropertySet>& _rxRowSetProps,
+ const Reference< XComponentContext>& _rxContext,
+ const Reference< XWindow >& _rxParent)
+{
+ Reference< XSingleSelectQueryComposer > xReturn;
+ try
+ {
+ xReturn = getComposedRowSetStatement( _rxRowSetProps, _rxContext, _rxParent );
+ }
+ catch( const SQLException& )
+ {
+ throw;
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "connectivity.commontools", "::getCurrentSettingsComposer : caught an exception !" );
+ }
+
+ return xReturn;
+}
+
+OUString composeTableName( const Reference< XDatabaseMetaData >& _rxMetaData,
+ const OUString& _rCatalog,
+ const OUString& _rSchema,
+ const OUString& _rName,
+ bool _bQuote,
+ EComposeRule _eComposeRule)
+{
+ return impl_doComposeTableName( _rxMetaData, _rCatalog, _rSchema, _rName, _bQuote, _eComposeRule );
+}
+
+OUString composeTableNameForSelect( const Reference< XConnection >& _rxConnection,
+ const OUString& _rCatalog, const OUString& _rSchema, const OUString& _rName )
+{
+ bool bUseCatalogInSelect = isDataSourcePropertyEnabled( _rxConnection, "UseCatalogInSelect", true );
+ bool bUseSchemaInSelect = isDataSourcePropertyEnabled( _rxConnection, "UseSchemaInSelect", true );
+
+ return impl_doComposeTableName(
+ _rxConnection->getMetaData(),
+ bUseCatalogInSelect ? _rCatalog : OUString(),
+ bUseSchemaInSelect ? _rSchema : OUString(),
+ _rName,
+ true,
+ EComposeRule::InDataManipulation
+ );
+}
+
+namespace
+{
+ void lcl_getTableNameComponents( const Reference<XPropertySet>& _xTable,
+ OUString& _out_rCatalog, OUString& _out_rSchema, OUString& _out_rName )
+ {
+ ::dbtools::OPropertyMap& rPropMap = OMetaConnection::getPropMap();
+ Reference< XPropertySetInfo > xInfo;
+ if (_xTable.is())
+ xInfo = _xTable->getPropertySetInfo();
+ if ( xInfo.is()
+ && xInfo->hasPropertyByName(rPropMap.getNameByIndex(PROPERTY_ID_NAME)) )
+ {
+ if ( xInfo->hasPropertyByName(rPropMap.getNameByIndex(PROPERTY_ID_CATALOGNAME))
+ && xInfo->hasPropertyByName(rPropMap.getNameByIndex(PROPERTY_ID_SCHEMANAME)) )
+ {
+ _xTable->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_CATALOGNAME)) >>= _out_rCatalog;
+ _xTable->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_SCHEMANAME)) >>= _out_rSchema;
+ }
+ _xTable->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_NAME)) >>= _out_rName;
+ }
+ else
+ OSL_FAIL( "::dbtools::lcl_getTableNameComponents: this is no table object!" );
+ }
+}
+
+OUString composeTableNameForSelect( const Reference< XConnection >& _rxConnection, const Reference<XPropertySet>& _xTable )
+{
+ OUString sCatalog, sSchema, sName;
+ lcl_getTableNameComponents( _xTable, sCatalog, sSchema, sName );
+
+ return composeTableNameForSelect( _rxConnection, sCatalog, sSchema, sName );
+}
+
+OUString composeTableName(const Reference<XDatabaseMetaData>& _xMetaData,
+ const Reference<XPropertySet>& _xTable,
+ EComposeRule _eComposeRule,
+ bool _bQuote )
+{
+ OUString sCatalog, sSchema, sName;
+ lcl_getTableNameComponents( _xTable, sCatalog, sSchema, sName );
+
+ return impl_doComposeTableName(
+ _xMetaData,
+ sCatalog,
+ sSchema,
+ sName,
+ _bQuote,
+ _eComposeRule
+ );
+}
+
+sal_Int32 getSearchColumnFlag( const Reference< XConnection>& _rxConn,sal_Int32 _nDataType)
+{
+ sal_Int32 nSearchFlag = 0;
+ Reference<XResultSet> xSet = _rxConn->getMetaData()->getTypeInfo();
+ if(xSet.is())
+ {
+ Reference<XRow> xRow(xSet,UNO_QUERY);
+ while(xSet->next())
+ {
+ if(xRow->getInt(2) == _nDataType)
+ {
+ nSearchFlag = xRow->getInt(9);
+ break;
+ }
+ }
+ }
+ return nSearchFlag;
+}
+
+OUString createUniqueName( const Sequence< OUString >& _rNames, const OUString& _rBaseName, bool _bStartWithNumber )
+{
+ std::set< OUString > aUsedNames(_rNames.begin(), _rNames.end());
+
+ OUString sName( _rBaseName );
+ sal_Int32 nPos = 1;
+ if ( _bStartWithNumber )
+ sName += OUString::number( nPos );
+
+ while ( aUsedNames.find( sName ) != aUsedNames.end() )
+ {
+ sName = _rBaseName + OUString::number( ++nPos );
+ }
+ return sName;
+}
+
+OUString createUniqueName(const Reference<XNameAccess>& _rxContainer,const OUString& _rBaseName, bool _bStartWithNumber)
+{
+ Sequence< OUString > aElementNames;
+
+ OSL_ENSURE( _rxContainer.is(), "createUniqueName: invalid container!" );
+ if ( _rxContainer.is() )
+ aElementNames = _rxContainer->getElementNames();
+
+ return createUniqueName( aElementNames, _rBaseName, _bStartWithNumber );
+}
+
+void showError(const SQLExceptionInfo& _rInfo,
+ const Reference< XWindow>& _xParent,
+ const Reference< XComponentContext >& _rxContext)
+{
+ if (_rInfo.isValid())
+ {
+ try
+ {
+ Reference< XExecutableDialog > xErrorDialog = ErrorMessageDialog::create( _rxContext, "", _xParent, _rInfo.get() );
+ xErrorDialog->execute();
+ }
+ catch(const Exception&)
+ {
+ OSL_FAIL("showError: could not display the error message!");
+ }
+ }
+}
+
+bool implUpdateObject(const Reference< XRowUpdate >& _rxUpdatedObject,
+ const sal_Int32 _nColumnIndex, const Any& _rValue)
+{
+ bool bSuccessfullyReRouted = true;
+ switch (_rValue.getValueTypeClass())
+ {
+ case TypeClass_ANY:
+ {
+ bSuccessfullyReRouted = implUpdateObject(_rxUpdatedObject, _nColumnIndex, _rValue);
+ }
+ break;
+
+ case TypeClass_VOID:
+ _rxUpdatedObject->updateNull(_nColumnIndex);
+ break;
+
+ case TypeClass_STRING:
+ _rxUpdatedObject->updateString(_nColumnIndex, *o3tl::forceAccess<OUString>(_rValue));
+ break;
+
+ case TypeClass_BOOLEAN:
+ _rxUpdatedObject->updateBoolean(_nColumnIndex, *o3tl::forceAccess<bool>(_rValue));
+ break;
+
+ case TypeClass_BYTE:
+ _rxUpdatedObject->updateByte(_nColumnIndex, *o3tl::forceAccess<sal_Int8>(_rValue));
+ break;
+
+ case TypeClass_UNSIGNED_SHORT:
+ case TypeClass_SHORT:
+ _rxUpdatedObject->updateShort(_nColumnIndex, *o3tl::forceAccess<sal_Int16>(_rValue));
+ break;
+
+ case TypeClass_CHAR:
+ _rxUpdatedObject->updateString(_nColumnIndex,OUString(*o3tl::forceAccess<sal_Unicode>(_rValue)));
+ break;
+
+ case TypeClass_UNSIGNED_LONG:
+ case TypeClass_LONG:
+ _rxUpdatedObject->updateInt(_nColumnIndex, *o3tl::forceAccess<sal_Int32>(_rValue));
+ break;
+
+ case TypeClass_HYPER:
+ {
+ sal_Int64 nValue = 0;
+ OSL_VERIFY( _rValue >>= nValue );
+ _rxUpdatedObject->updateLong( _nColumnIndex, nValue );
+ }
+ break;
+
+ case TypeClass_FLOAT:
+ _rxUpdatedObject->updateFloat(_nColumnIndex, *o3tl::forceAccess<float>(_rValue));
+ break;
+
+ case TypeClass_DOUBLE:
+ _rxUpdatedObject->updateDouble(_nColumnIndex, *o3tl::forceAccess<double>(_rValue));
+ break;
+
+ case TypeClass_SEQUENCE:
+ if (auto s = o3tl::tryAccess<Sequence< sal_Int8 >>(_rValue))
+ _rxUpdatedObject->updateBytes(_nColumnIndex, *s);
+ else
+ bSuccessfullyReRouted = false;
+ break;
+ case TypeClass_STRUCT:
+ if (auto s1 = o3tl::tryAccess<DateTime>(_rValue))
+ _rxUpdatedObject->updateTimestamp(_nColumnIndex, *s1);
+ else if (auto s2 = o3tl::tryAccess<Date>(_rValue))
+ _rxUpdatedObject->updateDate(_nColumnIndex, *s2);
+ else if (auto s3 = o3tl::tryAccess<Time>(_rValue))
+ _rxUpdatedObject->updateTime(_nColumnIndex, *s3);
+ else
+ bSuccessfullyReRouted = false;
+ break;
+
+ case TypeClass_INTERFACE:
+ if (auto xStream = o3tl::tryAccess<Reference<XInputStream>>(_rValue))
+ {
+ _rxUpdatedObject->updateBinaryStream(_nColumnIndex, *xStream, (*xStream)->available());
+ break;
+ }
+ [[fallthrough]];
+ default:
+ bSuccessfullyReRouted = false;
+ }
+
+ return bSuccessfullyReRouted;
+}
+
+bool implSetObject( const Reference< XParameters >& _rxParameters,
+ const sal_Int32 _nColumnIndex, const Any& _rValue)
+{
+ bool bSuccessfullyReRouted = true;
+ switch (_rValue.getValueTypeClass())
+ {
+ case TypeClass_UNSIGNED_HYPER:
+ {
+ sal_uInt64 nValue = 0;
+ OSL_VERIFY( _rValue >>= nValue );
+ _rxParameters->setString(_nColumnIndex, OUString::number(nValue));
+ }
+ break;
+
+ case TypeClass_UNSIGNED_LONG:
+ case TypeClass_HYPER:
+ {
+ sal_Int64 nValue = 0;
+ OSL_VERIFY( _rValue >>= nValue );
+ _rxParameters->setLong( _nColumnIndex, nValue );
+ }
+ break;
+
+ case TypeClass_ANY:
+ {
+ bSuccessfullyReRouted = implSetObject(_rxParameters, _nColumnIndex, _rValue);
+ }
+ break;
+
+ case TypeClass_VOID:
+ _rxParameters->setNull(_nColumnIndex,DataType::VARCHAR);
+ break;
+
+ case TypeClass_STRING:
+ _rxParameters->setString(_nColumnIndex, *o3tl::forceAccess<OUString>(_rValue));
+ break;
+
+ case TypeClass_BOOLEAN:
+ _rxParameters->setBoolean(_nColumnIndex, *o3tl::forceAccess<bool>(_rValue));
+ break;
+
+ case TypeClass_BYTE:
+ _rxParameters->setByte(_nColumnIndex, *o3tl::forceAccess<sal_Int8>(_rValue));
+ break;
+
+ case TypeClass_SHORT:
+ _rxParameters->setShort(_nColumnIndex, *o3tl::forceAccess<sal_Int16>(_rValue));
+ break;
+
+ case TypeClass_CHAR:
+ _rxParameters->setString(_nColumnIndex, OUString(*o3tl::forceAccess<sal_Unicode>(_rValue)));
+ break;
+
+ case TypeClass_UNSIGNED_SHORT:
+ case TypeClass_LONG:
+ {
+ sal_Int32 nValue = 0;
+ OSL_VERIFY( _rValue >>= nValue );
+ _rxParameters->setInt(_nColumnIndex, nValue);
+ break;
+ }
+
+ case TypeClass_FLOAT:
+ _rxParameters->setFloat(_nColumnIndex, *o3tl::forceAccess<float>(_rValue));
+ break;
+
+ case TypeClass_DOUBLE:
+ _rxParameters->setDouble(_nColumnIndex, *o3tl::forceAccess<double>(_rValue));
+ break;
+
+ case TypeClass_SEQUENCE:
+ if (auto s = o3tl::tryAccess<Sequence< sal_Int8 >>(_rValue))
+ {
+ _rxParameters->setBytes(_nColumnIndex, *s);
+ }
+ else
+ bSuccessfullyReRouted = false;
+ break;
+ case TypeClass_STRUCT:
+ if (auto s1 = o3tl::tryAccess<DateTime>(_rValue))
+ _rxParameters->setTimestamp(_nColumnIndex, *s1);
+ else if (auto s2 = o3tl::tryAccess<Date>(_rValue))
+ _rxParameters->setDate(_nColumnIndex, *s2);
+ else if (auto s3 = o3tl::tryAccess<Time>(_rValue))
+ _rxParameters->setTime(_nColumnIndex, *s3);
+ else
+ bSuccessfullyReRouted = false;
+ break;
+
+ case TypeClass_INTERFACE:
+ if (_rValue.getValueType() == cppu::UnoType<XInputStream>::get())
+ {
+ Reference< XInputStream > xStream;
+ _rValue >>= xStream;
+ _rxParameters->setBinaryStream(_nColumnIndex, xStream, xStream->available());
+ break;
+ }
+ [[fallthrough]];
+ default:
+ bSuccessfullyReRouted = false;
+
+ }
+
+ return bSuccessfullyReRouted;
+}
+
+namespace
+{
+ class OParameterWrapper : public ::cppu::WeakImplHelper< XIndexAccess >
+ {
+ std::vector<bool, std::allocator<bool> > m_aSet;
+ Reference<XIndexAccess> m_xSource;
+ public:
+ OParameterWrapper(std::vector<bool, std::allocator<bool> >&& _aSet,const Reference<XIndexAccess>& _xSource)
+ : m_aSet(std::move(_aSet)), m_xSource(_xSource) {}
+ private:
+ // css::container::XElementAccess
+ virtual Type SAL_CALL getElementType() override
+ {
+ return m_xSource->getElementType();
+ }
+ virtual sal_Bool SAL_CALL hasElements( ) override
+ {
+ if ( m_aSet.empty() )
+ return m_xSource->hasElements();
+ return std::count(m_aSet.begin(),m_aSet.end(),false) != 0;
+ }
+ // css::container::XIndexAccess
+ virtual sal_Int32 SAL_CALL getCount( ) override
+ {
+ if ( m_aSet.empty() )
+ return m_xSource->getCount();
+ return std::count(m_aSet.begin(),m_aSet.end(),false);
+ }
+ virtual Any SAL_CALL getByIndex( sal_Int32 Index ) override
+ {
+ if ( m_aSet.empty() )
+ return m_xSource->getByIndex(Index);
+ if ( Index < 0 || m_aSet.size() < o3tl::make_unsigned(Index) )
+ throw IndexOutOfBoundsException();
+
+ std::vector<bool, std::allocator<bool> >::const_iterator aIter = m_aSet.begin();
+ std::vector<bool, std::allocator<bool> >::const_iterator aEnd = m_aSet.end();
+ sal_Int32 i = 0;
+ for(; aIter != aEnd && i <= Index; ++aIter)
+ {
+ if ( !*aIter )
+ {
+ ++i;
+ }
+ }
+ auto nParamPos = static_cast<sal_Int32>(std::distance(m_aSet.cbegin(), aIter)) - 1;
+ return m_xSource->getByIndex(nParamPos);
+ }
+ };
+}
+
+void askForParameters(const Reference< XSingleSelectQueryComposer >& _xComposer,
+ const Reference<XParameters>& _xParameters,
+ const Reference< XConnection>& _xConnection,
+ const Reference< XInteractionHandler >& _rxHandler,
+ const std::vector<bool, std::allocator<bool> >& _aParametersSet)
+{
+ OSL_ENSURE(_xComposer.is(),"dbtools::askForParameters XSQLQueryComposer is null!");
+ OSL_ENSURE(_xParameters.is(),"dbtools::askForParameters XParameters is null!");
+ OSL_ENSURE(_xConnection.is(),"dbtools::askForParameters XConnection is null!");
+ OSL_ENSURE(_rxHandler.is(),"dbtools::askForParameters XInteractionHandler is null!");
+
+ // we have to set this here again because getCurrentSettingsComposer can force a setpropertyvalue
+ Reference<XParametersSupplier> xParameters(_xComposer, UNO_QUERY);
+
+ Reference<XIndexAccess> xParamsAsIndicies = xParameters.is() ? xParameters->getParameters() : Reference<XIndexAccess>();
+ sal_Int32 nParamCount = xParamsAsIndicies.is() ? xParamsAsIndicies->getCount() : 0;
+ std::vector<bool, std::allocator<bool> > aNewParameterSet( _aParametersSet );
+ if ( !(nParamCount && std::count(aNewParameterSet.begin(),aNewParameterSet.end(),true) != nParamCount) )
+ return;
+
+ static const OUString PROPERTY_NAME(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME));
+ aNewParameterSet.resize(nParamCount ,false);
+ typedef std::map< OUString, std::vector<sal_Int32> > TParameterPositions;
+ TParameterPositions aParameterNames;
+ for(sal_Int32 i = 0; i < nParamCount; ++i)
+ {
+ Reference<XPropertySet> xParam(xParamsAsIndicies->getByIndex(i),UNO_QUERY);
+ OUString sName;
+ xParam->getPropertyValue(PROPERTY_NAME) >>= sName;
+
+ TParameterPositions::const_iterator aFind = aParameterNames.find(sName);
+ if ( aFind != aParameterNames.end() )
+ aNewParameterSet[i] = true;
+ aParameterNames[sName].push_back(i+1);
+ }
+ // build an interaction request
+ // two continuations (Ok and Cancel)
+ rtl::Reference<OInteractionAbort> pAbort = new OInteractionAbort;
+ rtl::Reference<OParameterContinuation> pParams = new OParameterContinuation;
+ // the request
+ ParametersRequest aRequest;
+ Reference<XIndexAccess> xWrappedParameters = new OParameterWrapper(std::move(aNewParameterSet),xParamsAsIndicies);
+ aRequest.Parameters = xWrappedParameters;
+ aRequest.Connection = _xConnection;
+ rtl::Reference<OInteractionRequest> pRequest = new OInteractionRequest(Any(aRequest));
+ // some knittings
+ pRequest->addContinuation(pAbort);
+ pRequest->addContinuation(pParams);
+
+ // execute the request
+ _rxHandler->handle(pRequest);
+
+ if (!pParams->wasSelected())
+ {
+ // canceled by the user (i.e. (s)he canceled the dialog)
+ RowSetVetoException e;
+ e.ErrorCode = ParameterInteractionCancelled;
+ throw e;
+ }
+
+ // now transfer the values from the continuation object to the parameter columns
+ Sequence< PropertyValue > aFinalValues = pParams->getValues();
+ const PropertyValue* pFinalValues = aFinalValues.getConstArray();
+ for (sal_Int32 i=0; i<aFinalValues.getLength(); ++i, ++pFinalValues)
+ {
+ Reference< XPropertySet > xParamColumn(xWrappedParameters->getByIndex(i),UNO_QUERY);
+ if (xParamColumn.is())
+ {
+ OUString sName;
+ xParamColumn->getPropertyValue(PROPERTY_NAME) >>= sName;
+ OSL_ENSURE(sName == pFinalValues->Name, "::dbaui::askForParameters: inconsistent parameter names!");
+
+ // determine the field type and ...
+ sal_Int32 nParamType = 0;
+ xParamColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE)) >>= nParamType;
+ // ... the scale of the parameter column
+ sal_Int32 nScale = 0;
+ if (hasProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCALE), xParamColumn))
+ xParamColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCALE)) >>= nScale;
+ // (the index of the parameters is one-based)
+ TParameterPositions::const_iterator aFind = aParameterNames.find(pFinalValues->Name);
+ for(const auto& rItem : aFind->second)
+ {
+ if ( _aParametersSet.empty() || !_aParametersSet[rItem-1] )
+ {
+ _xParameters->setObjectWithInfo(rItem, pFinalValues->Value, nParamType, nScale);
+ }
+ }
+ }
+ }
+}
+
+void setObjectWithInfo(const Reference<XParameters>& _xParams,
+ sal_Int32 parameterIndex,
+ const Any& x,
+ sal_Int32 sqlType,
+ sal_Int32 scale)
+{
+ ORowSetValue aVal;
+ aVal.fill(x);
+ setObjectWithInfo(_xParams,parameterIndex,aVal,sqlType,scale);
+}
+
+void setObjectWithInfo(const Reference<XParameters>& _xParams,
+ sal_Int32 parameterIndex,
+ const ::connectivity::ORowSetValue& _rValue,
+ sal_Int32 sqlType,
+ sal_Int32 scale)
+{
+ if ( _rValue.isNull() )
+ _xParams->setNull(parameterIndex,sqlType);
+ else
+ {
+ switch(sqlType)
+ {
+ case DataType::DECIMAL:
+ case DataType::NUMERIC:
+ _xParams->setObjectWithInfo(parameterIndex,_rValue.makeAny(),sqlType,scale);
+ break;
+ case DataType::CHAR:
+ case DataType::VARCHAR:
+ case DataType::LONGVARCHAR:
+ _xParams->setString(parameterIndex,_rValue.getString());
+ break;
+ case DataType::CLOB:
+ {
+ Any x(_rValue.makeAny());
+ OUString sValue;
+ if ( x >>= sValue )
+ _xParams->setString(parameterIndex,sValue);
+ else
+ {
+ Reference< XClob > xClob;
+ if(x >>= xClob)
+ _xParams->setClob(parameterIndex,xClob);
+ else
+ {
+ Reference< css::io::XInputStream > xStream;
+ if(x >>= xStream)
+ _xParams->setCharacterStream(parameterIndex,xStream,xStream->available());
+ }
+ }
+ }
+ break;
+ case DataType::BIGINT:
+ if ( _rValue.isSigned() )
+ _xParams->setLong(parameterIndex,_rValue.getLong());
+ else
+ _xParams->setString(parameterIndex,_rValue.getString());
+ break;
+
+ case DataType::FLOAT:
+ _xParams->setFloat(parameterIndex,_rValue.getFloat());
+ break;
+ case DataType::REAL:
+ case DataType::DOUBLE:
+ _xParams->setDouble(parameterIndex,_rValue.getDouble());
+ break;
+ case DataType::DATE:
+ _xParams->setDate(parameterIndex,_rValue.getDate());
+ break;
+ case DataType::TIME:
+ _xParams->setTime(parameterIndex,_rValue.getTime());
+ break;
+ case DataType::TIMESTAMP:
+ _xParams->setTimestamp(parameterIndex,_rValue.getDateTime());
+ break;
+ case DataType::BINARY:
+ case DataType::VARBINARY:
+ case DataType::LONGVARBINARY:
+ case DataType::BLOB:
+ {
+ Any x(_rValue.makeAny());
+ Sequence< sal_Int8> aBytes;
+ if(x >>= aBytes)
+ _xParams->setBytes(parameterIndex,aBytes);
+ else
+ {
+ Reference< XBlob > xBlob;
+ if(x >>= xBlob)
+ _xParams->setBlob(parameterIndex,xBlob);
+ else
+ {
+ Reference< XClob > xClob;
+ if(x >>= xClob)
+ _xParams->setClob(parameterIndex,xClob);
+ else
+ {
+ Reference< css::io::XInputStream > xBinStream;
+ if(x >>= xBinStream)
+ _xParams->setBinaryStream(parameterIndex,xBinStream,xBinStream->available());
+ }
+ }
+ }
+ }
+ break;
+ case DataType::BIT:
+ case DataType::BOOLEAN:
+ _xParams->setBoolean(parameterIndex,_rValue.getBool());
+ break;
+ case DataType::TINYINT:
+ if ( _rValue.isSigned() )
+ _xParams->setByte(parameterIndex,_rValue.getInt8());
+ else
+ _xParams->setShort(parameterIndex,_rValue.getInt16());
+ break;
+ case DataType::SMALLINT:
+ if ( _rValue.isSigned() )
+ _xParams->setShort(parameterIndex,_rValue.getInt16());
+ else
+ _xParams->setInt(parameterIndex,_rValue.getInt32());
+ break;
+ case DataType::INTEGER:
+ if ( _rValue.isSigned() )
+ _xParams->setInt(parameterIndex,_rValue.getULong());
+ else
+ _xParams->setLong(parameterIndex,_rValue.getLong());
+ break;
+ default:
+ {
+ ::connectivity::SharedResources aResources;
+ const OUString sError( aResources.getResourceStringWithSubstitution(
+ STR_UNKNOWN_PARA_TYPE,
+ "$position$", OUString::number(parameterIndex)
+ ) );
+ ::dbtools::throwGenericSQLException(sError,nullptr);
+ }
+ }
+ }
+}
+
+void getBooleanComparisonPredicate( std::u16string_view _rExpression, const bool _bValue, const sal_Int32 _nBooleanComparisonMode,
+ OUStringBuffer& _out_rSQLPredicate )
+{
+ switch ( _nBooleanComparisonMode )
+ {
+ case BooleanComparisonMode::IS_LITERAL:
+ _out_rSQLPredicate.append( _rExpression );
+ if ( _bValue )
+ _out_rSQLPredicate.append( " IS TRUE" );
+ else
+ _out_rSQLPredicate.append( " IS FALSE" );
+ break;
+
+ case BooleanComparisonMode::EQUAL_LITERAL:
+ _out_rSQLPredicate.append( _rExpression );
+ _out_rSQLPredicate.appendAscii( _bValue ? " = TRUE" : " = FALSE" );
+ break;
+
+ case BooleanComparisonMode::ACCESS_COMPAT:
+ if ( _bValue )
+ {
+ _out_rSQLPredicate.append( " NOT ( ( " );
+ _out_rSQLPredicate.append( _rExpression );
+ _out_rSQLPredicate.append( " = 0 ) OR ( " );
+ _out_rSQLPredicate.append( _rExpression );
+ _out_rSQLPredicate.append( " IS NULL ) )" );
+ }
+ else
+ {
+ _out_rSQLPredicate.append( _rExpression );
+ _out_rSQLPredicate.append( " = 0" );
+ }
+ break;
+
+ case BooleanComparisonMode::EQUAL_INTEGER:
+ // fall through
+ default:
+ _out_rSQLPredicate.append( _rExpression );
+ _out_rSQLPredicate.appendAscii( _bValue ? " = 1" : " = 0" );
+ break;
+ }
+}
+
+} // namespace dbtools
+
+namespace connectivity
+{
+void checkDisposed(bool _bThrow)
+{
+ if (_bThrow)
+ throw DisposedException();
+
+}
+
+OSQLColumns::const_iterator find(const OSQLColumns::const_iterator& first,
+ const OSQLColumns::const_iterator& last,
+ std::u16string_view _rVal,
+ const ::comphelper::UStringMixEqual& _rCase)
+{
+ OUString sName = OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME);
+ return find(first,last,sName,_rVal,_rCase);
+}
+
+OSQLColumns::const_iterator findRealName(const OSQLColumns::const_iterator& first,
+ const OSQLColumns::const_iterator& last,
+ std::u16string_view _rVal,
+ const ::comphelper::UStringMixEqual& _rCase)
+{
+ OUString sRealName = OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_REALNAME);
+ return find(first,last,sRealName,_rVal,_rCase);
+}
+
+OSQLColumns::const_iterator find(OSQLColumns::const_iterator first,
+ const OSQLColumns::const_iterator& last,
+ const OUString& _rProp,
+ std::u16string_view _rVal,
+ const ::comphelper::UStringMixEqual& _rCase)
+{
+ while (first != last && !_rCase(getString((*first)->getPropertyValue(_rProp)),_rVal))
+ ++first;
+ return first;
+}
+
+namespace dbase
+{
+ bool dbfDecodeCharset(rtl_TextEncoding &_out_encoding, sal_uInt8 nType, sal_uInt8 nCodepage)
+ {
+ switch (nType)
+ {
+ // dBaseIII header doesn't contain language driver ID
+ // See http://dbase.free.fr/tlcharge/structure%20tables.pdf
+ case dBaseIII:
+ case dBaseIIIMemo:
+ break;
+ case dBaseIV:
+ case dBaseV:
+ case VisualFoxPro:
+ case VisualFoxProAuto:
+ case dBaseFS:
+ case dBaseFSMemo:
+ case dBaseIVMemoSQL:
+ case FoxProMemo:
+ {
+ if (nCodepage != 0x00)
+ {
+ auto eEncoding(RTL_TEXTENCODING_DONTKNOW);
+ switch(nCodepage)
+ {
+ case 0x01: eEncoding = RTL_TEXTENCODING_IBM_437; break; // DOS USA code page 437
+ case 0x02: eEncoding = RTL_TEXTENCODING_IBM_850; break; // DOS Multilingual code page 850
+ case 0x03: eEncoding = RTL_TEXTENCODING_MS_1252; break; // Windows ANSI code page 1252
+ case 0x04: eEncoding = RTL_TEXTENCODING_APPLE_ROMAN; break; // Standard Macintosh
+ case 0x64: eEncoding = RTL_TEXTENCODING_IBM_852; break; // EE MS-DOS code page 852
+ case 0x65: eEncoding = RTL_TEXTENCODING_IBM_866; break; // Russian MS-DOS code page 866
+ case 0x66: eEncoding = RTL_TEXTENCODING_IBM_865; break; // Nordic MS-DOS code page 865
+ case 0x67: eEncoding = RTL_TEXTENCODING_IBM_861; break; // Icelandic MS-DOS
+ case 0x68: eEncoding = RTL_TEXTENCODING_KAMENICKY; break; // Kamenicky (Czech) MS-DOS
+ case 0x69: eEncoding = RTL_TEXTENCODING_MAZOVIA; break; // Mazovia (Polish) MS-DOS
+ case 0x6A: eEncoding = RTL_TEXTENCODING_IBM_737; break; // Greek MS-DOS (437G)
+ case 0x6B: eEncoding = RTL_TEXTENCODING_IBM_857; break; // Turkish MS-DOS
+ case 0x6C: eEncoding = RTL_TEXTENCODING_IBM_863; break; // MS-DOS, Canada
+ case 0x78: eEncoding = RTL_TEXTENCODING_MS_950; break; // Windows, Traditional Chinese
+ case 0x79: eEncoding = RTL_TEXTENCODING_MS_949; break; // Windows, Korean (Hangul)
+ case 0x7A: eEncoding = RTL_TEXTENCODING_MS_936; break; // Windows, Simplified Chinese
+ case 0x7B: eEncoding = RTL_TEXTENCODING_MS_932; break; // Windows, Japanese (Shift-jis)
+ case 0x7C: eEncoding = RTL_TEXTENCODING_MS_874; break; // Windows, Thai
+ case 0x7D: eEncoding = RTL_TEXTENCODING_MS_1255; break; // Windows, Hebrew
+ case 0x7E: eEncoding = RTL_TEXTENCODING_MS_1256; break; // Windows, Arabic
+ case 0x96: eEncoding = RTL_TEXTENCODING_APPLE_CYRILLIC; break; // Russian Macintosh
+ case 0x97: eEncoding = RTL_TEXTENCODING_APPLE_CENTEURO; break; // Eastern European Macintosh
+ case 0x98: eEncoding = RTL_TEXTENCODING_APPLE_GREEK; break; // Greek Macintosh
+ case 0xC8: eEncoding = RTL_TEXTENCODING_MS_1250; break; // Windows EE code page 1250
+ case 0xC9: eEncoding = RTL_TEXTENCODING_MS_1251; break; // Russian Windows
+ case 0xCA: eEncoding = RTL_TEXTENCODING_MS_1254; break; // Turkish Windows
+ case 0xCB: eEncoding = RTL_TEXTENCODING_MS_1253; break; // Greek Windows
+ case 0xCC: eEncoding = RTL_TEXTENCODING_MS_1257; break; // Windows, Baltic
+ }
+ if(eEncoding != RTL_TEXTENCODING_DONTKNOW)
+ {
+ _out_encoding = eEncoding;
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ bool dbfReadCharset(rtl_TextEncoding &nCharSet, SvStream* dbf_Stream)
+ {
+ sal_uInt8 nType=0;
+ dbf_Stream->ReadUChar( nType );
+
+ dbf_Stream->Seek(STREAM_SEEK_TO_BEGIN + 29);
+ if (dbf_Stream->eof())
+ {
+ return false;
+ }
+ else
+ {
+ sal_uInt8 nEncoding=0;
+ dbf_Stream->ReadUChar( nEncoding );
+ return dbfDecodeCharset(nCharSet, nType, nEncoding);
+ }
+ }
+
+}
+
+} //namespace connectivity
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/commontools/dbtools2.cxx b/connectivity/source/commontools/dbtools2.cxx
new file mode 100644
index 0000000000..8148b25ddc
--- /dev/null
+++ b/connectivity/source/commontools/dbtools2.cxx
@@ -0,0 +1,1018 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <connectivity/dbtools.hxx>
+#include <connectivity/dbconversion.hxx>
+#include <connectivity/dbcharset.hxx>
+#include <SQLStatementHelper.hxx>
+#include <unotools/confignode.hxx>
+#include <resource/sharedresources.hxx>
+#include <strings.hrc>
+#include <com/sun/star/sdb/XSingleSelectQueryComposer.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <com/sun/star/sdbc/XDataSource.hpp>
+#include <com/sun/star/sdbc/ColumnValue.hpp>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <com/sun/star/sdbc/DriverManager.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
+#include <com/sun/star/sdbcx/XKeysSupplier.hpp>
+#include <com/sun/star/sdbcx/XDataDefinitionSupplier.hpp>
+#include <com/sun/star/sdbcx/Privilege.hpp>
+#include <com/sun/star/container/XIndexAccess.hpp>
+#include <com/sun/star/sdbc/KeyRule.hpp>
+#include <com/sun/star/sdbcx/KeyType.hpp>
+#include <TConnection.hxx>
+#include <connectivity/sdbcx/VColumn.hxx>
+#include <com/sun/star/frame/XModel.hpp>
+#include <com/sun/star/container/XChild.hpp>
+
+#include <comphelper/types.hxx>
+#include <comphelper/diagnose_ex.hxx>
+#include <unotools/sharedunocomponent.hxx>
+#include <algorithm>
+#include <string_view>
+
+namespace dbtools
+{
+
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::beans;
+ using namespace ::com::sun::star::sdb;
+ using namespace ::com::sun::star::sdbc;
+ using namespace ::com::sun::star::sdbcx;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::container;
+ using namespace ::com::sun::star::frame;
+ using namespace connectivity;
+ using namespace comphelper;
+
+OUString createStandardTypePart(const Reference< XPropertySet >& xColProp,const Reference< XConnection>& _xConnection,std::u16string_view _sCreatePattern)
+{
+
+ Reference<XDatabaseMetaData> xMetaData = _xConnection->getMetaData();
+
+ ::dbtools::OPropertyMap& rPropMap = OMetaConnection::getPropMap();
+
+ OUString sTypeName;
+ sal_Int32 nDataType = 0;
+ sal_Int32 nPrecision = 0;
+ sal_Int32 nScale = 0;
+
+ nDataType = nPrecision = nScale = 0;
+
+ xColProp->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_TYPENAME)) >>= sTypeName;
+ xColProp->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_TYPE)) >>= nDataType;
+ xColProp->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_PRECISION)) >>= nPrecision;
+ xColProp->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_SCALE)) >>= nScale;
+
+ OUStringBuffer aSql;
+
+ // check if the user enter a specific string to create autoincrement values
+ OUString sAutoIncrementValue;
+ Reference<XPropertySetInfo> xPropInfo = xColProp->getPropertySetInfo();
+ if ( xPropInfo.is() && xPropInfo->hasPropertyByName(rPropMap.getNameByIndex(PROPERTY_ID_AUTOINCREMENTCREATION)) )
+ xColProp->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_AUTOINCREMENTCREATION)) >>= sAutoIncrementValue;
+ // look if we have to use precisions
+ bool bUseLiteral = false;
+ OUString sPrefix,sPostfix,sCreateParams;
+ {
+ Reference<XResultSet> xRes = xMetaData->getTypeInfo();
+ if(xRes.is())
+ {
+ Reference<XRow> xRow(xRes,UNO_QUERY);
+ while(xRes->next())
+ {
+ OUString sTypeName2Cmp = xRow->getString(1);
+ sal_Int32 nType = xRow->getShort(2);
+ sPrefix = xRow->getString (4);
+ sPostfix = xRow->getString (5);
+ sCreateParams = xRow->getString(6);
+ // first identical type will be used if typename is empty
+ if ( sTypeName.isEmpty() && nType == nDataType )
+ sTypeName = sTypeName2Cmp;
+
+ if( sTypeName.equalsIgnoreAsciiCase(sTypeName2Cmp) && nType == nDataType && !sCreateParams.isEmpty() && !xRow->wasNull())
+ {
+ bUseLiteral = true;
+ break;
+ }
+ }
+ }
+ }
+
+ if ( !sAutoIncrementValue.isEmpty() )
+ {
+ sal_Int32 nIndex = sTypeName.indexOf(sAutoIncrementValue);
+ if (nIndex != -1)
+ sTypeName = sTypeName.replaceAt(nIndex,sTypeName.getLength() - nIndex, u"");
+ }
+
+ if ( (nPrecision > 0 || nScale > 0) && bUseLiteral )
+ {
+ bool bTimed = (nDataType == DataType::TIME ||
+ nDataType == DataType::TIME_WITH_TIMEZONE ||
+ nDataType == DataType::TIMESTAMP ||
+ nDataType == DataType::TIMESTAMP_WITH_TIMEZONE);
+
+ sal_Int32 nParenPos = (nDataType == DataType::TIME_WITH_TIMEZONE ||
+ nDataType == DataType::TIMESTAMP_WITH_TIMEZONE) ?
+ sTypeName.indexOf(' ') :
+ sTypeName.indexOf('(');
+
+ if ( nParenPos == -1 )
+ aSql.append(sTypeName);
+ else
+ aSql.append(sTypeName.subView(0, nParenPos));
+ aSql.append("(");
+
+ if ( nPrecision > 0 && !bTimed )
+ {
+ aSql.append(nPrecision);
+ if ( (nScale > 0) || (!_sCreatePattern.empty() && sCreateParams.indexOf(_sCreatePattern) != -1) )
+ aSql.append(",");
+ }
+ if ( (nScale > 0) || ( !_sCreatePattern.empty() && sCreateParams.indexOf(_sCreatePattern) != -1 ) || bTimed )
+ aSql.append(nScale);
+
+ if ( nParenPos == -1 )
+ aSql.append(")");
+ else
+ {
+ if ( bTimed )
+ aSql.append(")");
+ else
+ nParenPos = sTypeName.indexOf(')',nParenPos);
+ aSql.append(sTypeName.subView(nParenPos));
+ }
+ }
+ else
+ aSql.append(sTypeName); // simply add the type name
+
+ OUString aDefault = ::comphelper::getString(xColProp->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_DEFAULTVALUE)));
+ if ( !aDefault.isEmpty() )
+ {
+ aSql.append(" DEFAULT " + sPrefix + aDefault + sPostfix);
+ } // if ( aDefault.getLength() )
+
+ return aSql.makeStringAndClear();
+}
+
+OUString createStandardColumnPart(const Reference< XPropertySet >& xColProp,const Reference< XConnection>& _xConnection,ISQLStatementHelper* _pHelper,std::u16string_view _sCreatePattern)
+{
+ Reference<XDatabaseMetaData> xMetaData = _xConnection->getMetaData();
+
+ ::dbtools::OPropertyMap& rPropMap = OMetaConnection::getPropMap();
+
+ bool bIsAutoIncrement = false;
+ xColProp->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_ISAUTOINCREMENT)) >>= bIsAutoIncrement;
+
+ const OUString sQuoteString = xMetaData->getIdentifierQuoteString();
+ OUStringBuffer aSql(::dbtools::quoteName(sQuoteString,::comphelper::getString(xColProp->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_NAME)))));
+
+ // check if the user enter a specific string to create autoincrement values
+ OUString sAutoIncrementValue;
+ Reference<XPropertySetInfo> xPropInfo = xColProp->getPropertySetInfo();
+ if ( xPropInfo.is() && xPropInfo->hasPropertyByName(rPropMap.getNameByIndex(PROPERTY_ID_AUTOINCREMENTCREATION)) )
+ xColProp->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_AUTOINCREMENTCREATION)) >>= sAutoIncrementValue;
+
+ aSql.append(" " + createStandardTypePart(xColProp, _xConnection, _sCreatePattern));
+
+ if(::comphelper::getINT32(xColProp->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_ISNULLABLE))) == ColumnValue::NO_NULLS)
+ aSql.append(" NOT NULL");
+
+ if ( bIsAutoIncrement && !sAutoIncrementValue.isEmpty())
+ {
+ aSql.append(" " + sAutoIncrementValue);
+ }
+
+ if ( _pHelper )
+ _pHelper->addComment(xColProp,aSql);
+
+ return aSql.makeStringAndClear();
+}
+
+
+OUString createStandardCreateStatement(const Reference< XPropertySet >& descriptor,const Reference< XConnection>& _xConnection,ISQLStatementHelper* _pHelper,std::u16string_view _sCreatePattern)
+{
+ OUStringBuffer aSql("CREATE TABLE ");
+ OUString sCatalog,sSchema,sTable,sComposedName;
+
+ Reference<XDatabaseMetaData> xMetaData = _xConnection->getMetaData();
+ ::dbtools::OPropertyMap& rPropMap = OMetaConnection::getPropMap();
+
+ descriptor->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_CATALOGNAME)) >>= sCatalog;
+ descriptor->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_SCHEMANAME)) >>= sSchema;
+ descriptor->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_NAME)) >>= sTable;
+
+ sComposedName = ::dbtools::composeTableName( xMetaData, sCatalog, sSchema, sTable, true, ::dbtools::EComposeRule::InTableDefinitions );
+ if ( sComposedName.isEmpty() )
+ ::dbtools::throwFunctionSequenceException(_xConnection);
+
+ aSql.append(sComposedName + " (");
+
+ // columns
+ Reference<XColumnsSupplier> xColumnSup(descriptor,UNO_QUERY);
+ Reference<XIndexAccess> xColumns(xColumnSup->getColumns(),UNO_QUERY);
+ // check if there are columns
+ if(!xColumns.is() || !xColumns->getCount())
+ ::dbtools::throwFunctionSequenceException(_xConnection);
+
+ Reference< XPropertySet > xColProp;
+
+ sal_Int32 nCount = xColumns->getCount();
+ for(sal_Int32 i=0;i<nCount;++i)
+ {
+ if ( (xColumns->getByIndex(i) >>= xColProp) && xColProp.is() )
+ {
+ aSql.append(
+ createStandardColumnPart(xColProp,_xConnection,_pHelper,_sCreatePattern)
+ + ",");
+ }
+ }
+ return aSql.makeStringAndClear();
+}
+namespace
+{
+ OUString generateColumnNames(const Reference<XIndexAccess>& _xColumns,const Reference<XDatabaseMetaData>& _xMetaData)
+ {
+ ::dbtools::OPropertyMap& rPropMap = OMetaConnection::getPropMap();
+
+ const OUString sQuote(_xMetaData->getIdentifierQuoteString());
+ OUStringBuffer sSql( " (" );
+ Reference< XPropertySet > xColProp;
+
+ sal_Int32 nColCount = _xColumns->getCount();
+ for(sal_Int32 i=0;i<nColCount;++i)
+ {
+ if ( (_xColumns->getByIndex(i) >>= xColProp) && xColProp.is() )
+ sSql.append( ::dbtools::quoteName(sQuote,::comphelper::getString(xColProp->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_NAME)))) +
+ ",");
+ }
+
+ if ( nColCount )
+ sSql[sSql.getLength()-1] = ')';
+ return sSql.makeStringAndClear();
+ }
+}
+
+OUString createStandardKeyStatement(const Reference< XPropertySet >& descriptor,const Reference< XConnection>& _xConnection)
+{
+ Reference<XDatabaseMetaData> xMetaData = _xConnection->getMetaData();
+ ::dbtools::OPropertyMap& rPropMap = OMetaConnection::getPropMap();
+
+ OUStringBuffer aSql;
+ // keys
+ Reference<XKeysSupplier> xKeySup(descriptor,UNO_QUERY);
+ Reference<XIndexAccess> xKeys = xKeySup->getKeys();
+ if ( xKeys.is() )
+ {
+ Reference< XPropertySet > xColProp;
+ Reference<XIndexAccess> xColumns;
+ Reference<XColumnsSupplier> xColumnSup;
+ OUString sCatalog,sSchema,sTable,sComposedName;
+ bool bPKey = false;
+ for(sal_Int32 i=0;i<xKeys->getCount();++i)
+ {
+ if ( (xKeys->getByIndex(i) >>= xColProp) && xColProp.is() )
+ {
+
+ sal_Int32 nKeyType = ::comphelper::getINT32(xColProp->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_TYPE)));
+
+ if ( nKeyType == KeyType::PRIMARY )
+ {
+ if(bPKey)
+ ::dbtools::throwFunctionSequenceException(_xConnection);
+
+ bPKey = true;
+ xColumnSup.set(xColProp,UNO_QUERY);
+ xColumns.set(xColumnSup->getColumns(),UNO_QUERY);
+ if(!xColumns.is() || !xColumns->getCount())
+ ::dbtools::throwFunctionSequenceException(_xConnection);
+
+ aSql.append(" PRIMARY KEY " + generateColumnNames(xColumns,xMetaData));
+ }
+ else if(nKeyType == KeyType::UNIQUE)
+ {
+ xColumnSup.set(xColProp,UNO_QUERY);
+ xColumns.set(xColumnSup->getColumns(),UNO_QUERY);
+ if(!xColumns.is() || !xColumns->getCount())
+ ::dbtools::throwFunctionSequenceException(_xConnection);
+
+ aSql.append(" UNIQUE " + generateColumnNames(xColumns,xMetaData));
+ }
+ else if(nKeyType == KeyType::FOREIGN)
+ {
+ sal_Int32 nDeleteRule = getINT32(xColProp->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_DELETERULE)));
+
+ xColumnSup.set(xColProp,UNO_QUERY);
+ xColumns.set(xColumnSup->getColumns(),UNO_QUERY);
+ if(!xColumns.is() || !xColumns->getCount())
+ ::dbtools::throwFunctionSequenceException(_xConnection);
+
+ aSql.append(" FOREIGN KEY ");
+ OUString sRefTable = getString(xColProp->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_REFERENCEDTABLE)));
+ ::dbtools::qualifiedNameComponents(xMetaData,
+ sRefTable,
+ sCatalog,
+ sSchema,
+ sTable,
+ ::dbtools::EComposeRule::InDataManipulation);
+ sComposedName = ::dbtools::composeTableName( xMetaData, sCatalog, sSchema, sTable, true, ::dbtools::EComposeRule::InTableDefinitions );
+
+
+ if ( sComposedName.isEmpty() )
+ ::dbtools::throwFunctionSequenceException(_xConnection);
+
+ aSql.append(generateColumnNames(xColumns,xMetaData));
+
+ switch(nDeleteRule)
+ {
+ case KeyRule::CASCADE:
+ aSql.append(" ON DELETE CASCADE ");
+ break;
+ case KeyRule::RESTRICT:
+ aSql.append(" ON DELETE RESTRICT ");
+ break;
+ case KeyRule::SET_NULL:
+ aSql.append(" ON DELETE SET NULL ");
+ break;
+ case KeyRule::SET_DEFAULT:
+ aSql.append(" ON DELETE SET DEFAULT ");
+ break;
+ default:
+ ;
+ }
+ }
+ }
+ }
+ }
+
+ if ( !aSql.isEmpty() )
+ {
+ if ( aSql[aSql.getLength() - 1] == ',' )
+ aSql[aSql.getLength() - 1] = ')';
+ else
+ aSql.append(")");
+ }
+
+ return aSql.makeStringAndClear();
+
+}
+
+OUString createSqlCreateTableStatement( const Reference< XPropertySet >& descriptor,
+ const Reference< XConnection>& _xConnection)
+{
+ OUString aSql = ::dbtools::createStandardCreateStatement(descriptor,_xConnection,nullptr,{});
+ const OUString sKeyStmt = ::dbtools::createStandardKeyStatement(descriptor,_xConnection);
+ if ( !sKeyStmt.isEmpty() )
+ aSql += sKeyStmt;
+ else
+ {
+ if ( aSql.endsWith(",") )
+ aSql = aSql.replaceAt(aSql.getLength()-1, 1, u")");
+ else
+ aSql += ")";
+ }
+ return aSql;
+}
+namespace
+{
+ Reference<XPropertySet> lcl_createSDBCXColumn(const Reference<XNameAccess>& _xPrimaryKeyColumns,
+ const Reference<XConnection>& _xConnection,
+ const Any& _aCatalog,
+ const OUString& _aSchema,
+ const OUString& _aTable,
+ const OUString& _rQueryName,
+ const OUString& _rName,
+ bool _bCase,
+ bool _bQueryForInfo,
+ bool _bIsAutoIncrement,
+ bool _bIsCurrency,
+ sal_Int32 _nDataType)
+ {
+ Reference<XPropertySet> xProp;
+ Reference<XDatabaseMetaData> xMetaData = _xConnection->getMetaData();
+ Reference< XResultSet > xResult = xMetaData->getColumns(_aCatalog, _aSchema, _aTable, _rQueryName);
+ OUString sCatalog;
+ _aCatalog >>= sCatalog;
+
+ if ( xResult.is() )
+ {
+ UStringMixEqual aMixCompare(_bCase);
+ Reference< XRow > xRow(xResult,UNO_QUERY);
+ while( xResult->next() )
+ {
+ if ( aMixCompare(xRow->getString(4),_rName) )
+ {
+ sal_Int32 nField5 = xRow->getInt(5);
+ OUString aField6 = xRow->getString(6);
+ sal_Int32 nField7 = xRow->getInt(7)
+ , nField9 = xRow->getInt(9)
+ , nField11= xRow->getInt(11);
+ OUString sField12 = xRow->getString(12),
+ sField13 = xRow->getString(13);
+ ::comphelper::disposeComponent(xRow);
+
+ bool bAutoIncrement = _bIsAutoIncrement
+ ,bIsCurrency = _bIsCurrency;
+ if ( _bQueryForInfo )
+ {
+ const OUString sQuote = xMetaData->getIdentifierQuoteString();
+ OUString sQuotedName = ::dbtools::quoteName(sQuote,_rName);
+ OUString sComposedName = composeTableNameForSelect(_xConnection, getString( _aCatalog ), _aSchema, _aTable );
+
+ ColumnInformationMap aInfo(_bCase);
+ collectColumnInformation(_xConnection,sComposedName,sQuotedName,aInfo);
+ ColumnInformationMap::const_iterator aIter = aInfo.begin();
+ if ( aIter != aInfo.end() )
+ {
+ bAutoIncrement = aIter->second.first.first;
+ bIsCurrency = aIter->second.first.second;
+ if ( DataType::OTHER == nField5 )
+ nField5 = aIter->second.second;
+ }
+ }
+ else if ( DataType::OTHER == nField5 )
+ nField5 = _nDataType;
+
+ if ( nField11 != ColumnValue::NO_NULLS )
+ {
+ try
+ {
+ if ( _xPrimaryKeyColumns.is() )
+ {
+ if ( _xPrimaryKeyColumns->hasByName(_rName) )
+ nField11 = ColumnValue::NO_NULLS;
+
+ }
+ else
+ {
+ Reference< XResultSet > xPKeys = xMetaData->getPrimaryKeys( _aCatalog, _aSchema, _aTable );
+ Reference< XRow > xPKeyRow( xPKeys, UNO_QUERY_THROW );
+ while( xPKeys->next() ) // there can be only one primary key
+ {
+ OUString sKeyColumn = xPKeyRow->getString(4);
+ if ( aMixCompare(_rName,sKeyColumn) )
+ {
+ nField11 = ColumnValue::NO_NULLS;
+ break;
+ }
+ }
+ }
+ }
+ catch(SQLException&)
+ {
+ TOOLS_WARN_EXCEPTION( "connectivity.commontools", "lcl_createSDBCXColumn" );
+ }
+ }
+
+ xProp = new connectivity::sdbcx::OColumn(_rName,
+ aField6,
+ sField13,
+ sField12,
+ nField11,
+ nField7,
+ nField9,
+ nField5,
+ bAutoIncrement,
+ false,
+ bIsCurrency,
+ _bCase,
+ sCatalog,
+ _aSchema,
+ _aTable);
+
+ break;
+ }
+ }
+ }
+
+ return xProp;
+ }
+
+ Reference< XModel> lcl_getXModel(const Reference< XInterface>& _xIface)
+ {
+ Reference< XInterface > xParent = _xIface;
+ Reference< XModel > xModel(xParent,UNO_QUERY);
+ while( xParent.is() && !xModel.is() )
+ {
+ Reference<XChild> xChild(xParent,UNO_QUERY);
+ xParent.set(xChild.is() ? xChild->getParent() : Reference< XInterface >(),UNO_QUERY);
+ xModel.set(xParent,UNO_QUERY);
+ }
+ return xModel;
+ }
+}
+
+Reference<XPropertySet> createSDBCXColumn(const Reference<XPropertySet>& _xTable,
+ const Reference<XConnection>& _xConnection,
+ const OUString& _rName,
+ bool _bCase,
+ bool _bQueryForInfo,
+ bool _bIsAutoIncrement,
+ bool _bIsCurrency,
+ sal_Int32 _nDataType)
+{
+ Reference<XPropertySet> xProp;
+ OSL_ENSURE(_xTable.is(),"Table is NULL!");
+ if ( !_xTable.is() )
+ return xProp;
+
+ ::dbtools::OPropertyMap& rPropMap = OMetaConnection::getPropMap();
+ Any aCatalog = _xTable->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_CATALOGNAME));
+ OUString sCatalog;
+ aCatalog >>= sCatalog;
+
+ OUString aSchema, aTable;
+ _xTable->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_SCHEMANAME)) >>= aSchema;
+ _xTable->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_NAME)) >>= aTable;
+
+ Reference<XNameAccess> xPrimaryKeyColumns = getPrimaryKeyColumns_throw(_xTable);
+
+ xProp = lcl_createSDBCXColumn(xPrimaryKeyColumns,_xConnection,aCatalog, aSchema, aTable, _rName,_rName,_bCase,_bQueryForInfo,_bIsAutoIncrement,_bIsCurrency,_nDataType);
+ if ( !xProp.is() )
+ {
+ xProp = lcl_createSDBCXColumn(xPrimaryKeyColumns,_xConnection,aCatalog, aSchema, aTable, "%",_rName,_bCase,_bQueryForInfo,_bIsAutoIncrement,_bIsCurrency,_nDataType);
+ if ( !xProp.is() )
+ xProp = new connectivity::sdbcx::OColumn(_rName,
+ OUString(),OUString(),OUString(),
+ ColumnValue::NULLABLE_UNKNOWN,
+ 0,
+ 0,
+ DataType::VARCHAR,
+ _bIsAutoIncrement,
+ false,
+ _bIsCurrency,
+ _bCase,
+ sCatalog,
+ aSchema,
+ aTable);
+
+ }
+
+ return xProp;
+}
+
+
+bool getBooleanDataSourceSetting( const Reference< XConnection >& _rxConnection, const char* _pAsciiSettingName )
+{
+ return getBooleanDataSourceSetting(_rxConnection, OUString::createFromAscii( _pAsciiSettingName ));
+}
+
+bool getBooleanDataSourceSetting( const Reference< XConnection >& _rxConnection, const OUString & rSettingName )
+{
+ bool bValue( false );
+ try
+ {
+ Reference< XPropertySet> xDataSourceProperties( findDataSource( _rxConnection ), UNO_QUERY );
+ OSL_ENSURE( xDataSourceProperties.is(), "::dbtools::getBooleanDataSourceSetting: somebody is using this with a non-SDB-level connection!" );
+ if ( xDataSourceProperties.is() )
+ {
+ Reference< XPropertySet > xSettings(
+ xDataSourceProperties->getPropertyValue("Settings"),
+ UNO_QUERY_THROW
+ );
+ OSL_VERIFY( xSettings->getPropertyValue( rSettingName ) >>= bValue );
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("connectivity.commontools");
+ }
+ return bValue;
+}
+
+bool getDataSourceSetting( const Reference< XInterface >& _xChild, const OUString& _sAsciiSettingsName,
+ Any& /* [out] */ _rSettingsValue )
+{
+ bool bIsPresent = false;
+ try
+ {
+ const Reference< XPropertySet> xDataSourceProperties( findDataSource( _xChild ), UNO_QUERY );
+ if ( !xDataSourceProperties.is() )
+ return false;
+
+ const Reference< XPropertySet > xSettings(
+ xDataSourceProperties->getPropertyValue("Settings"),
+ UNO_QUERY_THROW
+ );
+
+ _rSettingsValue = xSettings->getPropertyValue( _sAsciiSettingsName );
+ bIsPresent = true;
+ }
+ catch( const Exception& )
+ {
+ bIsPresent = false;
+ }
+ return bIsPresent;
+}
+
+bool getDataSourceSetting( const Reference< XInterface >& _rxDataSource, const char* _pAsciiSettingsName,
+ Any& /* [out] */ _rSettingsValue )
+{
+ OUString sAsciiSettingsName = OUString::createFromAscii(_pAsciiSettingsName);
+ return getDataSourceSetting( _rxDataSource, sAsciiSettingsName,_rSettingsValue );
+}
+
+bool isDataSourcePropertyEnabled(const Reference<XInterface>& _xProp, const OUString& _sProperty, bool _bDefault)
+{
+ bool bEnabled = _bDefault;
+ try
+ {
+ Reference< XPropertySet> xProp(findDataSource(_xProp),UNO_QUERY);
+ if ( xProp.is() )
+ {
+ Sequence< PropertyValue > aInfo;
+ xProp->getPropertyValue("Info") >>= aInfo;
+ const PropertyValue* pValue =std::find_if(std::cbegin(aInfo),
+ std::cend(aInfo),
+ [&_sProperty](const PropertyValue& lhs)
+ { return lhs.Name == _sProperty; });
+ if ( pValue != std::cend(aInfo) )
+ pValue->Value >>= bEnabled;
+ }
+ }
+ catch(SQLException&)
+ {
+ DBG_UNHANDLED_EXCEPTION("connectivity.commontools");
+ }
+ return bEnabled;
+}
+
+Reference< XTablesSupplier> getDataDefinitionByURLAndConnection(
+ const OUString& _rsUrl,
+ const Reference< XConnection>& _xConnection,
+ const Reference< XComponentContext >& _rxContext)
+{
+ Reference< XTablesSupplier> xTablesSup;
+ try
+ {
+ Reference< XDriverManager2 > xManager = DriverManager::create( _rxContext );
+ Reference< XDataDefinitionSupplier > xSupp( xManager->getDriverByURL( _rsUrl ), UNO_QUERY );
+
+ if ( xSupp.is() )
+ {
+ xTablesSup = xSupp->getDataDefinitionByConnection( _xConnection );
+ OSL_ENSURE(xTablesSup.is(),"No table supplier!");
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("connectivity.commontools");
+ }
+ return xTablesSup;
+}
+
+
+sal_Int32 getTablePrivileges(const Reference< XDatabaseMetaData>& _xMetaData,
+ const OUString& _sCatalog,
+ const OUString& _sSchema,
+ const OUString& _sTable)
+{
+ OSL_ENSURE(_xMetaData.is(),"Invalid metadata!");
+ sal_Int32 nPrivileges = 0;
+ try
+ {
+ Any aVal;
+ if(!_sCatalog.isEmpty())
+ aVal <<= _sCatalog;
+ Reference< XResultSet > xPrivileges = _xMetaData->getTablePrivileges(aVal, _sSchema, _sTable);
+ Reference< XRow > xCurrentRow(xPrivileges, UNO_QUERY);
+
+ const OUString sUserWorkingFor = _xMetaData->getUserName();
+ static const char sSELECT[] = "SELECT";
+ static const char sINSERT[] = "INSERT";
+ static const char sUPDATE[] = "UPDATE";
+ static const char sDELETE[] = "DELETE";
+ static const char sREAD[] = "READ";
+ static const char sCREATE[] = "CREATE";
+ static const char sALTER[] = "ALTER";
+ static const char sREFERENCE[] = "REFERENCE";
+ static const char sDROP[] = "DROP";
+
+ if ( xCurrentRow.is() )
+ {
+ // after creation the set is positioned before the first record, per definition
+ OUString sPrivilege, sGrantee;
+ while ( xPrivileges->next() )
+ {
+ sGrantee = xCurrentRow->getString(5);
+ sPrivilege = xCurrentRow->getString(6);
+
+ if (!sUserWorkingFor.equalsIgnoreAsciiCase(sGrantee))
+ continue;
+
+ if (sPrivilege.equalsIgnoreAsciiCase(sSELECT))
+ nPrivileges |= Privilege::SELECT;
+ else if (sPrivilege.equalsIgnoreAsciiCase(sINSERT))
+ nPrivileges |= Privilege::INSERT;
+ else if (sPrivilege.equalsIgnoreAsciiCase(sUPDATE))
+ nPrivileges |= Privilege::UPDATE;
+ else if (sPrivilege.equalsIgnoreAsciiCase(sDELETE))
+ nPrivileges |= Privilege::DELETE;
+ else if (sPrivilege.equalsIgnoreAsciiCase(sREAD))
+ nPrivileges |= Privilege::READ;
+ else if (sPrivilege.equalsIgnoreAsciiCase(sCREATE))
+ nPrivileges |= Privilege::CREATE;
+ else if (sPrivilege.equalsIgnoreAsciiCase(sALTER))
+ nPrivileges |= Privilege::ALTER;
+ else if (sPrivilege.equalsIgnoreAsciiCase(sREFERENCE))
+ nPrivileges |= Privilege::REFERENCE;
+ else if (sPrivilege.equalsIgnoreAsciiCase(sDROP))
+ nPrivileges |= Privilege::DROP;
+ }
+ }
+ disposeComponent(xPrivileges);
+
+ // Some drivers put a table privilege as soon as any column has the privilege,
+ // some drivers only if all columns have the privilege.
+ // To unify the situation, collect column privileges here, too.
+ Reference< XResultSet > xColumnPrivileges = _xMetaData->getColumnPrivileges(aVal, _sSchema, _sTable, "%");
+ Reference< XRow > xColumnCurrentRow(xColumnPrivileges, UNO_QUERY);
+ if ( xColumnCurrentRow.is() )
+ {
+ // after creation the set is positioned before the first record, per definition
+ OUString sPrivilege, sGrantee;
+ while ( xColumnPrivileges->next() )
+ {
+ sGrantee = xColumnCurrentRow->getString(6);
+ sPrivilege = xColumnCurrentRow->getString(7);
+
+ if (!sUserWorkingFor.equalsIgnoreAsciiCase(sGrantee))
+ continue;
+
+ if (sPrivilege.equalsIgnoreAsciiCase(sSELECT))
+ nPrivileges |= Privilege::SELECT;
+ else if (sPrivilege.equalsIgnoreAsciiCase(sINSERT))
+ nPrivileges |= Privilege::INSERT;
+ else if (sPrivilege.equalsIgnoreAsciiCase(sUPDATE))
+ nPrivileges |= Privilege::UPDATE;
+ else if (sPrivilege.equalsIgnoreAsciiCase(sDELETE))
+ nPrivileges |= Privilege::DELETE;
+ else if (sPrivilege.equalsIgnoreAsciiCase(sREAD))
+ nPrivileges |= Privilege::READ;
+ else if (sPrivilege.equalsIgnoreAsciiCase(sCREATE))
+ nPrivileges |= Privilege::CREATE;
+ else if (sPrivilege.equalsIgnoreAsciiCase(sALTER))
+ nPrivileges |= Privilege::ALTER;
+ else if (sPrivilege.equalsIgnoreAsciiCase(sREFERENCE))
+ nPrivileges |= Privilege::REFERENCE;
+ else if (sPrivilege.equalsIgnoreAsciiCase(sDROP))
+ nPrivileges |= Privilege::DROP;
+ }
+ }
+ disposeComponent(xColumnPrivileges);
+ }
+ catch(const SQLException& e)
+ {
+ // some drivers don't support any privileges so we assume that we are allowed to do all we want :-)
+ if(e.SQLState == "IM001")
+ nPrivileges |= Privilege::DROP |
+ Privilege::REFERENCE |
+ Privilege::ALTER |
+ Privilege::CREATE |
+ Privilege::READ |
+ Privilege::DELETE |
+ Privilege::UPDATE |
+ Privilege::INSERT |
+ Privilege::SELECT;
+ else
+ OSL_FAIL("Could not collect the privileges !");
+ }
+ return nPrivileges;
+}
+
+// we need some more information about the column
+void collectColumnInformation(const Reference< XConnection>& _xConnection,
+ std::u16string_view _sComposedName,
+ std::u16string_view _rName,
+ ColumnInformationMap& _rInfo)
+{
+ OUString sSelect = OUString::Concat("SELECT ") + _rName +
+ " FROM " + _sComposedName +
+ " WHERE 0 = 1";
+
+ try
+ {
+ ::utl::SharedUNOComponent< XStatement > xStmt( _xConnection->createStatement() );
+ Reference< XPropertySet > xStatementProps( xStmt, UNO_QUERY_THROW );
+ xStatementProps->setPropertyValue( OMetaConnection::getPropMap().getNameByIndex( PROPERTY_ID_ESCAPEPROCESSING ), Any( false ) );
+ Reference< XResultSet > xResult( xStmt->executeQuery( sSelect ), UNO_SET_THROW );
+ Reference< XResultSetMetaDataSupplier > xSuppMeta( xResult, UNO_QUERY_THROW );
+ Reference< XResultSetMetaData > xMeta( xSuppMeta->getMetaData(), UNO_SET_THROW );
+
+ sal_Int32 nCount = xMeta->getColumnCount();
+ OSL_ENSURE( nCount != 0, "::dbtools::collectColumnInformation: result set has empty (column-less) meta data!" );
+ for (sal_Int32 i=1; i <= nCount ; ++i)
+ {
+ _rInfo.emplace( xMeta->getColumnName(i),
+ ColumnInformation(TBoolPair(xMeta->isAutoIncrement(i),xMeta->isCurrency(i)),xMeta->getColumnType(i)));
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("connectivity.commontools");
+ }
+}
+
+
+bool isEmbeddedInDatabase( const Reference< XInterface >& _rxComponent, Reference< XConnection >& _rxActualConnection )
+{
+ bool bIsEmbedded = false;
+ try
+ {
+ Reference< XModel > xModel = lcl_getXModel( _rxComponent );
+
+ if ( xModel.is() )
+ {
+ Sequence< PropertyValue > aArgs = xModel->getArgs();
+ const PropertyValue* pIter = aArgs.getConstArray();
+ const PropertyValue* pEnd = pIter + aArgs.getLength();
+ for(;pIter != pEnd;++pIter)
+ {
+ if ( pIter->Name == "ComponentData" )
+ {
+ Sequence<PropertyValue> aDocumentContext;
+ pIter->Value >>= aDocumentContext;
+ const PropertyValue* pContextIter = aDocumentContext.getConstArray();
+ const PropertyValue* pContextEnd = pContextIter + aDocumentContext.getLength();
+ for(;pContextIter != pContextEnd;++pContextIter)
+ {
+ if ( pContextIter->Name == "ActiveConnection"
+ && ( pContextIter->Value >>= _rxActualConnection )
+ )
+ {
+ bIsEmbedded = true;
+ break;
+ }
+ }
+ break;
+ }
+ }
+ }
+ }
+ catch(Exception&)
+ {
+ // not interested in
+ }
+ return bIsEmbedded;
+}
+
+namespace
+{
+ OUString lcl_getEncodingName( rtl_TextEncoding _eEncoding )
+ {
+ OUString sEncodingName;
+
+ OCharsetMap aCharsets;
+ OCharsetMap::CharsetIterator aEncodingPos = aCharsets.find( _eEncoding );
+ OSL_ENSURE( aEncodingPos != aCharsets.end(), "lcl_getEncodingName: *which* encoding?" );
+ if ( aEncodingPos != aCharsets.end() )
+ sEncodingName = (*aEncodingPos).getIanaName();
+
+ return sEncodingName;
+ }
+}
+
+
+sal_Int32 DBTypeConversion::convertUnicodeString( const OUString& _rSource, OString& _rDest, rtl_TextEncoding _eEncoding )
+{
+ if ( !rtl_convertUStringToString( &_rDest.pData, _rSource.getStr(), _rSource.getLength(),
+ _eEncoding,
+ RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR |
+ RTL_UNICODETOTEXT_FLAGS_UNDEFINED_REPLACE |
+ RTL_UNICODETOTEXT_FLAGS_PRIVATE_MAPTO0 )
+ )
+ {
+ SharedResources aResources;
+ OUString sMessage = aResources.getResourceStringWithSubstitution( STR_CANNOT_CONVERT_STRING,
+ "$string$", _rSource,
+ "$charset$", lcl_getEncodingName( _eEncoding )
+ );
+
+ throw SQLException(
+ sMessage,
+ nullptr,
+ "22018",
+ 22018,
+ Any()
+ );
+ }
+
+ return _rDest.getLength();
+}
+
+
+sal_Int32 DBTypeConversion::convertUnicodeStringToLength( const OUString& _rSource, OString& _rDest,
+ sal_Int32 _nMaxLen, rtl_TextEncoding _eEncoding )
+{
+ sal_Int32 nLen = convertUnicodeString( _rSource, _rDest, _eEncoding );
+ if ( nLen > _nMaxLen )
+ {
+ SharedResources aResources;
+ OUString sMessage = aResources.getResourceStringWithSubstitution( STR_STRING_LENGTH_EXCEEDED,
+ "$string$", _rSource,
+ "$maxlen$", OUString::number( _nMaxLen ),
+ "$charset$", lcl_getEncodingName( _eEncoding )
+ );
+
+ throw SQLException(
+ sMessage,
+ nullptr,
+ "22001",
+ 22001,
+ Any()
+ );
+ }
+
+ return nLen;
+}
+
+OUString getDefaultReportEngineServiceName(const Reference< XComponentContext >& _rxORB)
+{
+ ::utl::OConfigurationTreeRoot aReportEngines = ::utl::OConfigurationTreeRoot::createWithComponentContext(
+ _rxORB, "org.openoffice.Office.DataAccess/ReportEngines", -1, ::utl::OConfigurationTreeRoot::CM_READONLY);
+
+ if ( aReportEngines.isValid() )
+ {
+ OUString sDefaultReportEngineName;
+ aReportEngines.getNodeValue("DefaultReportEngine") >>= sDefaultReportEngineName;
+ if ( !sDefaultReportEngineName.isEmpty() )
+ {
+ ::utl::OConfigurationNode aReportEngineNames = aReportEngines.openNode("ReportEngineNames");
+ if ( aReportEngineNames.isValid() )
+ {
+ ::utl::OConfigurationNode aReportEngine = aReportEngineNames.openNode(sDefaultReportEngineName);
+ if ( aReportEngine.isValid() )
+ {
+ OUString sRet;
+ aReportEngine.getNodeValue("ServiceName") >>= sRet;
+ return sRet;
+ }
+ }
+ }
+ else
+ return "org.libreoffice.report.pentaho.SOReportJobFactory";
+ }
+ else
+ return "org.libreoffice.report.pentaho.SOReportJobFactory";
+ return OUString();
+}
+
+bool isAggregateColumn(const Reference< XSingleSelectQueryComposer > &_xParser, const Reference< XPropertySet > &_xField)
+{
+ OUString sName;
+ _xField->getPropertyValue("Name") >>= sName;
+ Reference< XColumnsSupplier > xColumnsSupplier(_xParser, UNO_QUERY);
+ Reference< css::container::XNameAccess > xCols;
+ if (xColumnsSupplier.is())
+ xCols = xColumnsSupplier->getColumns();
+
+ return isAggregateColumn(xCols, sName);
+}
+
+bool isAggregateColumn(const Reference< XNameAccess > &_xColumns, const OUString &_sName)
+{
+ if ( _xColumns.is() && _xColumns->hasByName(_sName) )
+ {
+ Reference<XPropertySet> xProp(_xColumns->getByName(_sName),UNO_QUERY);
+ assert(xProp.is());
+ return isAggregateColumn( xProp );
+ }
+ return false;
+}
+
+bool isAggregateColumn( const Reference< XPropertySet > &_xColumn )
+{
+ bool bAgg(false);
+
+ static constexpr OUString sAgg = u"AggregateFunction"_ustr;
+ if ( _xColumn->getPropertySetInfo()->hasPropertyByName(sAgg) )
+ _xColumn->getPropertyValue(sAgg) >>= bAgg;
+
+ return bAgg;
+}
+
+
+} // namespace dbtools
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/commontools/filtermanager.cxx b/connectivity/source/commontools/filtermanager.cxx
new file mode 100644
index 0000000000..0a6ac9018f
--- /dev/null
+++ b/connectivity/source/commontools/filtermanager.cxx
@@ -0,0 +1,254 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <connectivity/filtermanager.hxx>
+
+#include <com/sun/star/sdb/XSQLQueryComposerFactory.hpp>
+#include <TConnection.hxx>
+#include <osl/diagnose.h>
+#include <comphelper/diagnose_ex.hxx>
+#include <rtl/ustrbuf.hxx>
+
+
+namespace dbtools
+{
+
+
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::sdbc;
+ using namespace ::com::sun::star::sdb;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::beans;
+ using namespace connectivity;
+
+ FilterManager::FilterManager( )
+ :m_bApplyPublicFilter( true )
+ {
+ }
+
+
+ void FilterManager::initialize( const Reference< XPropertySet >& _rxComponentAggregate )
+ {
+ m_xComponentAggregate = _rxComponentAggregate;
+ OSL_ENSURE( m_xComponentAggregate.is(), "FilterManager::initialize: invalid arguments!" );
+
+ if ( m_xComponentAggregate.is() )
+ m_xComponentAggregate->setPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_APPLYFILTER), Any( true ) );
+ }
+
+
+ void FilterManager::dispose( )
+ {
+ m_xComponentAggregate.clear();
+ }
+
+
+ const OUString& FilterManager::getFilterComponent( FilterComponent _eWhich ) const
+ {
+ switch (_eWhich)
+ {
+ case FilterComponent::PublicFilter:
+ return m_aPublicFilterComponent;
+ case FilterComponent::PublicHaving:
+ return m_aPublicHavingComponent;
+ case FilterComponent::LinkFilter:
+ return m_aLinkFilterComponent;
+ case FilterComponent::LinkHaving:
+ return m_aLinkHavingComponent;
+ }
+ assert(false);
+
+ static constexpr OUString sErr(u"#FilterManager::getFilterComponent unknown component#"_ustr);
+ return sErr;
+ }
+
+
+ void FilterManager::setFilterComponent( FilterComponent _eWhich, const OUString& _rComponent )
+ {
+ switch (_eWhich)
+ {
+ case FilterComponent::PublicFilter:
+ m_aPublicFilterComponent = _rComponent;
+ break;
+ case FilterComponent::PublicHaving:
+ m_aPublicHavingComponent = _rComponent;
+ break;
+ case FilterComponent::LinkFilter:
+ m_aLinkFilterComponent = _rComponent;
+ break;
+ case FilterComponent::LinkHaving:
+ m_aLinkHavingComponent = _rComponent;
+ break;
+ }
+ try
+ {
+ if ( m_xComponentAggregate.is() )
+ {
+ bool propagate(true);
+ switch (_eWhich)
+ {
+ case FilterComponent::PublicFilter:
+ propagate = propagate && m_bApplyPublicFilter;
+ [[fallthrough]];
+ case FilterComponent::LinkFilter:
+ if (propagate)
+ m_xComponentAggregate->setPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FILTER), Any( getComposedFilter() ) );
+ break;
+ case FilterComponent::PublicHaving:
+ propagate = propagate && m_bApplyPublicFilter;
+ [[fallthrough]];
+ case FilterComponent::LinkHaving:
+ if (propagate)
+ m_xComponentAggregate->setPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_HAVINGCLAUSE), Any( getComposedHaving() ) );
+ break;
+ }
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("connectivity.commontools");
+ }
+ }
+
+
+ void FilterManager::setApplyPublicFilter( bool _bApply )
+ {
+ if ( m_bApplyPublicFilter == _bApply )
+ return;
+
+ m_bApplyPublicFilter = _bApply;
+
+ try
+ {
+ if ( m_xComponentAggregate.is())
+ {
+ // only where/if something changed
+ if (!getFilterComponent( FilterComponent::PublicFilter ).isEmpty())
+ m_xComponentAggregate->setPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FILTER), Any( getComposedFilter() ) );
+ if (!getFilterComponent( FilterComponent::PublicHaving ).isEmpty())
+ m_xComponentAggregate->setPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_HAVINGCLAUSE), Any( getComposedHaving() ) );
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("connectivity.commontools");
+ }
+ }
+
+
+ void FilterManager::appendFilterComponent( OUStringBuffer& io_appendTo, std::u16string_view i_component )
+ {
+ if ( !io_appendTo.isEmpty() )
+ {
+ io_appendTo.insert( 0, '(' );
+ io_appendTo.insert( 1, ' ' );
+ io_appendTo.append( " ) AND " );
+ }
+
+ io_appendTo.append( "( " );
+ io_appendTo.append( i_component );
+ io_appendTo.append( " )" );
+ }
+
+
+ bool FilterManager::isThereAtMostOneFilterComponent( OUString& o_singleComponent ) const
+ {
+ if (m_bApplyPublicFilter) {
+ if (!m_aPublicFilterComponent.isEmpty() && !m_aLinkFilterComponent.isEmpty())
+ return false;
+ if (!m_aPublicFilterComponent.isEmpty())
+ o_singleComponent = m_aPublicFilterComponent;
+ else if (!m_aLinkFilterComponent.isEmpty())
+ o_singleComponent = m_aLinkFilterComponent;
+ else
+ o_singleComponent.clear();
+ return true;
+ }
+ else
+ {
+ if (m_aLinkFilterComponent.isEmpty())
+ o_singleComponent.clear();
+ else
+ o_singleComponent = m_aLinkFilterComponent;
+ return true;
+ }
+ }
+
+ bool FilterManager::isThereAtMostOneHavingComponent( OUString& o_singleComponent ) const
+ {
+ if (m_bApplyPublicFilter) {
+ if (!m_aPublicHavingComponent.isEmpty() && !m_aLinkHavingComponent.isEmpty())
+ return false;
+ if (!m_aPublicHavingComponent.isEmpty())
+ o_singleComponent = m_aPublicHavingComponent;
+ else if (!m_aLinkHavingComponent.isEmpty())
+ o_singleComponent = m_aLinkHavingComponent;
+ else
+ o_singleComponent.clear();
+ return true;
+ }
+ else
+ {
+ if (m_aLinkHavingComponent.isEmpty())
+ o_singleComponent.clear();
+ else
+ o_singleComponent = m_aLinkHavingComponent;
+ return true;
+ }
+ }
+
+
+ OUString FilterManager::getComposedFilter( ) const
+ {
+ // if we have only one non-empty component, then there's no need to compose anything
+ OUString singleComponent;
+ if ( isThereAtMostOneFilterComponent( singleComponent ) )
+ {
+ return singleComponent;
+ }
+ // append the single components
+ OUStringBuffer aComposedFilter(singleComponent);
+ if (m_bApplyPublicFilter)
+ appendFilterComponent( aComposedFilter, m_aPublicFilterComponent );
+ appendFilterComponent( aComposedFilter, m_aLinkFilterComponent );
+ return aComposedFilter.makeStringAndClear();
+ }
+
+
+ OUString FilterManager::getComposedHaving( ) const
+ {
+ // if we have only one non-empty component, then there's no need to compose anything
+ OUString singleComponent;
+ if ( isThereAtMostOneHavingComponent( singleComponent ) )
+ {
+ return singleComponent;
+ }
+ // append the single components
+ OUStringBuffer aComposedFilter(singleComponent);
+ if (m_bApplyPublicFilter)
+ appendFilterComponent( aComposedFilter, m_aPublicHavingComponent );
+ appendFilterComponent( aComposedFilter, m_aLinkHavingComponent );
+ return aComposedFilter.makeStringAndClear();
+ }
+
+
+} // namespace dbtools
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/commontools/formattedcolumnvalue.cxx b/connectivity/source/commontools/formattedcolumnvalue.cxx
new file mode 100644
index 0000000000..32db3d7177
--- /dev/null
+++ b/connectivity/source/commontools/formattedcolumnvalue.cxx
@@ -0,0 +1,291 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <connectivity/formattedcolumnvalue.hxx>
+#include <connectivity/dbtools.hxx>
+#include <connectivity/dbconversion.hxx>
+
+#include <com/sun/star/util/NumberFormatter.hpp>
+#include <com/sun/star/util/Date.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <com/sun/star/util/XNumberFormatTypes.hpp>
+#include <com/sun/star/util/NumberFormat.hpp>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <com/sun/star/sdb/XColumn.hpp>
+#include <com/sun/star/sdb/XColumnUpdate.hpp>
+
+#include <comphelper/diagnose_ex.hxx>
+#include <i18nlangtag/mslangid.hxx>
+#include <i18nlangtag/languagetag.hxx>
+#include <comphelper/numbers.hxx>
+
+
+namespace dbtools
+{
+
+
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::uno::UNO_QUERY;
+ using ::com::sun::star::uno::UNO_QUERY_THROW;
+ using ::com::sun::star::uno::UNO_SET_THROW;
+ using ::com::sun::star::uno::Exception;
+ using ::com::sun::star::uno::XComponentContext;
+ using ::com::sun::star::sdbc::XRowSet;
+ using ::com::sun::star::beans::XPropertySet;
+ using ::com::sun::star::util::NumberFormatter;
+ using ::com::sun::star::util::XNumberFormatter;
+ using ::com::sun::star::util::Date;
+ using ::com::sun::star::sdbc::XConnection;
+ using ::com::sun::star::util::XNumberFormatsSupplier;
+ using ::com::sun::star::beans::XPropertySetInfo;
+ using ::com::sun::star::lang::Locale;
+ using ::com::sun::star::util::XNumberFormatTypes;
+ using ::com::sun::star::sdb::XColumn;
+ using ::com::sun::star::sdb::XColumnUpdate;
+
+ namespace DataType = ::com::sun::star::sdbc::DataType;
+ namespace NumberFormat = ::com::sun::star::util::NumberFormat;
+
+ struct FormattedColumnValue_Data
+ {
+ Reference< XNumberFormatter > m_xFormatter;
+ Date m_aNullDate;
+ sal_Int32 m_nFormatKey;
+ sal_Int32 m_nFieldType;
+ sal_Int16 m_nKeyType;
+ bool m_bNumericField;
+
+ Reference< XColumn > m_xColumn;
+ Reference< XColumnUpdate > m_xColumnUpdate;
+
+ FormattedColumnValue_Data()
+ :m_aNullDate( DBTypeConversion::getStandardDate() )
+ ,m_nFormatKey( 0 )
+ ,m_nFieldType( DataType::OTHER )
+ ,m_nKeyType( NumberFormat::UNDEFINED )
+ ,m_bNumericField( false )
+ {
+ }
+ };
+
+
+ namespace
+ {
+
+ void lcl_clear_nothrow( FormattedColumnValue_Data& _rData )
+ {
+ _rData.m_xFormatter.clear();
+ _rData.m_nFormatKey = 0;
+ _rData.m_nFieldType = DataType::OTHER;
+ _rData.m_nKeyType = NumberFormat::UNDEFINED;
+ _rData.m_bNumericField = false;
+
+ _rData.m_xColumn.clear();
+ _rData.m_xColumnUpdate.clear();
+ }
+
+
+ void lcl_initColumnDataValue_nothrow( FormattedColumnValue_Data& _rData,
+ const Reference< XNumberFormatter >& i_rNumberFormatter, const Reference< XPropertySet >& _rxColumn )
+ {
+ lcl_clear_nothrow( _rData );
+
+ OSL_PRECOND( i_rNumberFormatter.is(), "lcl_initColumnDataValue_nothrow: no number formats -> no formatted values!" );
+ if ( !i_rNumberFormatter.is() )
+ return;
+
+ try
+ {
+ Reference< XNumberFormatsSupplier > xNumberFormatsSupp( i_rNumberFormatter->getNumberFormatsSupplier(), UNO_SET_THROW );
+
+ // remember the column
+ _rData.m_xColumn.set( _rxColumn, UNO_QUERY_THROW );
+ _rData.m_xColumnUpdate.set( _rxColumn, UNO_QUERY );
+
+ // determine the field type, and whether it's a numeric field
+ OSL_VERIFY( _rxColumn->getPropertyValue("Type") >>= _rData.m_nFieldType );
+
+ switch ( _rData.m_nFieldType )
+ {
+ case DataType::DATE:
+ case DataType::TIME:
+ case DataType::TIME_WITH_TIMEZONE:
+ case DataType::TIMESTAMP:
+ case DataType::TIMESTAMP_WITH_TIMEZONE:
+ case DataType::BIT:
+ case DataType::BOOLEAN:
+ case DataType::TINYINT:
+ case DataType::SMALLINT:
+ case DataType::INTEGER:
+ case DataType::REAL:
+ case DataType::BIGINT:
+ case DataType::DOUBLE:
+ case DataType::NUMERIC:
+ case DataType::DECIMAL:
+ _rData.m_bNumericField = true;
+ break;
+ default:
+ _rData.m_bNumericField = false;
+ break;
+ }
+
+ // get the format key of our bound field
+ Reference< XPropertySetInfo > xPSI( _rxColumn->getPropertySetInfo(), UNO_SET_THROW );
+ bool bHaveFieldFormat = false;
+ static constexpr OUString sFormatKeyProperty( u"FormatKey"_ustr );
+ if ( xPSI->hasPropertyByName( sFormatKeyProperty ) )
+ {
+ bHaveFieldFormat = ( _rxColumn->getPropertyValue( sFormatKeyProperty ) >>= _rData.m_nFormatKey );
+ }
+ if ( !bHaveFieldFormat )
+ {
+ // fall back to a format key as indicated by the field type
+ Locale aSystemLocale( LanguageTag( MsLangId::getConfiguredSystemLanguage() ).getLocale() );
+ Reference< XNumberFormatTypes > xNumTypes( xNumberFormatsSupp->getNumberFormats(), UNO_QUERY_THROW );
+ _rData.m_nFormatKey = getDefaultNumberFormat( _rxColumn, xNumTypes, aSystemLocale );
+ }
+
+ // some more formatter settings
+ _rData.m_nKeyType = ::comphelper::getNumberFormatType( xNumberFormatsSupp->getNumberFormats(), _rData.m_nFormatKey );
+ Reference< XPropertySet > xFormatSettings( xNumberFormatsSupp->getNumberFormatSettings(), UNO_SET_THROW );
+ OSL_VERIFY( xFormatSettings->getPropertyValue("NullDate") >>= _rData.m_aNullDate );
+
+ // remember the formatter
+ _rData.m_xFormatter = i_rNumberFormatter;
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("connectivity.commontools");
+ }
+ }
+
+
+ void lcl_initColumnDataValue_nothrow( const Reference<XComponentContext>& i_rContext, FormattedColumnValue_Data& i_rData,
+ const Reference< XRowSet >& i_rRowSet, const Reference< XPropertySet >& i_rColumn )
+ {
+ OSL_PRECOND( i_rRowSet.is(), "lcl_initColumnDataValue_nothrow: no row set!" );
+ if ( !i_rRowSet.is() )
+ return;
+
+ Reference< XNumberFormatter > xNumberFormatter;
+ try
+ {
+ // get the number formats supplier of the connection of the form
+ Reference< XConnection > xConnection( getConnection( i_rRowSet ), UNO_SET_THROW );
+ Reference< XNumberFormatsSupplier > xSupplier( getNumberFormats( xConnection, true, i_rContext ), UNO_SET_THROW );
+
+ // create a number formatter for it
+ xNumberFormatter.set( NumberFormatter::create( i_rContext ), UNO_QUERY_THROW );
+ xNumberFormatter->attachNumberFormatsSupplier( xSupplier );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("connectivity.commontools");
+ }
+
+ lcl_initColumnDataValue_nothrow( i_rData, xNumberFormatter, i_rColumn );
+ }
+ }
+
+ FormattedColumnValue::FormattedColumnValue( const Reference< XComponentContext >& _rxContext,
+ const Reference< XRowSet >& _rxRowSet, const Reference< XPropertySet >& i_rColumn )
+ :m_pData( new FormattedColumnValue_Data )
+ {
+ lcl_initColumnDataValue_nothrow( _rxContext, *m_pData, _rxRowSet, i_rColumn );
+ }
+
+
+ FormattedColumnValue::FormattedColumnValue( const Reference< XNumberFormatter >& i_rNumberFormatter,
+ const Reference< XPropertySet >& _rxColumn )
+ :m_pData( new FormattedColumnValue_Data )
+ {
+ lcl_initColumnDataValue_nothrow( *m_pData, i_rNumberFormatter, _rxColumn );
+ }
+
+
+ FormattedColumnValue::~FormattedColumnValue()
+ {
+ lcl_clear_nothrow( *m_pData );
+ }
+
+ sal_Int16 FormattedColumnValue::getKeyType() const
+ {
+ return m_pData->m_nKeyType;
+ }
+
+
+ const Reference< XColumn >& FormattedColumnValue::getColumn() const
+ {
+ return m_pData->m_xColumn;
+ }
+
+ bool FormattedColumnValue::setFormattedValue( const OUString& _rFormattedStringValue ) const
+ {
+ OSL_PRECOND( m_pData->m_xColumnUpdate.is(), "FormattedColumnValue::setFormattedValue: no column!" );
+ if ( !m_pData->m_xColumnUpdate.is() )
+ return false;
+
+ try
+ {
+ if ( m_pData->m_bNumericField )
+ {
+ ::dbtools::DBTypeConversion::setValue( m_pData->m_xColumnUpdate, m_pData->m_xFormatter, m_pData->m_aNullDate,
+ _rFormattedStringValue, m_pData->m_nFormatKey, ::sal::static_int_cast< sal_Int16 >( m_pData->m_nFieldType ),
+ m_pData->m_nKeyType );
+ }
+ else
+ {
+ m_pData->m_xColumnUpdate->updateString( _rFormattedStringValue );
+ }
+ }
+ catch( const Exception& )
+ {
+ return false;
+ }
+ return true;
+ }
+
+
+ OUString FormattedColumnValue::getFormattedValue() const
+ {
+ OSL_PRECOND( m_pData->m_xColumn.is(), "FormattedColumnValue::setFormattedValue: no column!" );
+
+ OUString sStringValue;
+ if ( m_pData->m_xColumn.is() )
+ {
+ if ( m_pData->m_bNumericField )
+ {
+ sStringValue = DBTypeConversion::getFormattedValue(
+ m_pData->m_xColumn, m_pData->m_xFormatter, m_pData->m_aNullDate, m_pData->m_nFormatKey, m_pData->m_nKeyType
+ );
+ }
+ else
+ {
+ sStringValue = m_pData->m_xColumn->getString();
+ }
+ }
+ return sStringValue;
+ }
+
+
+} // namespace dbtools
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/commontools/parameters.cxx b/connectivity/source/commontools/parameters.cxx
new file mode 100644
index 0000000000..990085c87f
--- /dev/null
+++ b/connectivity/source/commontools/parameters.cxx
@@ -0,0 +1,1212 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <connectivity/parameters.hxx>
+
+#include <com/sun/star/form/DatabaseParameterEvent.hpp>
+#include <com/sun/star/form/XDatabaseParameterListener.hpp>
+#include <com/sun/star/sdbc/XParameters.hpp>
+#include <com/sun/star/container/XChild.hpp>
+#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
+#include <com/sun/star/sdb/XParametersSupplier.hpp>
+#include <com/sun/star/sdb/ParametersRequest.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <com/sun/star/task/XInteractionHandler.hpp>
+
+#include <connectivity/dbtools.hxx>
+#include <connectivity/filtermanager.hxx>
+#include <TConnection.hxx>
+
+#include <comphelper/diagnose_ex.hxx>
+
+#include <ParameterCont.hxx>
+#include <o3tl/safeint.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <sal/log.hxx>
+
+namespace dbtools
+{
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::sdb;
+ using namespace ::com::sun::star::sdbc;
+ using namespace ::com::sun::star::sdbcx;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::beans;
+ using namespace ::com::sun::star::task;
+ using namespace ::com::sun::star::form;
+ using namespace ::com::sun::star::container;
+
+ using namespace ::comphelper;
+ using namespace ::connectivity;
+
+ ParameterManager::ParameterManager( ::osl::Mutex& _rMutex, const Reference< XComponentContext >& _rxContext )
+ :m_rMutex ( _rMutex )
+ ,m_aParameterListeners( _rMutex )
+ ,m_xContext ( _rxContext )
+ ,m_nInnerCount ( 0 )
+ ,m_bUpToDate ( false )
+ {
+ OSL_ENSURE( m_xContext.is(), "ParameterManager::ParameterManager: no service factory!" );
+ }
+
+
+ void ParameterManager::initialize( const Reference< XPropertySet >& _rxComponent, const Reference< XAggregation >& _rxComponentAggregate )
+ {
+ OSL_ENSURE( !m_xComponent.get().is(), "ParameterManager::initialize: already initialized!" );
+
+ m_xComponent = _rxComponent;
+ m_xAggregatedRowSet = _rxComponentAggregate;
+ if ( m_xAggregatedRowSet.is() )
+ m_xAggregatedRowSet->queryAggregation( cppu::UnoType<decltype(m_xInnerParamUpdate)>::get() ) >>= m_xInnerParamUpdate;
+ OSL_ENSURE( m_xComponent.get().is() && m_xInnerParamUpdate.is(), "ParameterManager::initialize: invalid arguments!" );
+ if ( !m_xComponent.get().is() || !m_xInnerParamUpdate.is() )
+ return;
+ }
+
+
+ void ParameterManager::dispose( )
+ {
+ clearAllParameterInformation();
+
+ m_xComposer.clear();
+ m_xParentComposer.clear();
+ //m_xComponent.clear();
+ m_xInnerParamUpdate.clear();
+ m_xAggregatedRowSet.clear();
+ }
+
+
+ void ParameterManager::clearAllParameterInformation()
+ {
+ m_xInnerParamColumns.clear();
+ if ( m_pOuterParameters.is() )
+ m_pOuterParameters->dispose();
+ m_pOuterParameters = nullptr;
+ m_nInnerCount = 0;
+ ParameterInformation().swap(m_aParameterInformation);
+ m_aMasterFields.clear();
+ m_aDetailFields.clear();
+ m_sIdentifierQuoteString.clear();
+ m_sSpecialCharacters.clear();
+ m_xConnectionMetadata.clear();
+ std::vector< bool >().swap(m_aParametersVisited);
+ m_bUpToDate = false;
+ }
+
+
+ void ParameterManager::setAllParametersNull()
+ {
+ OSL_PRECOND( isAlive(), "ParameterManager::setAllParametersNull: not initialized, or already disposed!" );
+ if ( !isAlive() )
+ return;
+
+ for ( sal_Int32 i = 1; i <= m_nInnerCount; ++i )
+ m_xInnerParamUpdate->setNull( i, DataType::VARCHAR );
+ }
+
+
+ bool ParameterManager::initializeComposerByComponent( const Reference< XPropertySet >& _rxComponent )
+ {
+ OSL_PRECOND( _rxComponent.is(), "ParameterManager::initializeComposerByComponent: invalid !" );
+
+ m_xComposer.clear();
+ m_xInnerParamColumns.clear();
+ m_nInnerCount = 0;
+
+ // create and fill a composer
+ try
+ {
+ // get a query composer for the 's settings
+ m_xComposer.reset( getCurrentSettingsComposer( _rxComponent, m_xContext, nullptr ), SharedQueryComposer::TakeOwnership );
+
+ // see if the composer found parameters
+ Reference< XParametersSupplier > xParamSupp( m_xComposer, UNO_QUERY );
+ if ( xParamSupp.is() )
+ m_xInnerParamColumns = xParamSupp->getParameters();
+
+ if ( m_xInnerParamColumns.is() )
+ m_nInnerCount = m_xInnerParamColumns->getCount();
+ }
+ catch( const SQLException& )
+ {
+ }
+
+ return m_xInnerParamColumns.is();
+ }
+
+
+ void ParameterManager::collectInnerParameters( bool _bSecondRun )
+ {
+ OSL_PRECOND( m_xInnerParamColumns.is(), "ParameterManager::collectInnerParameters: missing some internal data!" );
+ if ( !m_xInnerParamColumns.is() )
+ return;
+
+ // strip previous index information
+ if ( _bSecondRun )
+ {
+ for (auto & paramInfo : m_aParameterInformation)
+ {
+ paramInfo.second.aInnerIndexes.clear();
+ }
+ }
+
+ // we need to map the parameter names (which is all we get from the 's
+ // MasterFields property) to indices, which are needed by the XParameters
+ // interface of the row set)
+ Reference<XPropertySet> xParam;
+ for ( sal_Int32 i = 0; i < m_nInnerCount; ++i )
+ {
+ try
+ {
+ xParam.clear();
+ m_xInnerParamColumns->getByIndex( i ) >>= xParam;
+
+ OUString sName;
+ xParam->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME) ) >>= sName;
+
+ // only append additional parameters when they are not already in the list
+ ParameterInformation::iterator aExistentPos = m_aParameterInformation.find( sName );
+ OSL_ENSURE( !_bSecondRun || ( aExistentPos != m_aParameterInformation.end() ),
+ "ParameterManager::collectInnerParameters: the parameter information should already exist in the second run!" );
+
+ if ( aExistentPos == m_aParameterInformation.end() )
+ {
+ aExistentPos = m_aParameterInformation.emplace(
+ sName, xParam ).first;
+ }
+ else
+ aExistentPos->second.xComposerColumn = xParam;
+
+ aExistentPos->second.aInnerIndexes.push_back( i );
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "connectivity.commontools", "ParameterManager::collectInnerParameters" );
+ }
+ }
+ }
+
+
+ OUString ParameterManager::createFilterConditionFromColumnLink(
+ const OUString &_rMasterColumn, const Reference < XPropertySet > &xDetailField, OUString &o_rNewParamName )
+ {
+ OUString sFilter;
+ // format is:
+ // <detail_column> = :<new_param_name>
+ {
+ OUString tblName;
+ xDetailField->getPropertyValue("TableName") >>= tblName;
+ if (!tblName.isEmpty())
+ sFilter = ::dbtools::quoteTableName( m_xConnectionMetadata, tblName, ::dbtools::EComposeRule::InDataManipulation ) + ".";
+ }
+ {
+ OUString colName;
+ xDetailField->getPropertyValue("RealName") >>= colName;
+ bool isFunction(false);
+ xDetailField->getPropertyValue("Function") >>= isFunction;
+ if (isFunction)
+ sFilter += colName;
+ else
+ sFilter += quoteName( m_sIdentifierQuoteString, colName );
+ }
+
+ // generate a parameter name which is not already used
+ o_rNewParamName = "link_from_";
+ o_rNewParamName += convertName2SQLName( _rMasterColumn, m_sSpecialCharacters );
+ while ( m_aParameterInformation.find( o_rNewParamName ) != m_aParameterInformation.end() )
+ {
+ o_rNewParamName += "_";
+ }
+
+ return sFilter + " =:" + o_rNewParamName;
+ }
+
+
+ void ParameterManager::classifyLinks( const Reference< XNameAccess >& _rxParentColumns,
+ const Reference< XNameAccess >& _rxColumns,
+ std::vector< OUString >& _out_rAdditionalFilterComponents,
+ std::vector< OUString >& _out_rAdditionalHavingComponents )
+ {
+ OSL_PRECOND( m_aMasterFields.size() == m_aDetailFields.size(),
+ "ParameterManager::classifyLinks: master and detail fields should have the same length!" );
+ OSL_ENSURE( _rxColumns.is(), "ParameterManager::classifyLinks: invalid columns!" );
+
+ if ( !_rxColumns.is() )
+ return;
+
+ // we may need to strip any links which are invalid, so here go the containers
+ // for temporarily holding the new pairs
+ std::vector< OUString > aStrippedMasterFields;
+ std::vector< OUString > aStrippedDetailFields;
+
+ bool bNeedExchangeLinks = false;
+
+ // classify the links
+ auto pMasterFields = m_aMasterFields.begin();
+ auto pDetailFields = m_aDetailFields.begin();
+ auto pDetailFieldsEnd = m_aDetailFields.end();
+ for ( ; pDetailFields != pDetailFieldsEnd; ++pDetailFields, ++pMasterFields )
+ {
+ if ( pMasterFields->isEmpty() || pDetailFields->isEmpty() )
+ continue;
+
+ // if not even the master part of the relationship exists in the parent, the
+ // link is invalid as a whole #i63674#
+ if ( !_rxParentColumns->hasByName( *pMasterFields ) )
+ {
+ bNeedExchangeLinks = true;
+ continue;
+ }
+
+ bool bValidLink = true;
+
+ // is there an inner parameter with this name? That is, a parameter which is already part of
+ // the very original statement (not the one we create ourselves, with the additional parameters)
+ ParameterInformation::iterator aPos = m_aParameterInformation.find( *pDetailFields );
+ if ( aPos != m_aParameterInformation.end() )
+ { // there is an inner parameter with this name
+ aPos->second.eType = ParameterClassification::LinkedByParamName;
+ aStrippedDetailFields.push_back( *pDetailFields );
+ }
+ else
+ {
+ // does the detail name denote a column?
+ if ( _rxColumns->hasByName( *pDetailFields ) )
+ {
+ Reference< XPropertySet > xDetailField(_rxColumns->getByName( *pDetailFields ), UNO_QUERY);
+ assert(xDetailField.is());
+
+ OUString sNewParamName;
+ const OUString sFilterCondition = createFilterConditionFromColumnLink( *pMasterFields, xDetailField, sNewParamName );
+ OSL_PRECOND( !sNewParamName.isEmpty(), "ParameterManager::classifyLinks: createFilterConditionFromColumnLink returned nonsense!" );
+
+ // remember meta information about this new parameter
+ std::pair< ParameterInformation::iterator, bool > aInsertionPos =
+ m_aParameterInformation.emplace(
+ sNewParamName, ParameterMetaData( nullptr )
+ );
+ OSL_ENSURE( aInsertionPos.second, "ParameterManager::classifyLinks: there already was a parameter with this name!" );
+ aInsertionPos.first->second.eType = ParameterClassification::LinkedByColumnName;
+
+ // remember the filter component
+ if (isAggregateColumn(xDetailField))
+ _out_rAdditionalHavingComponents.push_back( sFilterCondition );
+ else
+ _out_rAdditionalFilterComponents.push_back( sFilterCondition );
+
+ // remember the new "detail field" for this link
+ aStrippedDetailFields.push_back( sNewParamName );
+ bNeedExchangeLinks = true;
+ }
+ else
+ {
+ // the detail field neither denotes a column name, nor a parameter name
+ bValidLink = false;
+ bNeedExchangeLinks = true;
+ }
+ }
+
+ if ( bValidLink )
+ aStrippedMasterFields.push_back( *pMasterFields );
+ }
+ SAL_WARN_IF( aStrippedMasterFields.size() != aStrippedDetailFields.size(),
+ "connectivity.commontools",
+ "ParameterManager::classifyLinks: inconsistency in new link pairs!" );
+
+ if ( bNeedExchangeLinks )
+ {
+ m_aMasterFields.swap(aStrippedMasterFields);
+ m_aDetailFields.swap(aStrippedDetailFields);
+ }
+ }
+
+
+ void ParameterManager::analyzeFieldLinks( FilterManager& _rFilterManager, bool& /* [out] */ _rColumnsInLinkDetails )
+ {
+ OSL_PRECOND( isAlive(), "ParameterManager::analyzeFieldLinks: not initialized, or already disposed!" );
+ if ( !isAlive() )
+ return;
+
+ _rColumnsInLinkDetails = false;
+ try
+ {
+ // the links as determined by the properties
+ Reference< XPropertySet > xProp = m_xComponent;
+ OSL_ENSURE(xProp.is(),"Someone already released my component!");
+ if ( xProp.is() )
+ {
+ Sequence<OUString> aTmp;
+ if (xProp->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_MASTERFIELDS) ) >>= aTmp)
+ comphelper::sequenceToContainer(m_aMasterFields, aTmp);
+ if (xProp->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DETAILFIELDS) ) >>= aTmp)
+ comphelper::sequenceToContainer(m_aDetailFields, aTmp);
+ }
+
+ {
+ // normalize to equal length
+ sal_Int32 nMasterLength = m_aMasterFields.size();
+ sal_Int32 nDetailLength = m_aDetailFields.size();
+
+ if ( nMasterLength > nDetailLength )
+ m_aMasterFields.resize( nDetailLength );
+ else if ( nDetailLength > nMasterLength )
+ m_aDetailFields.resize( nMasterLength );
+ }
+
+ Reference< XNameAccess > xColumns;
+ if ( !getColumns( xColumns, true ) )
+ // already asserted in getColumns
+ return;
+
+ Reference< XNameAccess > xParentColumns;
+ if ( !getParentColumns( xParentColumns, true ) )
+ return;
+
+ // classify the links - depending on what the detail fields in each link pair denotes
+ std::vector< OUString > aAdditionalFilterComponents;
+ std::vector< OUString > aAdditionalHavingComponents;
+ classifyLinks( xParentColumns, xColumns, aAdditionalFilterComponents, aAdditionalHavingComponents );
+
+ // did we find links where the detail field refers to a detail column (instead of a parameter name)?
+ if ( !aAdditionalFilterComponents.empty() )
+ {
+ // build a conjunction of all the filter components
+ OUStringBuffer sAdditionalFilter;
+ for (auto const& elem : aAdditionalFilterComponents)
+ {
+ if ( !sAdditionalFilter.isEmpty() )
+ sAdditionalFilter.append(" AND ");
+
+ sAdditionalFilter.append("( " + elem + " )");
+ }
+
+ // now set this filter at the filter manager
+ _rFilterManager.setFilterComponent( FilterManager::FilterComponent::LinkFilter, sAdditionalFilter.makeStringAndClear() );
+
+ _rColumnsInLinkDetails = true;
+ }
+
+ if ( !aAdditionalHavingComponents.empty() )
+ {
+ // build a conjunction of all the filter components
+ OUStringBuffer sAdditionalHaving;
+ for (auto const& elem : aAdditionalHavingComponents)
+ {
+ if ( !sAdditionalHaving.isEmpty() )
+ sAdditionalHaving.append(" AND ");
+
+ sAdditionalHaving.append("( " + elem + " )");
+ }
+
+ // now set this having clause at the filter manager
+ _rFilterManager.setFilterComponent( FilterManager::FilterComponent::LinkHaving, sAdditionalHaving.makeStringAndClear() );
+
+ _rColumnsInLinkDetails = true;
+ }
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "connectivity.commontools", "ParameterManager::analyzeFieldLinks" );
+ }
+ }
+
+
+ void ParameterManager::createOuterParameters()
+ {
+ OSL_PRECOND( !m_pOuterParameters.is(), "ParameterManager::createOuterParameters: outer parameters not initialized!" );
+ OSL_PRECOND( m_xInnerParamUpdate.is(), "ParameterManager::createOuterParameters: no write access to the inner parameters!" );
+ if ( !m_xInnerParamUpdate.is() )
+ return;
+
+ m_pOuterParameters = new param::ParameterWrapperContainer;
+
+#if OSL_DEBUG_LEVEL > 0
+ sal_Int32 nSmallestIndexLinkedByColumnName = -1;
+ sal_Int32 nLargestIndexNotLinkedByColumnName = -1;
+#endif
+ for (auto & aParam : m_aParameterInformation)
+ {
+#if OSL_DEBUG_LEVEL > 0
+ if ( aParam.second.aInnerIndexes.size() )
+ {
+ if ( aParam.second.eType == ParameterClassification::LinkedByColumnName )
+ {
+ if ( nSmallestIndexLinkedByColumnName == -1 )
+ nSmallestIndexLinkedByColumnName = aParam.second.aInnerIndexes[ 0 ];
+ }
+ else
+ {
+ nLargestIndexNotLinkedByColumnName = aParam.second.aInnerIndexes[ aParam.second.aInnerIndexes.size() - 1 ];
+ }
+ }
+#endif
+ if ( aParam.second.eType != ParameterClassification::FilledExternally )
+ continue;
+
+ // check which of the parameters have already been visited (e.g. filled via XParameters)
+ size_t nAlreadyVisited = 0;
+ for (auto & aIndex : aParam.second.aInnerIndexes)
+ {
+ if ( ( m_aParametersVisited.size() > o3tl::make_unsigned(aIndex) ) && m_aParametersVisited[ aIndex ] )
+ { // exclude this index
+ aIndex = -1;
+ ++nAlreadyVisited;
+ }
+ }
+ if ( nAlreadyVisited == aParam.second.aInnerIndexes.size() )
+ continue;
+
+ // need a wrapper for this... the "inner parameters" as supplied by a result set don't have a "Value"
+ // property, but the parameter listeners expect such a property. So we need an object "aggregating"
+ // xParam and supplying an additional property ("Value")
+ // (it's no real aggregation of course...)
+ m_pOuterParameters->push_back( new param::ParameterWrapper( aParam.second.xComposerColumn, m_xInnerParamUpdate, std::vector(aParam.second.aInnerIndexes) ) );
+ }
+
+#if OSL_DEBUG_LEVEL > 0
+ OSL_ENSURE( ( nSmallestIndexLinkedByColumnName == -1 ) || ( nLargestIndexNotLinkedByColumnName == -1 ) ||
+ ( nSmallestIndexLinkedByColumnName > nLargestIndexNotLinkedByColumnName ),
+ "ParameterManager::createOuterParameters: inconsistency!" );
+
+ // for the master-detail links, where the detail field denoted a column name, we created an additional ("artificial")
+ // filter, and *appended* it to all other (potentially) existing filters of the row set. This means that the indexes
+ // for the parameters resulting from the artificial filter should be larger than any other parameter index, and this
+ // is what the assertion checks.
+ // If the assertion fails, then we would need another handling for the "parameters visited" flags, since they're based
+ // on parameter indexes *without* the artificial filter (because this filter is not visible from the outside).
+#endif
+ }
+
+
+ void ParameterManager::updateParameterInfo( FilterManager& _rFilterManager )
+ {
+ OSL_PRECOND( isAlive(), "ParameterManager::updateParameterInfo: not initialized, or already disposed!" );
+ if ( !isAlive() )
+ return;
+
+ clearAllParameterInformation();
+ cacheConnectionInfo();
+
+ // check whether the is based on a statement/query which requires parameters
+ Reference< XPropertySet > xProp = m_xComponent;
+ OSL_ENSURE(xProp.is(),"Some already released my component!");
+ if ( xProp.is() )
+ {
+ if ( !initializeComposerByComponent( xProp ) )
+ { // okay, nothing to do
+ m_bUpToDate = true;
+ return;
+ } // if ( !initializeComposerByComponent( m_xComponent ) )
+ }
+ SAL_WARN_IF( !m_xInnerParamColumns.is(),
+ "connectivity.commontools",
+ "ParameterManager::updateParameterInfo: initializeComposerByComponent did nonsense (1)!" );
+
+ // collect all parameters which are defined by the "inner parameters"
+ collectInnerParameters( false );
+
+ // analyze the master-detail relationships
+ bool bColumnsInLinkDetails = false;
+ analyzeFieldLinks( _rFilterManager, bColumnsInLinkDetails );
+
+ if ( bColumnsInLinkDetails )
+ {
+ // okay, in this case, analyzeFieldLinks modified the "real" filter at the RowSet, to contain
+ // an additional restriction (which we created ourself)
+ // So we need to update all information about our inner parameter columns
+ Reference< XPropertySet > xDirectRowSetProps;
+ m_xAggregatedRowSet->queryAggregation( cppu::UnoType<decltype(xDirectRowSetProps)>::get() ) >>= xDirectRowSetProps;
+ OSL_VERIFY( initializeComposerByComponent( xDirectRowSetProps ) );
+ collectInnerParameters( true );
+ }
+
+ if ( !m_nInnerCount )
+ { // no parameters at all
+ m_bUpToDate = true;
+ return;
+ }
+
+ // for what now remains as outer parameters, create the wrappers for the single
+ // parameter columns
+ createOuterParameters();
+
+ m_bUpToDate = true;
+ }
+
+
+ void ParameterManager::fillLinkedParameters( const Reference< XNameAccess >& _rxParentColumns )
+ {
+ OSL_PRECOND( isAlive(), "ParameterManager::fillLinkedParameters: not initialized, or already disposed!" );
+ if ( !isAlive() )
+ return;
+ OSL_PRECOND( m_xInnerParamColumns.is(), "ParameterManager::fillLinkedParameters: no inner parameters found!" );
+ OSL_ENSURE ( _rxParentColumns.is(), "ParameterManager::fillLinkedParameters: invalid parent columns!" );
+
+ try
+ {
+ // the master and detail field( name)s of the
+ auto pMasterFields = m_aMasterFields.begin();
+ auto pDetailFields = m_aDetailFields.begin();
+
+ sal_Int32 nMasterLen = m_aMasterFields.size();
+
+ // loop through all master fields. For each of them, get the respective column from the
+ // parent , and forward its current value as parameter value to the (inner) row set
+ for ( sal_Int32 i = 0; i < nMasterLen; ++i, ++pMasterFields, ++pDetailFields )
+ {
+ // does the name denote a valid column in the parent?
+ if ( !_rxParentColumns->hasByName( *pMasterFields ) )
+ {
+ SAL_WARN( "connectivity.commontools", "ParameterManager::fillLinkedParameters: invalid master names should have been stripped long before!" );
+ continue;
+ }
+
+ // do we, for this name, know where to place the values?
+ ParameterInformation::const_iterator aParamInfo = m_aParameterInformation.find( *pDetailFields );
+ if ( ( aParamInfo == m_aParameterInformation.end() )
+ || ( aParamInfo->second.aInnerIndexes.empty() )
+ )
+ {
+ SAL_WARN( "connectivity.commontools", "ParameterManager::fillLinkedParameters: nothing known about this detail field!" );
+ continue;
+ }
+
+ // the concrete master field
+ Reference< XPropertySet > xMasterField(_rxParentColumns->getByName( *pMasterFields ),UNO_QUERY);
+
+ // the positions where we have to fill in values for the current parameter name
+ for (auto const& aPosition : aParamInfo->second.aInnerIndexes)
+ {
+ // the concrete detail field
+ Reference< XPropertySet > xDetailField(m_xInnerParamColumns->getByIndex(aPosition),UNO_QUERY);
+ OSL_ENSURE( xDetailField.is(), "ParameterManager::fillLinkedParameters: invalid detail field!" );
+ if ( !xDetailField.is() )
+ continue;
+
+ // type and scale of the parameter field
+ sal_Int32 nParamType = DataType::VARCHAR;
+ OSL_VERIFY( xDetailField->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE) ) >>= nParamType );
+
+ sal_Int32 nScale = 0;
+ if ( xDetailField->getPropertySetInfo()->hasPropertyByName( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCALE) ) )
+ OSL_VERIFY( xDetailField->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCALE) ) >>= nScale );
+
+ // transfer the param value
+ try
+ {
+ m_xInnerParamUpdate->setObjectWithInfo(
+ aPosition + 1, // parameters are based at 1
+ xMasterField->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_VALUE) ),
+ nParamType,
+ nScale
+ );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("connectivity.commontools");
+ SAL_WARN( "connectivity.commontools", "ParameterManager::fillLinkedParameters: master-detail parameter number " <<
+ sal_Int32( aPosition + 1 ) << " could not be filled!" );
+ }
+ }
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("connectivity.commontools");
+ }
+ }
+
+
+ bool ParameterManager::completeParameters( const Reference< XInteractionHandler >& _rxCompletionHandler, const Reference< XConnection >& _rxConnection )
+ {
+ OSL_PRECOND( isAlive(), "ParameterManager::completeParameters: not initialized, or already disposed!" );
+ OSL_ENSURE ( _rxCompletionHandler.is(), "ParameterManager::completeParameters: invalid interaction handler!" );
+
+ // two continuations (Ok and Cancel)
+ rtl::Reference<OInteractionAbort> pAbort = new OInteractionAbort;
+ rtl::Reference<OParameterContinuation> pParams = new OParameterContinuation;
+
+ // the request
+ ParametersRequest aRequest;
+ aRequest.Parameters = m_pOuterParameters.get();
+ aRequest.Connection = _rxConnection;
+ rtl::Reference<OInteractionRequest> pRequest = new OInteractionRequest( Any( aRequest ) );
+
+ // some knittings
+ pRequest->addContinuation( pAbort );
+ pRequest->addContinuation( pParams );
+
+ // execute the request
+ try
+ {
+ _rxCompletionHandler->handle( pRequest );
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "connectivity.commontools", "ParameterManager::completeParameters: caught an exception while calling the handler" );
+ }
+
+ if ( !pParams->wasSelected() )
+ // canceled by the user (i.e. (s)he canceled the dialog)
+ return false;
+
+ try
+ {
+ // transfer the values from the continuation object to the parameter columns
+ const Sequence< PropertyValue >& aFinalValues = pParams->getValues();
+ const PropertyValue* pFinalValues = aFinalValues.getConstArray();
+ for ( sal_Int32 i = 0; i < aFinalValues.getLength(); ++i, ++pFinalValues )
+ {
+ Reference< XPropertySet > xParamColumn(aRequest.Parameters->getByIndex( i ),UNO_QUERY);
+ if ( xParamColumn.is() )
+ {
+ #ifdef DBG_UTIL
+ OUString sName;
+ xParamColumn->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME) ) >>= sName;
+ OSL_ENSURE( sName == pFinalValues->Name, "ParameterManager::completeParameters: inconsistent parameter names!" );
+ #endif
+ xParamColumn->setPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_VALUE), pFinalValues->Value );
+ // the property sets are wrapper classes, translating the Value property into a call to
+ // the appropriate XParameters interface
+ }
+ }
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "connectivity.commontools", "ParameterManager::completeParameters: caught an exception while propagating the values" );
+ }
+ return true;
+ }
+
+
+ bool ParameterManager::consultParameterListeners( ::osl::ResettableMutexGuard& _rClearForNotifies )
+ {
+ bool bCanceled = false;
+
+ sal_Int32 nParamsLeft = m_pOuterParameters->getParameters().size();
+ // TODO: shouldn't we subtract all the parameters which were already visited?
+ if ( nParamsLeft )
+ {
+ ::comphelper::OInterfaceIteratorHelper3 aIter( m_aParameterListeners );
+ Reference< XPropertySet > xProp = m_xComponent;
+ OSL_ENSURE(xProp.is(),"Some already released my component!");
+ DatabaseParameterEvent aEvent( xProp, m_pOuterParameters );
+
+ _rClearForNotifies.clear();
+ while ( aIter.hasMoreElements() && !bCanceled )
+ bCanceled = !aIter.next()->approveParameter( aEvent );
+ _rClearForNotifies.reset();
+ }
+
+ return !bCanceled;
+ }
+
+
+ bool ParameterManager::fillParameterValues( const Reference< XInteractionHandler >& _rxCompletionHandler, ::osl::ResettableMutexGuard& _rClearForNotifies )
+ {
+ OSL_PRECOND( isAlive(), "ParameterManager::fillParameterValues: not initialized, or already disposed!" );
+ if ( !isAlive() )
+ return true;
+
+ if ( m_nInnerCount == 0 )
+ // no parameters at all
+ return true;
+
+ // fill the parameters from the master-detail relationship
+ Reference< XNameAccess > xParentColumns;
+ if ( getParentColumns( xParentColumns, false ) && xParentColumns->hasElements() && !m_aMasterFields.empty() )
+ fillLinkedParameters( xParentColumns );
+
+ // let the user (via the interaction handler) fill all remaining parameters
+ Reference< XConnection > xConnection;
+ getConnection( xConnection );
+
+ if ( _rxCompletionHandler.is() )
+ return completeParameters( _rxCompletionHandler, xConnection );
+
+ return consultParameterListeners( _rClearForNotifies );
+ }
+
+
+ void ParameterManager::getConnection( Reference< XConnection >& /* [out] */ _rxConnection )
+ {
+ OSL_PRECOND( isAlive(), "ParameterManager::getConnection: not initialized, or already disposed!" );
+ if ( !isAlive() )
+ return;
+
+ _rxConnection.clear();
+ try
+ {
+ Reference< XPropertySet > xProp = m_xComponent;
+ OSL_ENSURE(xProp.is(),"Some already released my component!");
+ if ( xProp.is() )
+ xProp->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ACTIVE_CONNECTION) ) >>= _rxConnection;
+ }
+ catch( const Exception& )
+ {
+ SAL_WARN( "connectivity.commontools", "ParameterManager::getConnection: could not retrieve the connection of the !" );
+ }
+ }
+
+
+ void ParameterManager::cacheConnectionInfo()
+ {
+ try
+ {
+ Reference< XConnection > xConnection;
+ getConnection( xConnection );
+ Reference< XDatabaseMetaData > xMeta;
+ if ( xConnection.is() )
+ xMeta = xConnection->getMetaData();
+ if ( xMeta.is() )
+ {
+ m_xConnectionMetadata = xMeta;
+ m_sIdentifierQuoteString = xMeta->getIdentifierQuoteString();
+ m_sSpecialCharacters = xMeta->getExtraNameCharacters();
+ }
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "connectivity.commontools", "ParameterManager::cacheConnectionInfo: caught an exception" );
+ }
+ }
+
+
+ bool ParameterManager::getColumns( Reference< XNameAccess >& /* [out] */ _rxColumns, bool _bFromComposer )
+ {
+ _rxColumns.clear();
+
+ Reference< XColumnsSupplier > xColumnSupp;
+ if ( _bFromComposer )
+ xColumnSupp.set(m_xComposer, css::uno::UNO_QUERY);
+ else
+ xColumnSupp.set( m_xComponent.get(),UNO_QUERY);
+ if ( xColumnSupp.is() )
+ _rxColumns = xColumnSupp->getColumns();
+ OSL_ENSURE( _rxColumns.is(), "ParameterManager::getColumns: could not retrieve the columns for the detail !" );
+
+ return _rxColumns.is();
+ }
+
+
+ bool ParameterManager::getParentColumns( Reference< XNameAccess >& /* [out] */ _out_rxParentColumns, bool _bFromComposer )
+ {
+ OSL_PRECOND( isAlive(), "ParameterManager::getParentColumns: not initialized, or already disposed!" );
+
+ _out_rxParentColumns.clear();
+ try
+ {
+ // get the parent of the component we're working for
+ Reference< XChild > xAsChild( m_xComponent.get(), UNO_QUERY_THROW );
+ Reference< XPropertySet > xParent( xAsChild->getParent(), UNO_QUERY );
+ if ( !xParent.is() )
+ return false;
+
+ // the columns supplier: either from a composer, or directly from the
+ Reference< XColumnsSupplier > xParentColSupp;
+ if ( _bFromComposer )
+ {
+ // re-create the parent composer all the time. Else, we'd have to bother with
+ // being a listener at its properties, its loaded state, and event the parent-relationship.
+ m_xParentComposer.reset(
+ getCurrentSettingsComposer( xParent, m_xContext, nullptr ),
+ SharedQueryComposer::TakeOwnership
+ );
+ xParentColSupp.set(m_xParentComposer, css::uno::UNO_QUERY);
+ }
+ else
+ xParentColSupp.set(xParent, css::uno::UNO_QUERY);
+
+ // get the columns of the parent
+ if ( xParentColSupp.is() )
+ _out_rxParentColumns = xParentColSupp->getColumns();
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "connectivity.commontools", "ParameterManager::getParentColumns" );
+ }
+ return _out_rxParentColumns.is();
+ }
+
+
+ void ParameterManager::addParameterListener( const Reference< XDatabaseParameterListener >& _rxListener )
+ {
+ if ( _rxListener.is() )
+ m_aParameterListeners.addInterface( _rxListener );
+ }
+
+
+ void ParameterManager::removeParameterListener( const Reference< XDatabaseParameterListener >& _rxListener )
+ {
+ m_aParameterListeners.removeInterface( _rxListener );
+ }
+
+
+ void ParameterManager::resetParameterValues( )
+ {
+ OSL_PRECOND( isAlive(), "ParameterManager::resetParameterValues: not initialized, or already disposed!" );
+ if ( !isAlive() )
+ return;
+
+ if ( !m_nInnerCount )
+ // no parameters at all
+ return;
+
+ try
+ {
+ Reference< XNameAccess > xColumns;
+ if ( !getColumns( xColumns, false ) )
+ // already asserted in getColumns
+ return;
+
+ Reference< XNameAccess > xParentColumns;
+ if ( !getParentColumns( xParentColumns, false ) )
+ return;
+
+ // loop through all links pairs
+ auto pMasterFields = m_aMasterFields.begin();
+ auto pDetailFields = m_aDetailFields.begin();
+
+ Reference< XPropertySet > xMasterField;
+ Reference< XPropertySet > xDetailField;
+
+ // now really ....
+ auto pDetailFieldsEnd = m_aDetailFields.end();
+ for ( ; pDetailFields != pDetailFieldsEnd; ++pDetailFields, ++pMasterFields )
+ {
+ if ( !xParentColumns->hasByName( *pMasterFields ) )
+ {
+ // if this name is unknown in the parent columns, then we don't have a source
+ // for copying the value to the detail columns
+ SAL_WARN( "connectivity.commontools", "ParameterManager::resetParameterValues: this should have been stripped long before!" );
+ continue;
+ }
+
+ // for all inner parameters which are bound to the name as specified by the
+ // slave element of the link, propagate the value from the master column to this
+ // parameter column
+ ParameterInformation::const_iterator aParamInfo = m_aParameterInformation.find( *pDetailFields );
+ if ( ( aParamInfo == m_aParameterInformation.end() )
+ || ( aParamInfo->second.aInnerIndexes.empty() )
+ )
+ {
+ SAL_WARN( "connectivity.commontools", "ParameterManager::resetParameterValues: nothing known about this detail field!" );
+ continue;
+ }
+
+ xParentColumns->getByName( *pMasterFields ) >>= xMasterField;
+ if ( !xMasterField.is() )
+ continue;
+
+ for (auto const& aPosition : aParamInfo->second.aInnerIndexes)
+ {
+ Reference< XPropertySet > xInnerParameter;
+ m_xInnerParamColumns->getByIndex(aPosition) >>= xInnerParameter;
+ if ( !xInnerParameter.is() )
+ continue;
+
+ OUString sParamColumnRealName;
+ xInnerParameter->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_REALNAME) ) >>= sParamColumnRealName;
+ if ( xColumns->hasByName( sParamColumnRealName ) )
+ { // our own columns have a column which's name equals the real name of the param column
+ // -> transfer the value property
+ xColumns->getByName( sParamColumnRealName ) >>= xDetailField;
+ if ( xDetailField.is() )
+ xDetailField->setPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_VALUE), xMasterField->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_VALUE) ) );
+ }
+ }
+ }
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "connectivity.commontools", "ParameterManager::resetParameterValues" );
+ }
+
+ }
+
+
+ void ParameterManager::externalParameterVisited( sal_Int32 _nIndex )
+ {
+ if ( m_aParametersVisited.size() < o3tl::make_unsigned(_nIndex) )
+ {
+ m_aParametersVisited.reserve( _nIndex );
+ for ( sal_Int32 i = m_aParametersVisited.size(); i < _nIndex; ++i )
+ m_aParametersVisited.push_back( false );
+ }
+ m_aParametersVisited[ _nIndex - 1 ] = true;
+ }
+
+ void ParameterManager::setNull( sal_Int32 _nIndex, sal_Int32 sqlType )
+ {
+ ::osl::MutexGuard aGuard(m_rMutex);
+ OSL_ENSURE(m_xInnerParamUpdate.is(), "ParameterManager::XParameters::setXXX: no XParameters access to the RowSet!");
+ if (!m_xInnerParamUpdate.is())
+ return;
+ m_xInnerParamUpdate->setNull(_nIndex, sqlType);
+ externalParameterVisited(_nIndex);
+ }
+
+
+ void ParameterManager::setObjectNull( sal_Int32 _nIndex, sal_Int32 sqlType, const OUString& typeName )
+ {
+ ::osl::MutexGuard aGuard(m_rMutex);
+ OSL_ENSURE(m_xInnerParamUpdate.is(), "ParameterManager::XParameters::setXXX: no XParameters access to the RowSet!");
+ if (!m_xInnerParamUpdate.is())
+ return;
+ m_xInnerParamUpdate->setObjectNull(_nIndex, sqlType, typeName);
+ externalParameterVisited(_nIndex);
+ }
+
+
+ void ParameterManager::setBoolean( sal_Int32 _nIndex, bool x )
+ {
+ ::osl::MutexGuard aGuard(m_rMutex);
+ OSL_ENSURE(m_xInnerParamUpdate.is(), "ParameterManager::XParameters::setXXX: no XParameters access to the RowSet!");
+ if (!m_xInnerParamUpdate.is())
+ return;
+ m_xInnerParamUpdate->setBoolean(_nIndex, x);
+ externalParameterVisited(_nIndex);
+ }
+
+
+ void ParameterManager::setByte( sal_Int32 _nIndex, sal_Int8 x )
+ {
+ ::osl::MutexGuard aGuard(m_rMutex);
+ OSL_ENSURE(m_xInnerParamUpdate.is(), "ParameterManager::XParameters::setXXX: no XParameters access to the RowSet!");
+ if (!m_xInnerParamUpdate.is())
+ return;
+ m_xInnerParamUpdate->setByte(_nIndex, x);
+ externalParameterVisited(_nIndex);
+ }
+
+
+ void ParameterManager::setShort( sal_Int32 _nIndex, sal_Int16 x )
+ {
+ ::osl::MutexGuard aGuard(m_rMutex);
+ OSL_ENSURE(m_xInnerParamUpdate.is(), "ParameterManager::XParameters::setXXX: no XParameters access to the RowSet!");
+ if (!m_xInnerParamUpdate.is())
+ return;
+ m_xInnerParamUpdate->setShort(_nIndex, x);
+ externalParameterVisited(_nIndex);
+ }
+
+
+ void ParameterManager::setInt( sal_Int32 _nIndex, sal_Int32 x )
+ {
+ ::osl::MutexGuard aGuard(m_rMutex);
+ OSL_ENSURE(m_xInnerParamUpdate.is(), "ParameterManager::XParameters::setXXX: no XParameters access to the RowSet!");
+ if (!m_xInnerParamUpdate.is())
+ return;
+ m_xInnerParamUpdate->setInt(_nIndex, x);
+ externalParameterVisited(_nIndex);
+ }
+
+
+ void ParameterManager::setLong( sal_Int32 _nIndex, sal_Int64 x )
+ {
+ ::osl::MutexGuard aGuard(m_rMutex);
+ OSL_ENSURE(m_xInnerParamUpdate.is(), "ParameterManager::XParameters::setXXX: no XParameters access to the RowSet!");
+ if (!m_xInnerParamUpdate.is())
+ return;
+ m_xInnerParamUpdate->setLong(_nIndex, x);
+ externalParameterVisited(_nIndex);
+ }
+
+
+ void ParameterManager::setFloat( sal_Int32 _nIndex, float x )
+ {
+ ::osl::MutexGuard aGuard(m_rMutex);
+ OSL_ENSURE(m_xInnerParamUpdate.is(), "ParameterManager::XParameters::setXXX: no XParameters access to the RowSet!");
+ if (!m_xInnerParamUpdate.is())
+ return;
+ m_xInnerParamUpdate->setFloat(_nIndex, x);
+ externalParameterVisited(_nIndex);
+ }
+
+
+ void ParameterManager::setDouble( sal_Int32 _nIndex, double x )
+ {
+ ::osl::MutexGuard aGuard(m_rMutex);
+ OSL_ENSURE(m_xInnerParamUpdate.is(), "ParameterManager::XParameters::setXXX: no XParameters access to the RowSet!");
+ if (!m_xInnerParamUpdate.is())
+ return;
+ m_xInnerParamUpdate->setDouble(_nIndex, x);
+ externalParameterVisited(_nIndex);
+ }
+
+
+ void ParameterManager::setString( sal_Int32 _nIndex, const OUString& x )
+ {
+ ::osl::MutexGuard aGuard(m_rMutex);
+ OSL_ENSURE(m_xInnerParamUpdate.is(), "ParameterManager::XParameters::setXXX: no XParameters access to the RowSet!");
+ if (!m_xInnerParamUpdate.is())
+ return;
+ m_xInnerParamUpdate->setString(_nIndex, x);
+ externalParameterVisited(_nIndex);
+ }
+
+
+ void ParameterManager::setBytes( sal_Int32 _nIndex, const css::uno::Sequence< sal_Int8 >& x )
+ {
+ ::osl::MutexGuard aGuard(m_rMutex);
+ OSL_ENSURE(m_xInnerParamUpdate.is(), "ParameterManager::XParameters::setXXX: no XParameters access to the RowSet!");
+ if (!m_xInnerParamUpdate.is())
+ return;
+ m_xInnerParamUpdate->setBytes(_nIndex, x);
+ externalParameterVisited(_nIndex);
+ }
+
+
+ void ParameterManager::setDate( sal_Int32 _nIndex, const css::util::Date& x )
+ {
+ ::osl::MutexGuard aGuard(m_rMutex);
+ OSL_ENSURE(m_xInnerParamUpdate.is(), "ParameterManager::XParameters::setXXX: no XParameters access to the RowSet!");
+ if (!m_xInnerParamUpdate.is())
+ return;
+ m_xInnerParamUpdate->setDate(_nIndex, x);
+ externalParameterVisited(_nIndex);
+ }
+
+
+ void ParameterManager::setTime( sal_Int32 _nIndex, const css::util::Time& x )
+ {
+ ::osl::MutexGuard aGuard(m_rMutex);
+ OSL_ENSURE(m_xInnerParamUpdate.is(), "ParameterManager::XParameters::setXXX: no XParameters access to the RowSet!");
+ if (!m_xInnerParamUpdate.is())
+ return;
+ m_xInnerParamUpdate->setTime(_nIndex, x);
+ externalParameterVisited(_nIndex);
+ }
+
+
+ void ParameterManager::setTimestamp( sal_Int32 _nIndex, const css::util::DateTime& x )
+ {
+ ::osl::MutexGuard aGuard(m_rMutex);
+ OSL_ENSURE(m_xInnerParamUpdate.is(), "ParameterManager::XParameters::setXXX: no XParameters access to the RowSet!");
+ if (!m_xInnerParamUpdate.is())
+ return;
+ m_xInnerParamUpdate->setTimestamp(_nIndex, x);
+ externalParameterVisited(_nIndex);
+ }
+
+
+ void ParameterManager::setBinaryStream( sal_Int32 _nIndex, const css::uno::Reference< css::io::XInputStream>& x, sal_Int32 length )
+ {
+ ::osl::MutexGuard aGuard(m_rMutex);
+ OSL_ENSURE(m_xInnerParamUpdate.is(), "ParameterManager::XParameters::setXXX: no XParameters access to the RowSet!");
+ if (!m_xInnerParamUpdate.is())
+ return;
+ m_xInnerParamUpdate->setBinaryStream(_nIndex, x, length);
+ externalParameterVisited(_nIndex);
+ }
+
+
+ void ParameterManager::setCharacterStream( sal_Int32 _nIndex, const css::uno::Reference< css::io::XInputStream>& x, sal_Int32 length )
+ {
+ ::osl::MutexGuard aGuard(m_rMutex);
+ OSL_ENSURE(m_xInnerParamUpdate.is(), "ParameterManager::XParameters::setXXX: no XParameters access to the RowSet!");
+ if (!m_xInnerParamUpdate.is())
+ return;
+ m_xInnerParamUpdate->setCharacterStream(_nIndex, x, length);
+ externalParameterVisited(_nIndex);
+ }
+
+
+ void ParameterManager::setObject( sal_Int32 _nIndex, const css::uno::Any& x )
+ {
+ ::osl::MutexGuard aGuard(m_rMutex);
+ OSL_ENSURE(m_xInnerParamUpdate.is(), "ParameterManager::XParameters::setXXX: no XParameters access to the RowSet!");
+ if (!m_xInnerParamUpdate.is())
+ return;
+ m_xInnerParamUpdate->setObject(_nIndex, x);
+ externalParameterVisited(_nIndex);
+ }
+
+
+ void ParameterManager::setObjectWithInfo( sal_Int32 _nIndex, const css::uno::Any& x, sal_Int32 targetSqlType, sal_Int32 scale )
+ {
+ ::osl::MutexGuard aGuard(m_rMutex);
+ OSL_ENSURE(m_xInnerParamUpdate.is(), "ParameterManager::XParameters::setXXX: no XParameters access to the RowSet!");
+ if (!m_xInnerParamUpdate.is())
+ return;
+ m_xInnerParamUpdate->setObjectWithInfo(_nIndex, x, targetSqlType, scale);
+ externalParameterVisited(_nIndex);
+ }
+
+
+ void ParameterManager::setRef( sal_Int32 _nIndex, const css::uno::Reference< css::sdbc::XRef>& x )
+ {
+ ::osl::MutexGuard aGuard(m_rMutex);
+ OSL_ENSURE(m_xInnerParamUpdate.is(), "ParameterManager::XParameters::setXXX: no XParameters access to the RowSet!");
+ if (!m_xInnerParamUpdate.is())
+ return;
+ m_xInnerParamUpdate->setRef(_nIndex, x);
+ externalParameterVisited(_nIndex);
+ }
+
+
+ void ParameterManager::setBlob( sal_Int32 _nIndex, const css::uno::Reference< css::sdbc::XBlob>& x )
+ {
+ ::osl::MutexGuard aGuard(m_rMutex);
+ OSL_ENSURE(m_xInnerParamUpdate.is(), "ParameterManager::XParameters::setXXX: no XParameters access to the RowSet!");
+ if (!m_xInnerParamUpdate.is())
+ return;
+ m_xInnerParamUpdate->setBlob(_nIndex, x);
+ externalParameterVisited(_nIndex);
+ }
+
+
+ void ParameterManager::setClob( sal_Int32 _nIndex, const css::uno::Reference< css::sdbc::XClob>& x )
+ {
+ ::osl::MutexGuard aGuard(m_rMutex);
+ OSL_ENSURE(m_xInnerParamUpdate.is(), "ParameterManager::XParameters::setXXX: no XParameters access to the RowSet!");
+ if (!m_xInnerParamUpdate.is())
+ return;
+ m_xInnerParamUpdate->setClob(_nIndex, x);
+ externalParameterVisited(_nIndex);
+ }
+
+
+ void ParameterManager::setArray( sal_Int32 _nIndex, const css::uno::Reference< css::sdbc::XArray>& x )
+ {
+ ::osl::MutexGuard aGuard(m_rMutex);
+ OSL_ENSURE(m_xInnerParamUpdate.is(), "ParameterManager::XParameters::setXXX: no XParameters access to the RowSet!");
+ if (!m_xInnerParamUpdate.is())
+ return;
+ m_xInnerParamUpdate->setArray(_nIndex, x);
+ externalParameterVisited(_nIndex);
+ }
+
+
+ void ParameterManager::clearParameters( )
+ {
+ if ( m_xInnerParamUpdate.is() )
+ m_xInnerParamUpdate->clearParameters( );
+ }
+
+ void SAL_CALL OParameterContinuation::setParameters( const Sequence< PropertyValue >& _rValues )
+ {
+ m_aValues = _rValues;
+ }
+
+
+} // namespace frm
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/commontools/paramwrapper.cxx b/connectivity/source/commontools/paramwrapper.cxx
new file mode 100644
index 0000000000..e25a3e7b49
--- /dev/null
+++ b/connectivity/source/commontools/paramwrapper.cxx
@@ -0,0 +1,345 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#include <connectivity/paramwrapper.hxx>
+
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <com/sun/star/sdbc/XParameters.hpp>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <com/sun/star/lang/WrappedTargetException.hpp>
+#include <com/sun/star/sdb/XParametersSupplier.hpp>
+#include <com/sun/star/sdb/XSingleSelectQueryAnalyzer.hpp>
+#include <com/sun/star/lang/DisposedException.hpp>
+
+#include <o3tl/safeint.hxx>
+#include <comphelper/diagnose_ex.hxx>
+#include <comphelper/enumhelper.hxx>
+
+#define PROPERTY_ID_VALUE 1000
+
+
+namespace dbtools::param
+{
+
+
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::sdbc::XParameters;
+ using ::com::sun::star::uno::Sequence;
+ using ::com::sun::star::uno::Type;
+ using ::com::sun::star::uno::RuntimeException;
+ using ::com::sun::star::uno::XWeak;
+ using ::com::sun::star::beans::XPropertySet;
+ using ::com::sun::star::beans::XFastPropertySet;
+ using ::com::sun::star::beans::XMultiPropertySet;
+ using ::com::sun::star::beans::XPropertySetInfo;
+ using ::com::sun::star::beans::Property;
+ using ::com::sun::star::uno::Exception;
+ using ::com::sun::star::uno::UNO_QUERY_THROW;
+ using ::com::sun::star::uno::Any;
+ using ::com::sun::star::sdbc::SQLException;
+ using ::com::sun::star::lang::WrappedTargetException;
+ using ::com::sun::star::lang::IndexOutOfBoundsException;
+ using ::com::sun::star::container::XEnumeration;
+ using ::com::sun::star::sdb::XSingleSelectQueryAnalyzer;
+ using ::com::sun::star::sdb::XParametersSupplier;
+ using ::com::sun::star::lang::DisposedException;
+
+ namespace PropertyAttribute = ::com::sun::star::beans::PropertyAttribute;
+ namespace DataType = ::com::sun::star::sdbc::DataType;
+
+ ParameterWrapper::ParameterWrapper( const Reference< XPropertySet >& _rxColumn )
+ :PropertyBase( m_aBHelper )
+ ,m_xDelegator( _rxColumn )
+ {
+ if ( m_xDelegator.is() )
+ m_xDelegatorPSI = m_xDelegator->getPropertySetInfo();
+ if ( !m_xDelegatorPSI.is() )
+ throw RuntimeException();
+ }
+
+
+ ParameterWrapper::ParameterWrapper( const Reference< XPropertySet >& _rxColumn,
+ const Reference< XParameters >& _rxAllParameters, std::vector< sal_Int32 >&& _rIndexes )
+ :PropertyBase( m_aBHelper )
+ ,m_aIndexes( std::move(_rIndexes) )
+ ,m_xDelegator( _rxColumn )
+ ,m_xValueDestination( _rxAllParameters )
+ {
+ if ( m_xDelegator.is() )
+ m_xDelegatorPSI = m_xDelegator->getPropertySetInfo();
+ if ( !m_xDelegatorPSI.is() )
+ throw RuntimeException();
+
+ OSL_ENSURE( !m_aIndexes.empty(), "ParameterWrapper::ParameterWrapper: sure about the indexes?" );
+ }
+
+
+ ParameterWrapper::~ParameterWrapper()
+ {
+ }
+
+
+ IMPLEMENT_FORWARD_REFCOUNT( ParameterWrapper, UnoBase )
+
+ css::uno::Any ParameterWrapper::queryInterface(css::uno::Type const & aType)
+ {
+ css::uno::Any a(UnoBase::queryInterface(aType));
+ if (!a.hasValue()) {
+ a = PropertyBase::queryInterface(aType);
+ if (!a.hasValue()
+ && aType == cppu::UnoType<css::lang::XTypeProvider>::get())
+ {
+ a <<= css::uno::Reference<css::lang::XTypeProvider>(this);
+ }
+ }
+ return a;
+ }
+
+
+ Sequence< Type > SAL_CALL ParameterWrapper::getTypes( )
+ {
+ return Sequence< Type > {
+ cppu::UnoType<XWeak>::get(),
+ cppu::UnoType<XTypeProvider>::get(),
+ cppu::UnoType<XPropertySet>::get(),
+ cppu::UnoType<XFastPropertySet>::get(),
+ cppu::UnoType<XMultiPropertySet>::get()
+ };
+ }
+
+
+ IMPLEMENT_GET_IMPLEMENTATION_ID( ParameterWrapper )
+
+
+ OUString ParameterWrapper::impl_getPseudoAggregatePropertyName( sal_Int32 _nHandle ) const
+ {
+ Reference< XPropertySetInfo > xInfo = const_cast<ParameterWrapper*>( this )->getPropertySetInfo();
+ const css::uno::Sequence<Property> aProperties = xInfo->getProperties();
+ for ( const Property& rProperty : aProperties )
+ {
+ if ( rProperty.Handle == _nHandle )
+ return rProperty.Name;
+ }
+
+ OSL_FAIL( "ParameterWrapper::impl_getPseudoAggregatePropertyName: invalid argument!" );
+ return OUString();
+ }
+
+
+ Reference< XPropertySetInfo > ParameterWrapper::getPropertySetInfo()
+ {
+ return createPropertySetInfo( getInfoHelper() );
+ }
+
+
+ ::cppu::IPropertyArrayHelper& ParameterWrapper::getInfoHelper()
+ {
+ if (!m_pInfoHelper)
+ {
+ Sequence< Property > aProperties;
+ try
+ {
+ aProperties = m_xDelegatorPSI->getProperties();
+ sal_Int32 nProperties( aProperties.getLength() );
+ aProperties.realloc( nProperties + 1 );
+ aProperties.getArray()[ nProperties ] = Property(
+ "Value",
+ PROPERTY_ID_VALUE,
+ ::cppu::UnoType< Any >::get(),
+ PropertyAttribute::TRANSIENT | PropertyAttribute::MAYBEVOID
+ );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("connectivity.commontools");
+ }
+
+ m_pInfoHelper.reset( new ::cppu::OPropertyArrayHelper( aProperties, false ) );
+ }
+ return *m_pInfoHelper;
+ }
+
+
+ sal_Bool ParameterWrapper::convertFastPropertyValue(Any& rConvertedValue, Any& rOldValue, sal_Int32 nHandle, const Any& rValue)
+ {
+ OSL_ENSURE( PROPERTY_ID_VALUE == nHandle, "ParameterWrapper::convertFastPropertyValue: the only non-readonly prop should be our PROPERTY_VALUE!" );
+
+ // we're lazy here ...
+ rOldValue = m_aValue.makeAny();
+ rConvertedValue = rValue;
+ return true; // assume "modified" ...
+ }
+
+
+ void ParameterWrapper::setFastPropertyValue_NoBroadcast( sal_Int32 nHandle, const Any& rValue )
+ {
+ if ( nHandle == PROPERTY_ID_VALUE )
+ {
+ try
+ {
+ // TODO : aParamType & nScale can be obtained within the constructor...
+ sal_Int32 nParamType = DataType::VARCHAR;
+ OSL_VERIFY( m_xDelegator->getPropertyValue("Type") >>= nParamType );
+
+ sal_Int32 nScale = 0;
+ if ( m_xDelegatorPSI->hasPropertyByName("Scale") )
+ OSL_VERIFY( m_xDelegator->getPropertyValue("Scale") >>= nScale );
+
+ if ( m_xValueDestination.is() )
+ {
+ for ( const auto& rIndex : m_aIndexes )
+ {
+ m_xValueDestination->setObjectWithInfo( rIndex + 1, rValue, nParamType, nScale );
+ // (the index of the parameters is one-based)
+ }
+ }
+
+ m_aValue = rValue;
+ }
+ catch( SQLException& e )
+ {
+ throw WrappedTargetException(e.Message, e.Context, css::uno::Any(e));
+ }
+ }
+ else
+ {
+ OUString aName = impl_getPseudoAggregatePropertyName( nHandle );
+ m_xDelegator->setPropertyValue( aName, rValue );
+ }
+ }
+
+
+ void ParameterWrapper::getFastPropertyValue( Any& rValue, sal_Int32 nHandle ) const
+ {
+ if ( nHandle == PROPERTY_ID_VALUE )
+ {
+ rValue = m_aValue.makeAny();
+ }
+ else
+ {
+ OUString aName = impl_getPseudoAggregatePropertyName( nHandle );
+ rValue = m_xDelegator->getPropertyValue( aName );
+ }
+ }
+
+
+ void ParameterWrapper::dispose()
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ m_aValue.setNull();
+ m_aIndexes.resize(0);
+ m_xDelegator.clear();
+ m_xDelegatorPSI.clear();
+ m_xValueDestination.clear();
+
+ m_aBHelper.bDisposed = true;
+ }
+
+ ParameterWrapperContainer::ParameterWrapperContainer()
+ {
+ }
+
+
+ ParameterWrapperContainer::ParameterWrapperContainer( const Reference< XSingleSelectQueryAnalyzer >& _rxComposer )
+ {
+ Reference< XParametersSupplier > xSuppParams( _rxComposer, UNO_QUERY_THROW );
+ Reference< XIndexAccess > xParameters( xSuppParams->getParameters(), css::uno::UNO_SET_THROW );
+ sal_Int32 nParamCount( xParameters->getCount() );
+ m_aParameters.reserve( nParamCount );
+ for ( sal_Int32 i=0; i<nParamCount; ++i )
+ {
+ m_aParameters.push_back( new ParameterWrapper( Reference< XPropertySet >( xParameters->getByIndex( i ), UNO_QUERY_THROW ) ) );
+ }
+ }
+
+
+ ParameterWrapperContainer::~ParameterWrapperContainer()
+ {
+ }
+
+
+ Type SAL_CALL ParameterWrapperContainer::getElementType()
+ {
+ std::unique_lock aGuard( m_aMutex );
+ impl_checkDisposed_throw();
+ return cppu::UnoType<XPropertySet>::get();
+ }
+
+
+ sal_Bool SAL_CALL ParameterWrapperContainer::hasElements()
+ {
+ std::unique_lock aGuard( m_aMutex );
+ impl_checkDisposed_throw();
+ return !m_aParameters.empty();
+ }
+
+
+ sal_Int32 SAL_CALL ParameterWrapperContainer::getCount()
+ {
+ std::unique_lock aGuard( m_aMutex );
+ impl_checkDisposed_throw();
+ return m_aParameters.size();
+ }
+
+
+ Any SAL_CALL ParameterWrapperContainer::getByIndex( sal_Int32 _nIndex )
+ {
+ std::unique_lock aGuard( m_aMutex );
+ impl_checkDisposed_throw();
+
+ if ( ( _nIndex < 0 ) || ( o3tl::make_unsigned(_nIndex) >= m_aParameters.size() ) )
+ throw IndexOutOfBoundsException();
+
+ return Any( Reference< XPropertySet >( m_aParameters[ _nIndex ] ) );
+ }
+
+
+ Reference< XEnumeration > ParameterWrapperContainer::createEnumeration()
+ {
+ std::unique_lock aGuard( m_aMutex );
+ impl_checkDisposed_throw();
+
+ return new ::comphelper::OEnumerationByIndex( static_cast< XIndexAccess* >( this ) );
+ }
+
+
+ void ParameterWrapperContainer::impl_checkDisposed_throw()
+ {
+ if ( m_bDisposed )
+ throw DisposedException( OUString(), *this );
+ }
+
+
+ void ParameterWrapperContainer::disposing(std::unique_lock<std::mutex>& /*rGuard*/)
+ {
+ for (const auto& rxParam : m_aParameters)
+ {
+ rxParam->dispose();
+ }
+
+ Parameters().swap(m_aParameters);
+ }
+
+
+} // namespace
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/commontools/predicateinput.cxx b/connectivity/source/commontools/predicateinput.cxx
new file mode 100644
index 0000000000..cbeaf511a9
--- /dev/null
+++ b/connectivity/source/commontools/predicateinput.cxx
@@ -0,0 +1,411 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <connectivity/predicateinput.hxx>
+#include <comphelper/types.hxx>
+#include <connectivity/dbtools.hxx>
+#include <com/sun/star/i18n/LocaleData.hpp>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <com/sun/star/sdbc/ColumnValue.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <com/sun/star/util/NumberFormatter.hpp>
+#include <osl/diagnose.h>
+#include <connectivity/sqlnode.hxx>
+#include <connectivity/PColumn.hxx>
+#include <comphelper/numbers.hxx>
+#include <comphelper/diagnose_ex.hxx>
+
+#include <memory>
+#include <string_view>
+
+namespace dbtools
+{
+
+
+ using ::com::sun::star::sdbc::XConnection;
+ using ::com::sun::star::util::XNumberFormatsSupplier;
+ using ::com::sun::star::util::NumberFormatter;
+ using ::com::sun::star::uno::UNO_QUERY_THROW;
+ using ::com::sun::star::uno::XComponentContext;
+ using ::com::sun::star::beans::XPropertySet;
+ using ::com::sun::star::beans::XPropertySetInfo;
+ using ::com::sun::star::lang::Locale;
+ using ::com::sun::star::uno::Exception;
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::i18n::LocaleData;
+ using ::com::sun::star::i18n::LocaleDataItem;
+ using ::com::sun::star::uno::Any;
+
+ using namespace ::com::sun::star::sdbc;
+ using namespace ::connectivity;
+
+ using ::connectivity::OSQLParseNode;
+
+
+ static sal_Unicode lcl_getSeparatorChar(
+ std::u16string_view _rSeparator, sal_Unicode _nFallback )
+ {
+ OSL_ENSURE( !_rSeparator.empty(), "::lcl_getSeparatorChar: invalid separator string!" );
+
+ sal_Unicode nReturn( _nFallback );
+ if ( !_rSeparator.empty() )
+ nReturn = _rSeparator[0];
+ return nReturn;
+ }
+
+ bool OPredicateInputController::getSeparatorChars( const Locale& _rLocale, sal_Unicode& _rDecSep, sal_Unicode& _rThdSep ) const
+ {
+ _rDecSep = '.';
+ _rThdSep = ',';
+ try
+ {
+ LocaleDataItem aLocaleData;
+ if ( m_xLocaleData.is() )
+ {
+ aLocaleData = m_xLocaleData->getLocaleItem( _rLocale );
+ _rDecSep = lcl_getSeparatorChar( aLocaleData.decimalSeparator, _rDecSep );
+ _rThdSep = lcl_getSeparatorChar( aLocaleData.thousandSeparator, _rThdSep );
+ return true;
+ }
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "connectivity.commontools", "OPredicateInputController::getSeparatorChars" );
+ }
+ return false;
+ }
+
+
+ OPredicateInputController::OPredicateInputController(
+ const Reference< XComponentContext >& rxContext, const Reference< XConnection >& _rxConnection, const IParseContext* _pParseContext )
+ : m_xConnection( _rxConnection )
+ ,m_aParser( rxContext, _pParseContext )
+ {
+ try
+ {
+ // create a number formatter / number formats supplier pair
+ OSL_ENSURE( rxContext.is(), "OPredicateInputController::OPredicateInputController: need a service factory!" );
+ if ( rxContext.is() )
+ {
+ m_xFormatter.set( NumberFormatter::create(rxContext), UNO_QUERY_THROW );
+ }
+
+ Reference< XNumberFormatsSupplier > xNumberFormats = ::dbtools::getNumberFormats( m_xConnection, true );
+ if ( !xNumberFormats.is() )
+ ::comphelper::disposeComponent( m_xFormatter );
+ else
+ m_xFormatter->attachNumberFormatsSupplier( xNumberFormats );
+
+ // create the locale data
+ if ( rxContext.is() )
+ {
+ m_xLocaleData = LocaleData::create( rxContext );
+ }
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "connectivity.commontools", "OPredicateInputController::OPredicateInputController" );
+ }
+ }
+
+
+ std::unique_ptr<OSQLParseNode> OPredicateInputController::implPredicateTree(OUString& _rErrorMessage, const OUString& _rStatement, const Reference< XPropertySet > & _rxField) const
+ {
+ std::unique_ptr<OSQLParseNode> pReturn = const_cast< OSQLParser& >( m_aParser ).predicateTree( _rErrorMessage, _rStatement, m_xFormatter, _rxField );
+ if ( !pReturn )
+ { // is it a text field ?
+ sal_Int32 nType = DataType::OTHER;
+ _rxField->getPropertyValue("Type") >>= nType;
+
+ if ( ( DataType::CHAR == nType )
+ || ( DataType::VARCHAR == nType )
+ || ( DataType::LONGVARCHAR == nType )
+ || ( DataType::CLOB == nType )
+ )
+ { // yes -> force a quoted text and try again
+ OUString sQuoted( _rStatement );
+ if ( !sQuoted.isEmpty()
+ && ( !sQuoted.startsWith("'")
+ || !sQuoted.endsWith("'")
+ )
+ )
+ {
+ sQuoted = u"'" + sQuoted.replaceAll(u"'", u"''") + u"'";
+ }
+ pReturn = const_cast< OSQLParser& >( m_aParser ).predicateTree( _rErrorMessage, sQuoted, m_xFormatter, _rxField );
+ }
+
+ // one more fallback: for numeric fields, and value strings containing a decimal/thousands separator
+ // problem which is to be solved with this:
+ // * a system locale "german"
+ // * a column formatted with an english number format
+ // => the output is german (as we use the system locale for this), i.e. "3,4"
+ // => the input does not recognize the german text, as predicateTree uses the number format
+ // of the column to determine the main locale - the locale on the context is only a fallback
+ if ( ( DataType::FLOAT == nType )
+ || ( DataType::REAL == nType )
+ || ( DataType::DOUBLE == nType )
+ || ( DataType::NUMERIC == nType )
+ || ( DataType::DECIMAL == nType )
+ )
+ {
+ const IParseContext& rParseContext = m_aParser.getContext();
+ // get the separators for the locale of our parse context
+ sal_Unicode nCtxDecSep;
+ sal_Unicode nCtxThdSep;
+ getSeparatorChars( rParseContext.getPreferredLocale(), nCtxDecSep, nCtxThdSep );
+
+ // determine the locale of the column we're building a predicate string for
+ sal_Unicode nFmtDecSep( nCtxDecSep );
+ sal_Unicode nFmtThdSep( nCtxThdSep );
+ try
+ {
+ Reference< XPropertySetInfo > xPSI( _rxField->getPropertySetInfo() );
+ if ( xPSI.is() && xPSI->hasPropertyByName("FormatKey") )
+ {
+ sal_Int32 nFormatKey = 0;
+ _rxField->getPropertyValue("FormatKey") >>= nFormatKey;
+ if ( nFormatKey && m_xFormatter.is() )
+ {
+ Locale aFormatLocale;
+ ::comphelper::getNumberFormatProperty(
+ m_xFormatter,
+ nFormatKey,
+ "Locale"
+ ) >>= aFormatLocale;
+
+ // valid locale
+ if ( !aFormatLocale.Language.isEmpty() )
+ {
+ getSeparatorChars( aFormatLocale, nFmtDecSep, nCtxThdSep );
+ }
+ }
+ }
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "connectivity.commontools", "OPredicateInputController::implPredicateTree: caught an exception while dealing with the formats!" );
+ }
+
+ bool bDecDiffers = ( nCtxDecSep != nFmtDecSep );
+ bool bFmtDiffers = ( nCtxThdSep != nFmtThdSep );
+ if ( bDecDiffers || bFmtDiffers )
+ { // okay, at least one differs
+ // "translate" the value into the "format locale"
+ OUString sTranslated( _rStatement );
+ const sal_Unicode nIntermediate( '_' );
+ sTranslated = sTranslated.replace( nCtxDecSep, nIntermediate );
+ sTranslated = sTranslated.replace( nCtxThdSep, nFmtThdSep );
+ sTranslated = sTranslated.replace( nIntermediate, nFmtDecSep );
+
+ pReturn = const_cast< OSQLParser& >( m_aParser ).predicateTree( _rErrorMessage, sTranslated, m_xFormatter, _rxField );
+ }
+ }
+ }
+ return pReturn;
+ }
+
+
+ bool OPredicateInputController::normalizePredicateString(
+ OUString& _rPredicateValue, const Reference< XPropertySet > & _rxField, OUString* _pErrorMessage ) const
+ {
+ OSL_ENSURE( m_xConnection.is() && m_xFormatter.is() && _rxField.is(),
+ "OPredicateInputController::normalizePredicateString: invalid state or params!" );
+
+ bool bSuccess = false;
+ if ( m_xConnection.is() && m_xFormatter.is() && _rxField.is() )
+ {
+ // parse the string
+ OUString sError;
+ OUString sTransformedText( _rPredicateValue );
+ std::unique_ptr<OSQLParseNode> pParseNode = implPredicateTree( sError, sTransformedText, _rxField );
+ if ( _pErrorMessage ) *_pErrorMessage = sError;
+
+ if ( pParseNode )
+ {
+ const IParseContext& rParseContext = m_aParser.getContext();
+ sal_Unicode nDecSeparator, nThousandSeparator;
+ getSeparatorChars( rParseContext.getPreferredLocale(), nDecSeparator, nThousandSeparator );
+
+ // translate it back into a string
+ sTransformedText.clear();
+ pParseNode->parseNodeToPredicateStr(
+ sTransformedText, m_xConnection, m_xFormatter, _rxField, OUString(),
+ rParseContext.getPreferredLocale(), OUString(nDecSeparator), &rParseContext
+ );
+ _rPredicateValue = sTransformedText;
+
+ bSuccess = true;
+ }
+ }
+
+ return bSuccess;
+ }
+
+
+ OUString OPredicateInputController::getPredicateValueStr(
+ const OUString& _rPredicateValue, const Reference< XPropertySet > & _rxField ) const
+ {
+ OSL_ENSURE( _rxField.is(), "OPredicateInputController::getPredicateValue: invalid params!" );
+ OUString sReturn;
+ if ( _rxField.is() )
+ {
+ // The following is mostly stolen from the former implementation in the parameter dialog
+ // (dbaccess/source/ui/dlg/paramdialog.cxx). I do not fully understand this...
+
+ OUString sError;
+ std::unique_ptr<OSQLParseNode> pParseNode = implPredicateTree( sError, _rPredicateValue, _rxField );
+
+ implParseNode(std::move(pParseNode), true) >>= sReturn;
+ }
+
+ return sReturn;
+ }
+
+ OUString OPredicateInputController::getPredicateValueStr(
+ const OUString& _sField, const OUString& _rPredicateValue ) const
+ {
+ OUString sReturn = _rPredicateValue;
+ OUString sError;
+ sal_Int32 nIndex = 0;
+ OUString sField = _sField.getToken(0, '(', nIndex);
+ if(nIndex == -1)
+ sField = _sField;
+ sal_Int32 nType = ::connectivity::OSQLParser::getFunctionReturnType(sField,&m_aParser.getContext());
+ if ( nType == DataType::OTHER || sField.isEmpty() )
+ {
+ // first try the international version
+ OUString sSql = "SELECT * FROM x WHERE " + sField + _rPredicateValue;
+ const_cast< OSQLParser& >( m_aParser ).parseTree( sError, sSql, true );
+ nType = DataType::DOUBLE;
+ }
+
+ Reference<XDatabaseMetaData> xMeta = m_xConnection->getMetaData();
+ rtl::Reference<parse::OParseColumn> pColumn = new parse::OParseColumn( sField,
+ OUString(),
+ OUString(),
+ OUString(),
+ ColumnValue::NULLABLE_UNKNOWN,
+ 0,
+ 0,
+ nType,
+ false,
+ false,
+ xMeta.is() && xMeta->supportsMixedCaseQuotedIdentifiers(),
+ OUString(),
+ OUString(),
+ OUString());
+ Reference<XPropertySet> xColumn = pColumn;
+ pColumn->setFunction(true);
+ pColumn->setRealName(sField);
+
+ std::unique_ptr<OSQLParseNode> pParseNode = implPredicateTree( sError, _rPredicateValue, xColumn );
+ if(pParseNode)
+ {
+ implParseNode(std::move(pParseNode), true) >>= sReturn;
+ }
+ return sReturn;
+ }
+
+ Any OPredicateInputController::getPredicateValue(
+ const OUString& _rPredicateValue, const Reference< XPropertySet > & _rxField ) const
+ {
+ OSL_ENSURE( _rxField.is(), "OPredicateInputController::getPredicateValue: invalid params!" );
+
+ if ( _rxField.is() )
+ {
+ // The following is mostly stolen from the former implementation in the parameter dialog
+ // (dbaccess/source/ui/dlg/paramdialog.cxx). I do not fully understand this...
+
+ OUString sError;
+ std::unique_ptr<OSQLParseNode> pParseNode = implPredicateTree( sError, _rPredicateValue, _rxField );
+
+ return implParseNode(std::move(pParseNode), false);
+ }
+
+ return Any();
+ }
+
+ Any OPredicateInputController::implParseNode(std::unique_ptr<OSQLParseNode> pParseNode, bool _bForStatementUse) const
+ {
+ if ( ! pParseNode )
+ return Any();
+ else
+ {
+ OUString sReturn;
+ OSQLParseNode* pOdbcSpec = pParseNode->getByRule( OSQLParseNode::odbc_fct_spec );
+ if ( pOdbcSpec )
+ {
+ if ( _bForStatementUse )
+ {
+ OSQLParseNode* pFuncSpecParent = pOdbcSpec->getParent();
+ OSL_ENSURE( pFuncSpecParent, "OPredicateInputController::getPredicateValue: an ODBC func spec node without parent?" );
+ if ( pFuncSpecParent )
+ pFuncSpecParent->parseNodeToStr(sReturn, m_xConnection, &m_aParser.getContext());
+ }
+ else
+ {
+ OSQLParseNode* pValueNode = pOdbcSpec->getChild(1);
+ if ( SQLNodeType::String == pValueNode->getNodeType() )
+ sReturn = pValueNode->getTokenValue();
+ else
+ pValueNode->parseNodeToStr(sReturn, m_xConnection, &m_aParser.getContext());
+ }
+ }
+ else
+ {
+ if (pParseNode->getKnownRuleID() == OSQLParseNode::test_for_null )
+ {
+ assert(pParseNode->count() == 2);
+ return Any();
+ }
+ // LEM this seems overly permissive as test...
+ else if (pParseNode->count() >= 3)
+ {
+ OSQLParseNode* pValueNode = pParseNode->getChild(2);
+ assert(pValueNode && "OPredicateInputController::getPredicateValue: invalid node child!");
+ if ( !_bForStatementUse )
+ {
+ if ( SQLNodeType::String == pValueNode->getNodeType() )
+ sReturn = pValueNode->getTokenValue();
+ else
+ pValueNode->parseNodeToStr(
+ sReturn, m_xConnection, &m_aParser.getContext()
+ );
+ }
+ else
+ pValueNode->parseNodeToStr(
+ sReturn, m_xConnection, &m_aParser.getContext()
+ );
+ }
+ else
+ {
+ OSL_FAIL( "OPredicateInputController::getPredicateValue: unknown/invalid structure (noodbc)!" );
+ return Any();
+ }
+ }
+ return Any(sReturn);
+ }
+ }
+
+} // namespace dbtools
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/commontools/propertyids.cxx b/connectivity/source/commontools/propertyids.cxx
new file mode 100644
index 0000000000..cedd0f5f06
--- /dev/null
+++ b/connectivity/source/commontools/propertyids.cxx
@@ -0,0 +1,104 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <propertyids.hxx>
+
+namespace dbtools
+{
+ OPropertyMap::OPropertyMap()
+ {
+ // MSVC complains about ambiguous operator=
+ m_aPropertyMap.insert({
+ {PROPERTY_ID_QUERYTIMEOUT, "QueryTimeOut"},
+ {PROPERTY_ID_MAXFIELDSIZE, "MaxFieldSize"},
+ {PROPERTY_ID_MAXROWS, "MaxRows"},
+ {PROPERTY_ID_CURSORNAME, "CursorName"},
+ {PROPERTY_ID_RESULTSETCONCURRENCY, "ResultSetConcurrency"},
+
+ {PROPERTY_ID_RESULTSETTYPE, "ResultSetType"},
+ {PROPERTY_ID_FETCHDIRECTION, "FetchDirection"},
+ {PROPERTY_ID_FETCHSIZE, "FetchSize"},
+ {PROPERTY_ID_ESCAPEPROCESSING, "EscapeProcessing"},
+ {PROPERTY_ID_USEBOOKMARKS, "UseBookmarks"},
+ // Column
+ {PROPERTY_ID_NAME, "Name"},
+ {PROPERTY_ID_TYPE, "Type"},
+ {PROPERTY_ID_TYPENAME, "TypeName"},
+ {PROPERTY_ID_PRECISION, "Precision"},
+ {PROPERTY_ID_SCALE, "Scale"},
+ {PROPERTY_ID_ISNULLABLE, "IsNullable"},
+ {PROPERTY_ID_ISAUTOINCREMENT, "IsAutoIncrement"},
+ {PROPERTY_ID_ISROWVERSION, "IsRowVersion"},
+ {PROPERTY_ID_DESCRIPTION, "Description"},
+ {PROPERTY_ID_DEFAULTVALUE, "DefaultValue"},
+
+ {PROPERTY_ID_REFERENCEDTABLE, "ReferencedTable"},
+ {PROPERTY_ID_UPDATERULE, "UpdateRule"},
+ {PROPERTY_ID_DELETERULE, "DeleteRule"},
+ {PROPERTY_ID_CATALOG, "Catalog"},
+ {PROPERTY_ID_ISUNIQUE, "IsUnique"},
+ {PROPERTY_ID_ISPRIMARYKEYINDEX, "IsPrimaryKeyIndex"},
+ {PROPERTY_ID_ISCLUSTERED, "IsClustered"},
+ {PROPERTY_ID_ISASCENDING, "IsAscending"},
+ {PROPERTY_ID_SCHEMANAME, "SchemaName"},
+ {PROPERTY_ID_CATALOGNAME, "CatalogName"},
+
+ {PROPERTY_ID_COMMAND, "Command"},
+ {PROPERTY_ID_CHECKOPTION, "CheckOption"},
+ {PROPERTY_ID_PASSWORD, "Password"},
+ {PROPERTY_ID_RELATEDCOLUMN, "RelatedColumn"},
+
+ {PROPERTY_ID_FUNCTION, "Function"},
+ {PROPERTY_ID_AGGREGATEFUNCTION, "AggregateFunction"},
+ {PROPERTY_ID_TABLENAME, "TableName"},
+ {PROPERTY_ID_REALNAME, "RealName"},
+ {PROPERTY_ID_DBASEPRECISIONCHANGED,"DbasePrecisionChanged"},
+ {PROPERTY_ID_ISCURRENCY, "IsCurrency"},
+ {PROPERTY_ID_ISBOOKMARKABLE, "IsBookmarkable"},
+ {PROPERTY_ID_HY010, "HY010"}, // error messages
+ {PROPERTY_ID_DELIMITER, "/"},
+ {PROPERTY_ID_FORMATKEY, "FormatKey"},
+ {PROPERTY_ID_LOCALE, "Locale"},
+ {PROPERTY_ID_AUTOINCREMENTCREATION, "AutoIncrementCreation"},
+ {PROPERTY_ID_PRIVILEGES, "Privileges"},
+ {PROPERTY_ID_HAVINGCLAUSE, "HavingClause"},
+ {PROPERTY_ID_ISSIGNED, "IsSigned"},
+ {PROPERTY_ID_ISSEARCHABLE, "IsSearchable"},
+ {PROPERTY_ID_LABEL, "Label"},
+ {PROPERTY_ID_APPLYFILTER, "ApplyFilter"},
+ {PROPERTY_ID_FILTER, "Filter"},
+ {PROPERTY_ID_MASTERFIELDS, "MasterFields"},
+ {PROPERTY_ID_DETAILFIELDS, "DetailFields"},
+ {PROPERTY_ID_FIELDTYPE, "FieldType"},
+ {PROPERTY_ID_VALUE, "Value"},
+ {PROPERTY_ID_ACTIVE_CONNECTION, "ActiveConnection"},
+ } );
+ }
+
+ const OUString& OPropertyMap::getNameByIndex(sal_Int32 _nIndex) const
+ {
+ std::map<sal_Int32, OUString>::const_iterator aIter = m_aPropertyMap.find(_nIndex);
+ assert(aIter != m_aPropertyMap.end());
+ return aIter->second;
+ }
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/commontools/sqlerror.cxx b/connectivity/source/commontools/sqlerror.cxx
new file mode 100644
index 0000000000..50c5968cd7
--- /dev/null
+++ b/connectivity/source/commontools/sqlerror.cxx
@@ -0,0 +1,295 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <memory>
+#include <connectivity/sqlerror.hxx>
+
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <com/sun/star/sdb/ErrorCondition.hpp>
+
+#include <cppuhelper/exc_hlp.hxx>
+#include <unotools/resmgr.hxx>
+#include <osl/diagnose.h>
+
+#include <strings.hrc>
+#include <strings.hxx>
+#include <string.h>
+
+namespace connectivity
+{
+
+
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::uno::Any;
+ using ::com::sun::star::uno::XInterface;
+ using ::com::sun::star::sdbc::SQLException;
+ using ::com::sun::star::uno::Type;
+
+ class SQLError_Impl
+ {
+ public:
+ explicit SQLError_Impl();
+
+ // versions of the public SQLError methods which are just delegated to this impl-class
+ static const OUString& getMessagePrefix();
+ OUString getErrorMessage( const ErrorCondition _eCondition, const std::optional<OUString>& _rParamValue1, const std::optional<OUString>& _rParamValue2, const std::optional<OUString>& _rParamValue3 ) const;
+ static ErrorCode getErrorCode( const ErrorCondition _eCondition );
+ void raiseException( const ErrorCondition _eCondition, const Reference< XInterface >& _rxContext, const std::optional<OUString>& _rParamValue1, const std::optional<OUString>& _rParamValue2, const std::optional<OUString>& _rParamValue3 );
+ void raiseException( const ErrorCondition _eCondition, const std::optional<OUString>& _rParamValue1, const std::optional<OUString>& _rParamValue2, const std::optional<OUString>& _rParamValue3 );
+ void raiseTypedException( const ErrorCondition _eCondition, const Reference< XInterface >& _rxContext, const Type& _rExceptionType, const std::optional<OUString>& _rParamValue1, const std::optional<OUString>& _rParamValue2, const std::optional<OUString>& _rParamValue3 );
+ SQLException getSQLException( const ErrorCondition _eCondition, const Reference< XInterface >& _rxContext, const std::optional<OUString>& _rParamValue1, const std::optional<OUString>& _rParamValue2, const std::optional<OUString>& _rParamValue3 );
+
+ private:
+ /// returns the basic error message associated with the given error condition, without any parameter replacements
+ OUString impl_getErrorMessage( ErrorCondition _eCondition ) const;
+
+ /// returns the SQLState associated with the given error condition
+ static OUString
+ impl_getSQLState( ErrorCondition _eCondition );
+
+ /// returns an SQLException describing the given error condition
+ SQLException
+ impl_buildSQLException( const ErrorCondition _eCondition, const Reference< XInterface >& _rxContext,
+ const std::optional<OUString>& _rParamValue1, const std::optional<OUString>& _rParamValue2, const std::optional<OUString>& _rParamValue3 );
+ private:
+ std::locale m_aResources;
+ };
+
+ SQLError_Impl::SQLError_Impl()
+ : m_aResources(Translate::Create("cnr"))
+ {
+ }
+
+ const OUString& SQLError_Impl::getMessagePrefix()
+ {
+ static constexpr OUString s_sMessagePrefix( u"[OOoBase]"_ustr );
+ return s_sMessagePrefix;
+ }
+
+ namespace
+ {
+
+ /** substitutes a given placeholder in the given message with the given value
+ */
+ void lcl_substitutePlaceholder(OUString& _rMessage, const char* _pPlaceholder, const std::optional<OUString>& rParamValue)
+ {
+ size_t nPlaceholderLen( strlen( _pPlaceholder ) );
+ sal_Int32 nIndex = _rMessage.indexOfAsciiL( _pPlaceholder, nPlaceholderLen );
+
+ bool bHasPlaceholder = ( nIndex != -1 );
+ bool bWantsPlaceholder = rParamValue.has_value();
+ OSL_ENSURE( bHasPlaceholder == bWantsPlaceholder, "lcl_substitutePlaceholder: placeholder where none is expected, or no placeholder where one is needed!" );
+
+ if ( bHasPlaceholder && bWantsPlaceholder )
+ _rMessage = _rMessage.replaceAt( nIndex, nPlaceholderLen, *rParamValue );
+ }
+
+ TranslateId lcl_getResourceErrorID(const ErrorCondition _eCondition)
+ {
+ switch (_eCondition)
+ {
+ case css::sdb::ErrorCondition::ROW_SET_OPERATION_VETOED:
+ return STR_ROW_SET_OPERATION_VETOED;
+ case css::sdb::ErrorCondition::PARSER_CYCLIC_SUB_QUERIES:
+ return STR_PARSER_CYCLIC_SUB_QUERIES;
+ case css::sdb::ErrorCondition::DB_OBJECT_NAME_WITH_SLASHES:
+ return STR_DB_OBJECT_NAME_WITH_SLASHES;
+ case css::sdb::ErrorCondition::DB_INVALID_SQL_NAME:
+ return STR_DB_INVALID_SQL_NAME;
+ case css::sdb::ErrorCondition::DB_QUERY_NAME_WITH_QUOTES:
+ return STR_DB_QUERY_NAME_WITH_QUOTES;
+ case css::sdb::ErrorCondition::DB_OBJECT_NAME_IS_USED:
+ return STR_DB_OBJECT_NAME_IS_USED;
+ case css::sdb::ErrorCondition::DB_NOT_CONNECTED:
+ return STR_DB_NOT_CONNECTED;
+ case css::sdb::ErrorCondition::AB_ADDRESSBOOK_NOT_FOUND:
+ return STR_AB_ADDRESSBOOK_NOT_FOUND;
+ case css::sdb::ErrorCondition::DATA_CANNOT_SELECT_UNFILTERED:
+ return STR_DATA_CANNOT_SELECT_UNFILTERED;
+ }
+ return {};
+ }
+
+ OUString lcl_getResourceState(const ErrorCondition _eCondition)
+ {
+ switch (_eCondition)
+ {
+ case css::sdb::ErrorCondition::DB_NOT_CONNECTED:
+ return STR_DB_NOT_CONNECTED_STATE;
+ case css::sdb::ErrorCondition::DATA_CANNOT_SELECT_UNFILTERED:
+ return STR_DATA_CANNOT_SELECT_UNFILTERED_STATE;
+ }
+ return OUString();
+ }
+ }
+
+ OUString SQLError_Impl::getErrorMessage( const ErrorCondition _eCondition, const std::optional<OUString>& _rParamValue1, const std::optional<OUString>& _rParamValue2, const std::optional<OUString>& _rParamValue3 ) const
+ {
+ OUString sErrorMessage( impl_getErrorMessage( _eCondition ) );
+
+ lcl_substitutePlaceholder( sErrorMessage, "$1$", _rParamValue1 );
+ lcl_substitutePlaceholder( sErrorMessage, "$2$", _rParamValue2 );
+ lcl_substitutePlaceholder( sErrorMessage, "$3$", _rParamValue3 );
+
+ return sErrorMessage;
+ }
+
+
+ ErrorCode SQLError_Impl::getErrorCode( const ErrorCondition _eCondition )
+ {
+ return 0 - ::sal::static_int_cast< ErrorCode, ErrorCondition >( _eCondition );
+ }
+
+
+ void SQLError_Impl::raiseException( const ErrorCondition _eCondition, const Reference< XInterface >& _rxContext, const std::optional<OUString>& _rParamValue1, const std::optional<OUString>& _rParamValue2, const std::optional<OUString>& _rParamValue3 )
+ {
+ raiseTypedException(
+ _eCondition,
+ _rxContext,
+ ::cppu::UnoType< SQLException >::get(),
+ _rParamValue1,
+ _rParamValue2,
+ _rParamValue3
+ );
+ }
+
+
+ void SQLError_Impl::raiseException( const ErrorCondition _eCondition, const std::optional<OUString>& _rParamValue1, const std::optional<OUString>& _rParamValue2, const std::optional<OUString>& _rParamValue3 )
+ {
+ raiseTypedException(
+ _eCondition,
+ nullptr,
+ ::cppu::UnoType< SQLException >::get(),
+ _rParamValue1,
+ _rParamValue2,
+ _rParamValue3
+ );
+ }
+
+ void SQLError_Impl::raiseTypedException( const ErrorCondition _eCondition, const Reference< XInterface >& _rxContext,
+ const Type& _rExceptionType, const std::optional<OUString>& _rParamValue1, const std::optional<OUString>& _rParamValue2, const std::optional<OUString>& _rParamValue3 )
+ {
+ if ( !::cppu::UnoType< SQLException >::get().isAssignableFrom( _rExceptionType ) )
+ throw std::bad_cast();
+
+ // default-construct an exception of the desired type
+ Any aException( nullptr, _rExceptionType );
+
+ // fill it
+ SQLException* pException = static_cast< SQLException* >( aException.pData );
+ *pException = impl_buildSQLException( _eCondition, _rxContext, _rParamValue1, _rParamValue2, _rParamValue3 );
+
+ // throw it
+ ::cppu::throwException( aException );
+ }
+
+ SQLException SQLError_Impl::getSQLException( const ErrorCondition _eCondition, const Reference< XInterface >& _rxContext,
+ const std::optional<OUString>& _rParamValue1, const std::optional<OUString>& _rParamValue2, const std::optional<OUString>& _rParamValue3 )
+ {
+ return impl_buildSQLException( _eCondition, _rxContext, _rParamValue1, _rParamValue2, _rParamValue3 );
+ }
+
+ SQLException SQLError_Impl::impl_buildSQLException( const ErrorCondition _eCondition, const Reference< XInterface >& _rxContext,
+ const std::optional<OUString>& _rParamValue1, const std::optional<OUString>& _rParamValue2, const std::optional<OUString>& _rParamValue3 )
+ {
+ return SQLException(
+ getErrorMessage( _eCondition, _rParamValue1, _rParamValue2, _rParamValue3 ),
+ _rxContext,
+ impl_getSQLState( _eCondition ),
+ getErrorCode( _eCondition ),
+ Any()
+ );
+ }
+
+ OUString SQLError_Impl::impl_getErrorMessage( ErrorCondition _eCondition ) const
+ {
+ OUString sResMessage(Translate::get(lcl_getResourceErrorID(_eCondition), m_aResources));
+ OSL_ENSURE( !sResMessage.isEmpty(), "SQLError_Impl::impl_getErrorMessage: illegal error condition, or invalid resource!" );
+ return getMessagePrefix() + " " + sResMessage;
+ }
+
+ OUString SQLError_Impl::impl_getSQLState( ErrorCondition _eCondition )
+ {
+ static constexpr OUStringLiteral DEFAULT_STATE = u"S1000";
+ OUString sState = lcl_getResourceState(_eCondition);
+ if (sState.isEmpty())
+ sState = DEFAULT_STATE;
+ return sState;
+ }
+
+ SQLError::SQLError()
+ :m_pImpl( std::make_shared<SQLError_Impl>() )
+ {
+ }
+
+
+ SQLError::~SQLError()
+ {
+ }
+
+
+ const OUString& SQLError::getMessagePrefix()
+ {
+ return SQLError_Impl::getMessagePrefix();
+ }
+
+
+ OUString SQLError::getErrorMessage( const ErrorCondition _eCondition ) const
+ {
+ return m_pImpl->getErrorMessage( _eCondition, std::optional<OUString>(), std::optional<OUString>(), std::optional<OUString>() );
+ }
+
+
+ ErrorCode SQLError::getErrorCode( const ErrorCondition _eCondition )
+ {
+ return SQLError_Impl::getErrorCode( _eCondition );
+ }
+
+
+ void SQLError::raiseException( const ErrorCondition _eCondition, const Reference< XInterface >& _rxContext, const std::optional<OUString>& _rParamValue1, const std::optional<OUString>& _rParamValue2, const std::optional<OUString>& _rParamValue3 ) const
+ {
+ m_pImpl->raiseException( _eCondition, _rxContext, _rParamValue1, _rParamValue2, _rParamValue3 );
+ }
+
+
+ void SQLError::raiseException( const ErrorCondition _eCondition ) const
+ {
+ m_pImpl->raiseException( _eCondition, std::optional<OUString>(), std::optional<OUString>(), std::optional<OUString>() );
+ }
+
+
+ void SQLError::raiseTypedException( const ErrorCondition _eCondition, const Reference< XInterface >& _rxContext,
+ const Type& _rExceptionType ) const
+ {
+ m_pImpl->raiseTypedException( _eCondition, _rxContext, _rExceptionType, std::optional<OUString>(), std::optional<OUString>(), std::optional<OUString>() );
+ }
+
+
+ SQLException SQLError::getSQLException( const ErrorCondition _eCondition, const Reference< XInterface >& _rxContext,
+ const std::optional<OUString>& _rParamValue1, const std::optional<OUString>& _rParamValue2, const std::optional<OUString>& _rParamValue3 ) const
+ {
+ return m_pImpl->getSQLException( _eCondition, _rxContext, _rParamValue1, _rParamValue2, _rParamValue3 );
+ }
+
+
+} // namespace connectivity
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/commontools/statementcomposer.cxx b/connectivity/source/commontools/statementcomposer.cxx
new file mode 100644
index 0000000000..8ebbd9ca86
--- /dev/null
+++ b/connectivity/source/commontools/statementcomposer.cxx
@@ -0,0 +1,301 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <connectivity/statementcomposer.hxx>
+
+#include <connectivity/dbtools.hxx>
+
+#include <com/sun/star/sdb/CommandType.hpp>
+#include <com/sun/star/lang/NullPointerException.hpp>
+#include <com/sun/star/lang/XComponent.hpp>
+#include <com/sun/star/sdb/XQueriesSupplier.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/sdb/XSingleSelectQueryComposer.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+
+#include <unotools/sharedunocomponent.hxx>
+#include <comphelper/diagnose_ex.hxx>
+#include <comphelper/property.hxx>
+
+
+namespace dbtools
+{
+
+
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::sdbc::XConnection;
+ using ::com::sun::star::sdb::XSingleSelectQueryComposer;
+ using ::com::sun::star::lang::NullPointerException;
+ using ::com::sun::star::uno::Exception;
+ using ::com::sun::star::lang::XComponent;
+ using ::com::sun::star::uno::UNO_QUERY_THROW;
+ using ::com::sun::star::sdb::XQueriesSupplier;
+ using ::com::sun::star::container::XNameAccess;
+ using ::com::sun::star::beans::XPropertySet;
+ using ::com::sun::star::lang::XMultiServiceFactory;
+ using ::com::sun::star::sdbc::SQLException;
+
+ namespace CommandType = ::com::sun::star::sdb::CommandType;
+
+ struct StatementComposer_Data
+ {
+ const Reference< XConnection > xConnection;
+ Reference< XSingleSelectQueryComposer > xComposer;
+ OUString sCommand;
+ OUString sFilter;
+ OUString sHavingClause;
+ OUString sOrder;
+ sal_Int32 nCommandType;
+ bool bEscapeProcessing;
+ bool bComposerDirty;
+ bool bDisposeComposer;
+
+ explicit StatementComposer_Data( const Reference< XConnection >& _rxConnection )
+ :xConnection( _rxConnection )
+ ,nCommandType( CommandType::COMMAND )
+ ,bEscapeProcessing( true )
+ ,bComposerDirty( true )
+ ,bDisposeComposer( true )
+ {
+ if ( !_rxConnection.is() )
+ throw NullPointerException();
+ }
+ };
+
+
+ namespace
+ {
+
+ void lcl_resetComposer( StatementComposer_Data& _rData )
+ {
+ if ( _rData.bDisposeComposer && _rData.xComposer.is() )
+ {
+ try
+ {
+ Reference< XComponent > xComposerComponent( _rData.xComposer, UNO_QUERY_THROW );
+ xComposerComponent->dispose();
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("connectivity.commontools");
+ }
+ }
+ _rData.xComposer.clear();
+ }
+
+
+ bool lcl_ensureUpToDateComposer_nothrow( StatementComposer_Data& _rData )
+ {
+ if ( !_rData.bComposerDirty )
+ return _rData.xComposer.is();
+ lcl_resetComposer( _rData );
+
+ try
+ {
+ OUString sStatement;
+ switch ( _rData.nCommandType )
+ {
+ case CommandType::COMMAND:
+ if ( _rData.bEscapeProcessing )
+ sStatement = _rData.sCommand;
+ // (in case of no escape processing we assume a not parseable statement)
+ break;
+
+ case CommandType::TABLE:
+ {
+ if ( _rData.sCommand.isEmpty() )
+ break;
+
+ sStatement = "SELECT * FROM ";
+
+ OUString sCatalog, sSchema, sTable;
+ qualifiedNameComponents( _rData.xConnection->getMetaData(), _rData.sCommand, sCatalog, sSchema, sTable, EComposeRule::InDataManipulation );
+
+ sStatement += composeTableNameForSelect( _rData.xConnection, sCatalog, sSchema, sTable );
+ }
+ break;
+
+ case CommandType::QUERY:
+ {
+ // ask the connection for the query
+ Reference< XQueriesSupplier > xSupplyQueries( _rData.xConnection, UNO_QUERY_THROW );
+ Reference< XNameAccess > xQueries( xSupplyQueries->getQueries(), css::uno::UNO_SET_THROW );
+
+ if ( !xQueries->hasByName( _rData.sCommand ) )
+ break;
+
+ Reference< XPropertySet > xQuery( xQueries->getByName( _rData.sCommand ), UNO_QUERY_THROW );
+
+ // a native query ?
+ bool bQueryEscapeProcessing = false;
+ xQuery->getPropertyValue("EscapeProcessing") >>= bQueryEscapeProcessing;
+ if ( !bQueryEscapeProcessing )
+ break;
+
+ // the command used by the query
+ xQuery->getPropertyValue("Command") >>= sStatement;
+ if ( sStatement.isEmpty() )
+ break;
+
+ // use a composer to build a statement from the query filter/order props
+ Reference< XMultiServiceFactory > xFactory( _rData.xConnection, UNO_QUERY_THROW );
+ ::utl::SharedUNOComponent< XSingleSelectQueryComposer > xComposer;
+ xComposer.set(
+ xFactory->createInstance("com.sun.star.sdb.SingleSelectQueryComposer"),
+ UNO_QUERY_THROW
+ );
+
+ // the "basic" statement
+ xComposer->setElementaryQuery( sStatement );
+
+ // the sort order
+ static constexpr OUString sPropOrder( u"Order"_ustr );
+ if ( ::comphelper::hasProperty( sPropOrder, xQuery ) )
+ {
+ OUString sOrder;
+ OSL_VERIFY( xQuery->getPropertyValue( sPropOrder ) >>= sOrder );
+ xComposer->setOrder( sOrder );
+ }
+
+ // the filter
+ bool bApplyFilter = true;
+ static constexpr OUString sPropApply( u"ApplyFilter"_ustr );
+ if ( ::comphelper::hasProperty( sPropApply, xQuery ) )
+ {
+ OSL_VERIFY( xQuery->getPropertyValue( sPropApply ) >>= bApplyFilter );
+ }
+
+ if ( bApplyFilter )
+ {
+ OUString sFilter;
+ OSL_VERIFY( xQuery->getPropertyValue("Filter") >>= sFilter );
+ xComposer->setFilter( sFilter );
+ OSL_VERIFY( xQuery->getPropertyValue("HavingClause") >>= sFilter );
+ xComposer->setHavingClause( sFilter );
+ }
+
+ // the composed statement
+ sStatement = xComposer->getQuery();
+ }
+ break;
+
+ default:
+ OSL_FAIL("lcl_ensureUpToDateComposer_nothrow: no table, no query, no statement - what else ?!");
+ break;
+ }
+
+ if ( !sStatement.isEmpty() )
+ {
+ // create a composer
+ Reference< XMultiServiceFactory > xFactory( _rData.xConnection, UNO_QUERY_THROW );
+ Reference< XSingleSelectQueryComposer > xComposer( xFactory->createInstance("com.sun.star.sdb.SingleSelectQueryComposer"),
+ UNO_QUERY_THROW );
+ xComposer->setElementaryQuery( sStatement );
+
+ // append sort/filter
+ xComposer->setOrder( _rData.sOrder );
+ xComposer->setFilter( _rData.sFilter );
+ xComposer->setHavingClause( _rData.sHavingClause );
+
+ sStatement = xComposer->getQuery();
+
+ _rData.xComposer = xComposer;
+ _rData.bComposerDirty = false;
+ }
+ }
+ catch( const SQLException& )
+ {
+ // allowed to leave here
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("connectivity.commontools");
+ }
+
+ return _rData.xComposer.is();
+ }
+ }
+
+ StatementComposer::StatementComposer( const Reference< XConnection >& _rxConnection,
+ const OUString& _rCommand, const sal_Int32 _nCommandType, const bool _bEscapeProcessing )
+ :m_pData( new StatementComposer_Data( _rxConnection ) )
+ {
+ OSL_PRECOND( _rxConnection.is(), "StatementComposer::StatementComposer: illegal connection!" );
+ m_pData->sCommand = _rCommand;
+ m_pData->nCommandType = _nCommandType;
+ m_pData->bEscapeProcessing = _bEscapeProcessing;
+ }
+
+
+ StatementComposer::~StatementComposer()
+ {
+ lcl_resetComposer( *m_pData );
+ }
+
+
+ void StatementComposer::setDisposeComposer( bool _bDoDispose )
+ {
+ m_pData->bDisposeComposer = _bDoDispose;
+ }
+
+
+ void StatementComposer::setFilter( const OUString& _rFilter )
+ {
+ m_pData->sFilter = _rFilter;
+ m_pData->bComposerDirty = true;
+ }
+
+
+ void StatementComposer::setHavingClause( const OUString& _rHavingClause )
+ {
+ m_pData->sHavingClause = _rHavingClause;
+ m_pData->bComposerDirty = true;
+ }
+
+
+ void StatementComposer::setOrder( const OUString& _rOrder )
+ {
+ m_pData->sOrder = _rOrder;
+ m_pData->bComposerDirty = true;
+ }
+
+
+ Reference< XSingleSelectQueryComposer > const & StatementComposer::getComposer()
+ {
+ lcl_ensureUpToDateComposer_nothrow( *m_pData );
+ return m_pData->xComposer;
+ }
+
+
+ OUString StatementComposer::getQuery()
+ {
+ if ( lcl_ensureUpToDateComposer_nothrow( *m_pData ) )
+ {
+ return m_pData->xComposer->getQuery();
+ }
+
+ return OUString();
+ }
+
+
+} // namespace dbtools
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/commontools/warningscontainer.cxx b/connectivity/source/commontools/warningscontainer.cxx
new file mode 100644
index 0000000000..ba78256125
--- /dev/null
+++ b/connectivity/source/commontools/warningscontainer.cxx
@@ -0,0 +1,110 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <connectivity/warningscontainer.hxx>
+#include <connectivity/dbexception.hxx>
+
+#include <com/sun/star/sdb/SQLContext.hpp>
+#include <com/sun/star/sdbc/XWarningsSupplier.hpp>
+
+#include <o3tl/any.hxx>
+#include <osl/diagnose.h>
+
+
+namespace dbtools
+{
+
+
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::sdbc;
+ using namespace ::com::sun::star::sdb;
+
+ static void lcl_concatWarnings( Any& _rChainLeft, const Any& _rChainRight )
+ {
+ if ( !_rChainLeft.hasValue() )
+ _rChainLeft = _rChainRight;
+ else
+ {
+ // to travel the chain by reference (and not by value), we need the getValue...
+ // looks like a hack, but the meaning of getValue is documented, and it's the only chance for reference-traveling...
+
+ OSL_ENSURE( SQLExceptionInfo( _rChainLeft ).isValid(),
+ "lcl_concatWarnings: invalid warnings chain (this will crash)!" );
+
+ const SQLException* pChainTravel = o3tl::doAccess<SQLException>( _rChainLeft );
+ SQLExceptionIteratorHelper aReferenceIterHelper( *pChainTravel );
+ while ( aReferenceIterHelper.hasMoreElements() )
+ pChainTravel = aReferenceIterHelper.next();
+
+ // reached the end of the chain, and pChainTravel points to the last element
+ const_cast< SQLException* >( pChainTravel )->NextException = _rChainRight;
+ }
+ }
+
+
+ void WarningsContainer::appendWarning(const SQLException& _rWarning)
+ {
+ lcl_concatWarnings( m_aOwnWarnings, Any( _rWarning ) );
+ }
+
+
+ void WarningsContainer::appendWarning( const SQLContext& _rContext )
+ {
+ lcl_concatWarnings( m_aOwnWarnings, Any( _rContext ));
+ }
+
+
+ void WarningsContainer::appendWarning(const SQLWarning& _rWarning)
+ {
+ lcl_concatWarnings( m_aOwnWarnings, Any( _rWarning ) );
+ }
+
+
+ Any WarningsContainer::getWarnings( ) const
+ {
+ Any aAllWarnings;
+ if ( m_xExternalWarnings.is() )
+ aAllWarnings = m_xExternalWarnings->getWarnings();
+
+ if ( m_aOwnWarnings.hasValue() )
+ lcl_concatWarnings( aAllWarnings, m_aOwnWarnings );
+
+ return aAllWarnings;
+ }
+
+
+ void WarningsContainer::clearWarnings( )
+ {
+ if ( m_xExternalWarnings.is() )
+ m_xExternalWarnings->clearWarnings();
+ m_aOwnWarnings.clear();
+ }
+
+
+ void WarningsContainer::appendWarning( const OUString& _rWarning, const char* _pAsciiSQLState, const Reference< XInterface >& _rxContext )
+ {
+ appendWarning( SQLWarning( _rWarning, _rxContext, OUString::createFromAscii( _pAsciiSQLState ), 0, Any() ) );
+ }
+
+
+} // namespace dbtools
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/cpool/ZConnectionPool.cxx b/connectivity/source/cpool/ZConnectionPool.cxx
new file mode 100644
index 0000000000..7db4a8f16f
--- /dev/null
+++ b/connectivity/source/cpool/ZConnectionPool.cxx
@@ -0,0 +1,301 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include "ZConnectionPool.hxx"
+#include <com/sun/star/lang/XComponent.hpp>
+#include "ZPooledConnection.hxx"
+#include "ZPoolCollection.hxx"
+#include <connectivity/ConnectionWrapper.hxx>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <algorithm>
+
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::container;
+using namespace ::osl;
+using namespace connectivity;
+
+
+void SAL_CALL OPoolTimer::onShot()
+{
+ m_pPool->invalidatePooledConnections();
+}
+
+constexpr OUString TIMEOUT_NODENAME = u"Timeout"_ustr;
+
+OConnectionPool::OConnectionPool(const Reference< XDriver >& _xDriver,
+ const Reference< XInterface >& _xDriverNode,
+ const Reference< css::reflection::XProxyFactory >& _rxProxyFactory)
+ :m_xDriver(_xDriver)
+ ,m_xDriverNode(_xDriverNode)
+ ,m_xProxyFactory(_rxProxyFactory)
+ ,m_nTimeOut(10)
+ ,m_nALiveCount(10)
+{
+ OSL_ENSURE(m_xDriverNode.is(),"NO valid Driver node set!");
+ Reference< XComponent > xComponent(m_xDriverNode, UNO_QUERY);
+ if (xComponent.is())
+ xComponent->addEventListener(this);
+
+ Reference<XPropertySet> xProp(m_xDriverNode,UNO_QUERY);
+ if(xProp.is())
+ xProp->addPropertyChangeListener(TIMEOUT_NODENAME,this);
+
+ OPoolCollection::getNodeValue(TIMEOUT_NODENAME, m_xDriverNode) >>= m_nALiveCount;
+ calculateTimeOuts();
+
+ m_xInvalidator = new OPoolTimer(this,::salhelper::TTimeValue(m_nTimeOut,0));
+ m_xInvalidator->start();
+}
+
+OConnectionPool::~OConnectionPool()
+{
+ clear(false);
+}
+
+namespace {
+
+struct TRemoveEventListenerFunctor
+{
+ OConnectionPool* m_pConnectionPool;
+ bool m_bDispose;
+
+ TRemoveEventListenerFunctor(OConnectionPool* _pConnectionPool, bool _bDispose)
+ : m_pConnectionPool(_pConnectionPool)
+ ,m_bDispose(_bDispose)
+ {
+ OSL_ENSURE(m_pConnectionPool,"No connection pool!");
+ }
+
+ void dispose(const Reference<XInterface>& _xComponent)
+ {
+ Reference< XComponent > xComponent(_xComponent, UNO_QUERY);
+
+ if ( xComponent.is() )
+ {
+ xComponent->removeEventListener(m_pConnectionPool);
+ if ( m_bDispose )
+ xComponent->dispose();
+ }
+ }
+
+ void operator()(const TPooledConnections::value_type& _aValue)
+ {
+ dispose(_aValue);
+ }
+
+ void operator()(const TActiveConnectionMap::value_type& _aValue)
+ {
+ dispose(_aValue.first);
+ }
+};
+
+struct TConnectionPoolFunctor
+{
+ OConnectionPool* m_pConnectionPool;
+
+ explicit TConnectionPoolFunctor(OConnectionPool* _pConnectionPool)
+ : m_pConnectionPool(_pConnectionPool)
+ {
+ OSL_ENSURE(m_pConnectionPool,"No connection pool!");
+ }
+ void operator()(const TConnectionMap::value_type& _aValue)
+ {
+ std::for_each(_aValue.second.aConnections.begin(),_aValue.second.aConnections.end(),TRemoveEventListenerFunctor(m_pConnectionPool,true));
+ }
+};
+
+}
+
+void OConnectionPool::clear(bool _bDispose)
+{
+ std::unique_lock aGuard(m_aMutex);
+
+ if(m_xInvalidator->isTicking())
+ m_xInvalidator->stop();
+
+ std::for_each(m_aPool.begin(),m_aPool.end(),TConnectionPoolFunctor(this));
+ m_aPool.clear();
+
+ std::for_each(m_aActiveConnections.begin(),m_aActiveConnections.end(),TRemoveEventListenerFunctor(this,_bDispose));
+ m_aActiveConnections.clear();
+
+ Reference< XComponent > xComponent(m_xDriverNode, UNO_QUERY);
+ if (xComponent.is())
+ xComponent->removeEventListener(this);
+ Reference< XPropertySet > xProp(m_xDriverNode, UNO_QUERY);
+ if (xProp.is())
+ xProp->removePropertyChangeListener(TIMEOUT_NODENAME, this);
+
+ m_xDriverNode.clear();
+ m_xDriver.clear();
+}
+
+Reference< XConnection > OConnectionPool::getConnectionWithInfo( const OUString& _rURL, const Sequence< PropertyValue >& _rInfo )
+{
+ std::unique_lock aGuard(m_aMutex);
+
+ Reference<XConnection> xConnection;
+
+ // create a unique id and look for it in our map
+ Sequence< PropertyValue > aInfo(_rInfo);
+ TConnectionMap::key_type nId;
+ OConnectionWrapper::createUniqueId(_rURL,aInfo,nId.m_pBuffer);
+ TConnectionMap::iterator aIter = m_aPool.find(nId);
+
+ if ( m_aPool.end() != aIter )
+ xConnection = getPooledConnection(aIter);
+
+ if ( !xConnection.is() )
+ xConnection = createNewConnection(_rURL,_rInfo);
+
+ return xConnection;
+}
+
+void SAL_CALL OConnectionPool::disposing( const css::lang::EventObject& Source )
+{
+ Reference<XConnection> xConnection(Source.Source,UNO_QUERY);
+ if(xConnection.is())
+ {
+ std::unique_lock aGuard(m_aMutex);
+ TActiveConnectionMap::iterator aIter = m_aActiveConnections.find(xConnection);
+ OSL_ENSURE(aIter != m_aActiveConnections.end(),"OConnectionPool::disposing: Connection wasn't in pool");
+ if(aIter != m_aActiveConnections.end())
+ { // move the pooled connection back to the pool
+ aIter->second.aPos->second.nALiveCount = m_nALiveCount;
+ aIter->second.aPos->second.aConnections.push_back(aIter->second.xPooledConnection);
+ m_aActiveConnections.erase(aIter);
+ }
+ }
+ else
+ {
+ m_xDriverNode.clear();
+ }
+}
+
+Reference< XConnection> OConnectionPool::createNewConnection(const OUString& _rURL,const Sequence< PropertyValue >& _rInfo)
+{
+ // create new pooled connection
+ Reference< XPooledConnection > xPooledConnection = new ::connectivity::OPooledConnection(m_xDriver->connect(_rURL,_rInfo),m_xProxyFactory);
+ // get the new connection from the pooled connection
+ Reference<XConnection> xConnection = xPooledConnection->getConnection();
+ if(xConnection.is())
+ {
+ // add our own as dispose listener to know when we should put the connection back to the pool
+ Reference< XComponent > xComponent(xConnection, UNO_QUERY);
+ if (xComponent.is())
+ xComponent->addEventListener(this);
+
+ // save some information to find the right pool later on
+ Sequence< PropertyValue > aInfo(_rInfo);
+ TConnectionMap::key_type nId;
+ OConnectionWrapper::createUniqueId(_rURL,aInfo,nId.m_pBuffer);
+ TConnectionPool aPack;
+
+ // insert the new connection and struct into the active connection map
+ aPack.nALiveCount = m_nALiveCount;
+ TActiveConnectionInfo aActiveInfo;
+ aActiveInfo.aPos = m_aPool.emplace(nId,aPack).first;
+ aActiveInfo.xPooledConnection = xPooledConnection;
+ m_aActiveConnections.emplace(xConnection,aActiveInfo);
+
+ if(m_xInvalidator->isExpired())
+ m_xInvalidator->start();
+ }
+
+ return xConnection;
+}
+
+void OConnectionPool::invalidatePooledConnections()
+{
+ std::unique_lock aGuard(m_aMutex);
+ TConnectionMap::iterator aIter = m_aPool.begin();
+ for (; aIter != m_aPool.end(); )
+ {
+ if(!(--(aIter->second.nALiveCount))) // connections are invalid
+ {
+ std::for_each(aIter->second.aConnections.begin(),aIter->second.aConnections.end(),TRemoveEventListenerFunctor(this,true));
+
+ aIter->second.aConnections.clear();
+
+ // look if the iterator aIter is still present in the active connection map
+ bool isPresent = std::any_of(m_aActiveConnections.begin(), m_aActiveConnections.end(),
+ [&aIter](const TActiveConnectionMap::value_type& rEntry) { return rEntry.second.aPos == aIter; });
+ if(!isPresent)
+ {// he isn't so we can delete him
+ aIter = m_aPool.erase(aIter);
+ }
+ else
+ ++aIter;
+ }
+ else
+ ++aIter;
+ }
+ if(!m_aPool.empty())
+ m_xInvalidator->start();
+}
+
+Reference< XConnection> OConnectionPool::getPooledConnection(TConnectionMap::iterator const & _rIter)
+{
+ Reference<XConnection> xConnection;
+
+ if(!_rIter->second.aConnections.empty())
+ {
+ Reference< XPooledConnection > xPooledConnection = _rIter->second.aConnections.back();
+ _rIter->second.aConnections.pop_back();
+
+ OSL_ENSURE(xPooledConnection.is(),"Can not be null here!");
+ xConnection = xPooledConnection->getConnection();
+ Reference< XComponent > xComponent(xConnection, UNO_QUERY);
+ if (xComponent.is())
+ xComponent->addEventListener(this);
+
+ TActiveConnectionInfo aActiveInfo;
+ aActiveInfo.aPos = _rIter;
+ aActiveInfo.xPooledConnection = xPooledConnection;
+ m_aActiveConnections[xConnection] = aActiveInfo;
+ }
+ return xConnection;
+}
+
+void SAL_CALL OConnectionPool::propertyChange( const PropertyChangeEvent& evt )
+{
+ if(TIMEOUT_NODENAME == evt.PropertyName)
+ {
+ OPoolCollection::getNodeValue(TIMEOUT_NODENAME, m_xDriverNode) >>= m_nALiveCount;
+ calculateTimeOuts();
+ }
+}
+
+void OConnectionPool::calculateTimeOuts()
+{
+ sal_Int32 nTimeOutCorrection = 10;
+ if(m_nALiveCount < 100)
+ nTimeOutCorrection = 20;
+
+ m_nTimeOut = m_nALiveCount / nTimeOutCorrection;
+ m_nALiveCount = m_nALiveCount / m_nTimeOut;
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/cpool/ZConnectionPool.hxx b/connectivity/source/cpool/ZConnectionPool.hxx
new file mode 100644
index 0000000000..1d07920d01
--- /dev/null
+++ b/connectivity/source/cpool/ZConnectionPool.hxx
@@ -0,0 +1,147 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+#include <sal/config.h>
+
+#include <map>
+#include <mutex>
+#include <vector>
+
+#include <com/sun/star/sdbc/XPooledConnection.hpp>
+#include <com/sun/star/sdbc/XDriver.hpp>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/beans/XPropertyChangeListener.hpp>
+#include <com/sun/star/reflection/XProxyFactory.hpp>
+#include <cppuhelper/implbase.hxx>
+#include <osl/mutex.hxx>
+#include <salhelper/timer.hxx>
+#include <rtl/ref.hxx>
+#include <rtl/digest.h>
+
+namespace connectivity
+{
+ class OConnectionPool;
+
+ /// OPoolTimer - Invalidates the connection pool
+
+ class OPoolTimer : public ::salhelper::Timer
+ {
+ OConnectionPool* m_pPool;
+ public:
+ OPoolTimer(OConnectionPool* _pPool,const ::salhelper::TTimeValue& Time)
+ : ::salhelper::Timer(Time)
+ ,m_pPool(_pPool)
+ {}
+ protected:
+ virtual void SAL_CALL onShot() override;
+ };
+
+
+ // OConnectionPool - the one-instance service for PooledConnections
+ // manages the active connections and the connections in the pool
+
+ // typedef for the internal structure
+ typedef std::vector< css::uno::Reference< css::sdbc::XPooledConnection> > TPooledConnections;
+
+ // contains the currently pooled connections
+ struct TConnectionPool
+ {
+ TPooledConnections aConnections;
+ sal_Int32 nALiveCount; // will be decremented every time a time says to, when will reach zero the pool will be deleted
+ };
+
+ struct TDigestHolder
+ {
+ sal_uInt8 m_pBuffer[RTL_DIGEST_LENGTH_SHA1];
+ TDigestHolder()
+ {
+ m_pBuffer[0] = 0;
+ }
+
+ };
+
+ // typedef TDigestHolder
+
+ struct TDigestLess
+ {
+ bool operator() (const TDigestHolder& x, const TDigestHolder& y) const
+ {
+ sal_uInt32 i;
+ for(i=0;i < RTL_DIGEST_LENGTH_SHA1 && (x.m_pBuffer[i] >= y.m_pBuffer[i]); ++i)
+ ;
+ return i < RTL_DIGEST_LENGTH_SHA1;
+ }
+ };
+
+ typedef std::map< TDigestHolder,TConnectionPool,TDigestLess> TConnectionMap;
+
+ // contains additional information about an activeconnection which is needed to put it back to the pool
+ struct TActiveConnectionInfo
+ {
+ TConnectionMap::iterator aPos;
+ css::uno::Reference< css::sdbc::XPooledConnection> xPooledConnection;
+ };
+
+ typedef std::map< css::uno::Reference< css::sdbc::XConnection>,
+ TActiveConnectionInfo> TActiveConnectionMap;
+
+ class OConnectionPool : public ::cppu::WeakImplHelper< css::beans::XPropertyChangeListener>
+ {
+ TConnectionMap m_aPool; // the pooled connections
+ TActiveConnectionMap m_aActiveConnections; // the currently active connections
+
+ std::mutex m_aMutex;
+ ::rtl::Reference<OPoolTimer> m_xInvalidator; // invalidates the conntection pool when shot
+
+ css::uno::Reference< css::sdbc::XDriver > m_xDriver; // the one and only driver for this connectionpool
+ css::uno::Reference< css::uno::XInterface > m_xDriverNode; // config node entry
+ css::uno::Reference< css::reflection::XProxyFactory > m_xProxyFactory;
+ sal_Int32 m_nTimeOut;
+ sal_Int32 m_nALiveCount;
+
+ private:
+ css::uno::Reference< css::sdbc::XConnection> createNewConnection(const OUString& _rURL,
+ const css::uno::Sequence< css::beans::PropertyValue >& _rInfo);
+ css::uno::Reference< css::sdbc::XConnection> getPooledConnection(TConnectionMap::iterator const & _rIter);
+ // calculate the timeout and the corresponding ALiveCount
+ void calculateTimeOuts();
+
+ protected:
+ // the dtor will be called from the last instance (last release call)
+ virtual ~OConnectionPool() override;
+ public:
+ OConnectionPool(const css::uno::Reference< css::sdbc::XDriver >& _xDriver,
+ const css::uno::Reference< css::uno::XInterface >& _xDriverNode,
+ const css::uno::Reference< css::reflection::XProxyFactory >& _rxProxyFactory);
+
+ // delete all refs
+ void clear(bool _bDispose);
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ css::uno::Reference< css::sdbc::XConnection > getConnectionWithInfo( const OUString& url, const css::uno::Sequence< css::beans::PropertyValue >& info );
+ // XEventListener
+ virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override;
+ // XPropertyChangeListener
+ virtual void SAL_CALL propertyChange( const css::beans::PropertyChangeEvent& evt ) override;
+
+ void invalidatePooledConnections();
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/cpool/ZConnectionWrapper.cxx b/connectivity/source/cpool/ZConnectionWrapper.cxx
new file mode 100644
index 0000000000..dd4519859f
--- /dev/null
+++ b/connectivity/source/cpool/ZConnectionWrapper.cxx
@@ -0,0 +1,241 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "ZConnectionWrapper.hxx"
+
+using namespace connectivity;
+
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::sdbc;
+
+OConnectionWeakWrapper::OConnectionWeakWrapper(Reference< XAggregation >& _xConnection)
+ : OConnectionWeakWrapper_BASE(m_aMutex)
+{
+ setDelegation(_xConnection,m_refCount);
+ OSL_ENSURE(m_xConnection.is(),"OConnectionWeakWrapper: Connection must be valid!");
+}
+
+OConnectionWeakWrapper::~OConnectionWeakWrapper()
+{
+ if ( !OConnectionWeakWrapper_BASE::rBHelper.bDisposed )
+ {
+ osl_atomic_increment( &m_refCount );
+ dispose();
+ }
+}
+// XServiceInfo
+
+IMPLEMENT_SERVICE_INFO(OConnectionWeakWrapper, "com.sun.star.sdbc.drivers.OConnectionWeakWrapper", "com.sun.star.sdbc.Connection")
+
+
+Reference< XStatement > SAL_CALL OConnectionWeakWrapper::createStatement( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OConnectionWeakWrapper_BASE::rBHelper.bDisposed);
+
+
+ return m_xConnection->createStatement();
+}
+
+Reference< XPreparedStatement > SAL_CALL OConnectionWeakWrapper::prepareStatement( const OUString& sql )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OConnectionWeakWrapper_BASE::rBHelper.bDisposed);
+
+
+ return m_xConnection->prepareStatement(sql);
+}
+
+Reference< XPreparedStatement > SAL_CALL OConnectionWeakWrapper::prepareCall( const OUString& sql )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OConnectionWeakWrapper_BASE::rBHelper.bDisposed);
+
+
+ return m_xConnection->prepareCall(sql);
+}
+
+OUString SAL_CALL OConnectionWeakWrapper::nativeSQL( const OUString& sql )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OConnectionWeakWrapper_BASE::rBHelper.bDisposed);
+
+
+ return m_xConnection->nativeSQL(sql);
+}
+
+void SAL_CALL OConnectionWeakWrapper::setAutoCommit( sal_Bool autoCommit )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OConnectionWeakWrapper_BASE::rBHelper.bDisposed);
+
+ m_xConnection->setAutoCommit(autoCommit);
+}
+
+sal_Bool SAL_CALL OConnectionWeakWrapper::getAutoCommit( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OConnectionWeakWrapper_BASE::rBHelper.bDisposed);
+
+
+ return m_xConnection->getAutoCommit();
+}
+
+void SAL_CALL OConnectionWeakWrapper::commit( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OConnectionWeakWrapper_BASE::rBHelper.bDisposed);
+
+
+ m_xConnection->commit();
+}
+
+void SAL_CALL OConnectionWeakWrapper::rollback( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OConnectionWeakWrapper_BASE::rBHelper.bDisposed);
+
+
+ m_xConnection->rollback();
+}
+
+sal_Bool SAL_CALL OConnectionWeakWrapper::isClosed( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ return m_xConnection->isClosed();
+}
+
+Reference< XDatabaseMetaData > SAL_CALL OConnectionWeakWrapper::getMetaData( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OConnectionWeakWrapper_BASE::rBHelper.bDisposed);
+
+
+ return m_xConnection->getMetaData();
+}
+
+void SAL_CALL OConnectionWeakWrapper::setReadOnly( sal_Bool readOnly )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OConnectionWeakWrapper_BASE::rBHelper.bDisposed);
+
+
+ m_xConnection->setReadOnly(readOnly);
+}
+
+sal_Bool SAL_CALL OConnectionWeakWrapper::isReadOnly( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OConnectionWeakWrapper_BASE::rBHelper.bDisposed);
+
+
+ return m_xConnection->isReadOnly();
+}
+
+void SAL_CALL OConnectionWeakWrapper::setCatalog( const OUString& catalog )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OConnectionWeakWrapper_BASE::rBHelper.bDisposed);
+
+
+ m_xConnection->setCatalog(catalog);
+}
+
+OUString SAL_CALL OConnectionWeakWrapper::getCatalog( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OConnectionWeakWrapper_BASE::rBHelper.bDisposed);
+
+
+ return m_xConnection->getCatalog();
+}
+
+void SAL_CALL OConnectionWeakWrapper::setTransactionIsolation( sal_Int32 level )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OConnectionWeakWrapper_BASE::rBHelper.bDisposed);
+
+
+ m_xConnection->setTransactionIsolation(level);
+}
+
+sal_Int32 SAL_CALL OConnectionWeakWrapper::getTransactionIsolation( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OConnectionWeakWrapper_BASE::rBHelper.bDisposed);
+
+
+ return m_xConnection->getTransactionIsolation();
+}
+
+Reference< css::container::XNameAccess > SAL_CALL OConnectionWeakWrapper::getTypeMap( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OConnectionWeakWrapper_BASE::rBHelper.bDisposed);
+
+
+ return m_xConnection->getTypeMap();
+}
+
+void SAL_CALL OConnectionWeakWrapper::setTypeMap( const Reference< css::container::XNameAccess >& typeMap )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OConnectionWeakWrapper_BASE::rBHelper.bDisposed);
+
+
+ m_xConnection->setTypeMap(typeMap);
+}
+
+// XCloseable
+void SAL_CALL OConnectionWeakWrapper::close( )
+{
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OConnectionWeakWrapper_BASE::rBHelper.bDisposed);
+
+ }
+ dispose();
+}
+
+void OConnectionWeakWrapper::disposing()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+
+ OConnectionWeakWrapper_BASE::disposing();
+ OConnectionWrapper::disposing();
+}
+
+// css::lang::XUnoTunnel
+IMPLEMENT_FORWARD_REFCOUNT( OConnectionWeakWrapper, OConnectionWeakWrapper_BASE )
+
+css::uno::Any SAL_CALL OConnectionWeakWrapper::queryInterface( const css::uno::Type& _rType )
+{
+ css::uno::Any aReturn = OConnectionWeakWrapper_BASE::queryInterface( _rType );
+ if ( !aReturn.hasValue() )
+ aReturn = OConnectionWrapper::queryInterface( _rType );
+ return aReturn;
+}
+
+IMPLEMENT_FORWARD_XTYPEPROVIDER2(OConnectionWeakWrapper,OConnectionWeakWrapper_BASE,OConnectionWrapper)
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/cpool/ZConnectionWrapper.hxx b/connectivity/source/cpool/ZConnectionWrapper.hxx
new file mode 100644
index 0000000000..e4b945fa9c
--- /dev/null
+++ b/connectivity/source/cpool/ZConnectionWrapper.hxx
@@ -0,0 +1,77 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <cppuhelper/compbase.hxx>
+#include <cppuhelper/basemutex.hxx>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <comphelper/uno3.hxx>
+#include <connectivity/ConnectionWrapper.hxx>
+
+namespace connectivity
+{
+
+
+ // OConnectionWeakWrapper - wraps all methods to the real connection from the driver
+ // but when disposed it doesn't dispose the real connection
+
+ typedef ::cppu::WeakComponentImplHelper< css::sdbc::XConnection > OConnectionWeakWrapper_BASE;
+
+ class OConnectionWeakWrapper : public ::cppu::BaseMutex
+ , public OConnectionWeakWrapper_BASE
+ , public OConnectionWrapper
+ {
+ protected:
+ // OComponentHelper
+ virtual void SAL_CALL disposing() override;
+ virtual ~OConnectionWeakWrapper() override;
+ public:
+ explicit OConnectionWeakWrapper(css::uno::Reference< css::uno::XAggregation >& _xConnection);
+
+ // XServiceInfo
+ DECLARE_SERVICE_INFO();
+ DECLARE_XTYPEPROVIDER()
+ DECLARE_XINTERFACE( )
+
+ // XConnection
+ virtual css::uno::Reference< css::sdbc::XStatement > SAL_CALL createStatement( ) override;
+ virtual css::uno::Reference< css::sdbc::XPreparedStatement > SAL_CALL prepareStatement( const OUString& sql ) override;
+ virtual css::uno::Reference< css::sdbc::XPreparedStatement > SAL_CALL prepareCall( const OUString& sql ) override;
+ virtual OUString SAL_CALL nativeSQL( const OUString& sql ) override;
+ virtual void SAL_CALL setAutoCommit( sal_Bool autoCommit ) override;
+ virtual sal_Bool SAL_CALL getAutoCommit( ) override;
+ virtual void SAL_CALL commit( ) override;
+ virtual void SAL_CALL rollback( ) override;
+ virtual sal_Bool SAL_CALL isClosed( ) override;
+ virtual css::uno::Reference< css::sdbc::XDatabaseMetaData > SAL_CALL getMetaData( ) override;
+ virtual void SAL_CALL setReadOnly( sal_Bool readOnly ) override;
+ virtual sal_Bool SAL_CALL isReadOnly( ) override;
+ virtual void SAL_CALL setCatalog( const OUString& catalog ) override;
+ virtual OUString SAL_CALL getCatalog( ) override;
+ virtual void SAL_CALL setTransactionIsolation( sal_Int32 level ) override;
+ virtual sal_Int32 SAL_CALL getTransactionIsolation( ) override;
+ virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getTypeMap( ) override;
+ virtual void SAL_CALL setTypeMap( const css::uno::Reference< css::container::XNameAccess >& typeMap ) override;
+ // XCloseable
+ virtual void SAL_CALL close( ) override;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/cpool/ZDriverWrapper.cxx b/connectivity/source/cpool/ZDriverWrapper.cxx
new file mode 100644
index 0000000000..9a1bdf971f
--- /dev/null
+++ b/connectivity/source/cpool/ZDriverWrapper.cxx
@@ -0,0 +1,114 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "ZDriverWrapper.hxx"
+#include "ZConnectionPool.hxx"
+#include <osl/diagnose.h>
+
+
+namespace connectivity
+{
+
+
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::sdbc;
+ using namespace ::com::sun::star::beans;
+
+ ODriverWrapper::ODriverWrapper( Reference< XAggregation >& _rxAggregateDriver, OConnectionPool* _pPool )
+ :m_pConnectionPool(_pPool)
+ {
+ OSL_ENSURE(_rxAggregateDriver.is(), "ODriverWrapper::ODriverWrapper: invalid aggregate!");
+ OSL_ENSURE(m_pConnectionPool.is(), "ODriverWrapper::ODriverWrapper: invalid connection pool!");
+
+ osl_atomic_increment( &m_refCount );
+ if (_rxAggregateDriver.is())
+ {
+ // transfer the (one and only) real ref to the aggregate to our member
+ m_xDriverAggregate = _rxAggregateDriver;
+ _rxAggregateDriver = nullptr;
+
+ // a second "real" reference
+ m_xDriver.set(m_xDriverAggregate, UNO_QUERY);
+ OSL_ENSURE(m_xDriver.is(), "ODriverWrapper::ODriverWrapper: invalid aggregate (no XDriver)!");
+
+ // set ourself as delegator
+ m_xDriverAggregate->setDelegator( getXWeak() );
+ }
+ osl_atomic_decrement( &m_refCount );
+ }
+
+
+ ODriverWrapper::~ODriverWrapper()
+ {
+ if (m_xDriverAggregate.is())
+ m_xDriverAggregate->setDelegator(nullptr);
+ }
+
+
+ Any SAL_CALL ODriverWrapper::queryInterface( const Type& _rType )
+ {
+ Any aReturn = ODriverWrapper_BASE::queryInterface(_rType);
+ return aReturn.hasValue() ? aReturn : (m_xDriverAggregate.is() ? m_xDriverAggregate->queryAggregation(_rType) : aReturn);
+ }
+
+
+ Reference< XConnection > SAL_CALL ODriverWrapper::connect( const OUString& url, const Sequence< PropertyValue >& info )
+ {
+ Reference< XConnection > xConnection;
+ if (m_pConnectionPool.is())
+ // route this through the pool
+ xConnection = m_pConnectionPool->getConnectionWithInfo( url, info );
+ else if (m_xDriver.is())
+ xConnection = m_xDriver->connect( url, info );
+
+ return xConnection;
+ }
+
+
+ sal_Bool SAL_CALL ODriverWrapper::acceptsURL( const OUString& url )
+ {
+ return m_xDriver.is() && m_xDriver->acceptsURL(url);
+ }
+
+
+ Sequence< DriverPropertyInfo > SAL_CALL ODriverWrapper::getPropertyInfo( const OUString& url, const Sequence< PropertyValue >& info )
+ {
+ Sequence< DriverPropertyInfo > aInfo;
+ if (m_xDriver.is())
+ aInfo = m_xDriver->getPropertyInfo(url, info);
+ return aInfo;
+ }
+
+
+ sal_Int32 SAL_CALL ODriverWrapper::getMajorVersion( )
+ {
+ return m_xDriver.is() ? m_xDriver->getMajorVersion() : 0;
+ }
+
+
+ sal_Int32 SAL_CALL ODriverWrapper::getMinorVersion( )
+ {
+ return m_xDriver.is() ? m_xDriver->getMinorVersion() : 0;
+ }
+
+
+} // namespace connectivity
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/cpool/ZDriverWrapper.hxx b/connectivity/source/cpool/ZDriverWrapper.hxx
new file mode 100644
index 0000000000..b08cfc3ad9
--- /dev/null
+++ b/connectivity/source/cpool/ZDriverWrapper.hxx
@@ -0,0 +1,73 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/sdbc/XDriver.hpp>
+#include <cppuhelper/implbase.hxx>
+#include <rtl/ref.hxx>
+#include <com/sun/star/uno/XAggregation.hpp>
+
+
+namespace connectivity
+{
+
+
+ class OConnectionPool;
+
+ typedef ::cppu::WeakImplHelper< css::sdbc::XDriver > ODriverWrapper_BASE;
+
+ class ODriverWrapper final : public ODriverWrapper_BASE
+ {
+ css::uno::Reference< css::uno::XAggregation >
+ m_xDriverAggregate;
+ css::uno::Reference< css::sdbc::XDriver >
+ m_xDriver;
+ rtl::Reference<OConnectionPool>
+ m_pConnectionPool;
+
+ public:
+ /** creates a new wrapper for a driver
+ @param _rxAggregateDriver
+ the driver to aggregate. The object will be reset to <NULL/> when returning from the ctor.
+ */
+ ODriverWrapper(
+ css::uno::Reference< css::uno::XAggregation >& _rxAggregateDriver,
+ OConnectionPool* _pPool
+ );
+
+
+ // XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type& aType ) override;
+
+ private:
+ /// dtor
+ virtual ~ODriverWrapper() override;
+ // XDriver
+ virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL connect( const OUString& url, const css::uno::Sequence< css::beans::PropertyValue >& info ) override;
+ virtual sal_Bool SAL_CALL acceptsURL( const OUString& url ) override;
+ virtual css::uno::Sequence< css::sdbc::DriverPropertyInfo > SAL_CALL getPropertyInfo( const OUString& url, const css::uno::Sequence< css::beans::PropertyValue >& info ) override;
+ virtual sal_Int32 SAL_CALL getMajorVersion( ) override;
+ virtual sal_Int32 SAL_CALL getMinorVersion( ) override;
+ };
+
+
+} // namespace connectivity
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/cpool/ZPoolCollection.cxx b/connectivity/source/cpool/ZPoolCollection.cxx
new file mode 100644
index 0000000000..47167ed570
--- /dev/null
+++ b/connectivity/source/cpool/ZPoolCollection.cxx
@@ -0,0 +1,468 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "ZPoolCollection.hxx"
+#include "ZDriverWrapper.hxx"
+#include "ZConnectionPool.hxx"
+#include <com/sun/star/configuration/theDefaultProvider.hpp>
+#include <com/sun/star/container/XHierarchicalNameAccess.hpp>
+#include <com/sun/star/beans/NamedValue.hpp>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/frame/Desktop.hpp>
+#include <com/sun/star/reflection/ProxyFactory.hpp>
+#include <com/sun/star/sdbc/DriverManager.hpp>
+#include <cppuhelper/supportsservice.hxx>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <osl/diagnose.h>
+#include <sal/log.hxx>
+#include <comphelper/diagnose_ex.hxx>
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::reflection;
+using namespace ::osl;
+using namespace connectivity;
+
+
+static OUString getConnectionPoolNodeName()
+{
+ return "org.openoffice.Office.DataAccess/ConnectionPool";
+}
+
+static OUString getEnablePoolingNodeName()
+{
+ return "EnablePooling";
+}
+
+static OUString getDriverNameNodeName()
+{
+ return "DriverName";
+}
+
+static OUString getDriverSettingsNodeName()
+{
+ return "DriverSettings";
+}
+
+static OUString getEnableNodeName()
+{
+ return "Enable";
+}
+
+
+OPoolCollection::OPoolCollection(const Reference< XComponentContext >& _rxContext)
+ :m_xContext(_rxContext)
+{
+ // bootstrap all objects supporting the .sdb.Driver service
+ m_xManager = DriverManager::create( m_xContext );
+
+ m_xProxyFactory = ProxyFactory::create( m_xContext );
+
+ Reference<XPropertySet> xProp(getConfigPoolRoot(),UNO_QUERY);
+ if ( xProp.is() )
+ xProp->addPropertyChangeListener(getEnablePoolingNodeName(),this);
+ // attach as desktop listener to know when we have to release our pools
+ osl_atomic_increment( &m_refCount );
+ {
+
+ m_xDesktop = css::frame::Desktop::create( m_xContext );
+ m_xDesktop->addTerminateListener(this);
+
+ }
+ osl_atomic_decrement( &m_refCount );
+}
+
+OPoolCollection::~OPoolCollection()
+{
+ clearConnectionPools(false);
+}
+
+Reference< XConnection > SAL_CALL OPoolCollection::getConnection( const OUString& _rURL )
+{
+ return getConnectionWithInfo(_rURL,Sequence< PropertyValue >());
+}
+
+Reference< XConnection > SAL_CALL OPoolCollection::getConnectionWithInfo( const OUString& _rURL, const Sequence< PropertyValue >& _rInfo )
+{
+ MutexGuard aGuard(m_aMutex);
+ Reference< XConnection > xConnection;
+ Reference< XDriver > xDriver;
+ Reference< XInterface > xDriverNode;
+ OUString sImplName;
+ if(isPoolingEnabledByUrl(_rURL,xDriver,sImplName,xDriverNode) && xDriver.is())
+ {
+ OConnectionPool* pConnectionPool = getConnectionPool(sImplName,xDriver,xDriverNode);
+
+ if(pConnectionPool)
+ xConnection = pConnectionPool->getConnectionWithInfo(_rURL,_rInfo);
+ }
+ else if(xDriver.is())
+ xConnection = xDriver->connect(_rURL,_rInfo);
+
+ return xConnection;
+}
+
+void SAL_CALL OPoolCollection::setLoginTimeout( sal_Int32 seconds )
+{
+ MutexGuard aGuard(m_aMutex);
+ m_xManager->setLoginTimeout(seconds);
+}
+
+sal_Int32 SAL_CALL OPoolCollection::getLoginTimeout( )
+{
+ MutexGuard aGuard(m_aMutex);
+ return m_xManager->getLoginTimeout();
+}
+
+OUString SAL_CALL OPoolCollection::getImplementationName( )
+{
+ return "com.sun.star.sdbc.OConnectionPool";
+}
+
+sal_Bool SAL_CALL OPoolCollection::supportsService( const OUString& _rServiceName )
+{
+ return cppu::supportsService(this, _rServiceName);
+}
+
+
+Sequence< OUString > SAL_CALL OPoolCollection::getSupportedServiceNames( )
+{
+ return { "com.sun.star.sdbc.ConnectionPool" };
+}
+
+Reference< XDriver > SAL_CALL OPoolCollection::getDriverByURL( const OUString& _rURL )
+{
+ // returns the original driver when no connection pooling is enabled else it returns the proxy
+ MutexGuard aGuard(m_aMutex);
+
+ Reference< XDriver > xDriver;
+ Reference< XInterface > xDriverNode;
+ OUString sImplName;
+ if(isPoolingEnabledByUrl(_rURL,xDriver,sImplName,xDriverNode))
+ {
+ Reference< XDriver > xExistentProxy;
+ // look if we already have a proxy for this driver
+ for (const auto& [rxDriver, rxDriverRef] : m_aDriverProxies)
+ {
+ // hold the proxy alive as long as we're in this loop round
+ xExistentProxy = rxDriverRef;
+
+ if (xExistentProxy.is() && (rxDriver.get() == xDriver.get()))
+ // already created a proxy for this
+ break;
+ }
+ if (xExistentProxy.is())
+ {
+ xDriver = xExistentProxy;
+ }
+ else
+ { // create a new proxy for the driver
+ // this allows us to control the connections created by it
+ Reference< XAggregation > xDriverProxy = m_xProxyFactory->createProxy(xDriver);
+ OSL_ENSURE(xDriverProxy.is(), "OConnectionPool::getDriverByURL: invalid proxy returned by the proxy factory!");
+
+ OConnectionPool* pConnectionPool = getConnectionPool(sImplName,xDriver,xDriverNode);
+ xDriver = new ODriverWrapper(xDriverProxy, pConnectionPool);
+ }
+ }
+
+ return xDriver;
+}
+
+bool OPoolCollection::isDriverPoolingEnabled(std::u16string_view _sDriverImplName,
+ Reference< XInterface >& _rxDriverNode)
+{
+ bool bEnabled = false;
+ Reference<XInterface> xConnectionPoolRoot = getConfigPoolRoot();
+ // then look for which of them settings are stored in the configuration
+ Reference< XNameAccess > xDirectAccess(openNode(getDriverSettingsNodeName(),xConnectionPoolRoot),UNO_QUERY);
+
+ if(xDirectAccess.is())
+ {
+ Sequence< OUString > aDriverKeys = xDirectAccess->getElementNames();
+ const OUString* pDriverKeys = aDriverKeys.getConstArray();
+ const OUString* pDriverKeysEnd = pDriverKeys + aDriverKeys.getLength();
+ for (;pDriverKeys != pDriverKeysEnd; ++pDriverKeys)
+ {
+ // the name of the driver in this round
+ if(_sDriverImplName == *pDriverKeys)
+ {
+ _rxDriverNode = openNode(*pDriverKeys,xDirectAccess);
+ if(_rxDriverNode.is())
+ getNodeValue(getEnableNodeName(),_rxDriverNode) >>= bEnabled;
+ break;
+ }
+ }
+ }
+ return bEnabled;
+}
+
+bool OPoolCollection::isPoolingEnabled()
+{
+ // the config node where all pooling relevant info are stored under
+ Reference<XInterface> xConnectionPoolRoot = getConfigPoolRoot();
+
+ // the global "enabled" flag
+ bool bEnabled = false;
+ if(xConnectionPoolRoot.is())
+ getNodeValue(getEnablePoolingNodeName(),xConnectionPoolRoot) >>= bEnabled;
+ return bEnabled;
+}
+
+Reference<XInterface> const & OPoolCollection::getConfigPoolRoot()
+{
+ if(!m_xConfigNode.is())
+ m_xConfigNode = createWithProvider(
+ css::configuration::theDefaultProvider::get(m_xContext),
+ getConnectionPoolNodeName());
+ return m_xConfigNode;
+}
+
+bool OPoolCollection::isPoolingEnabledByUrl(const OUString& _sUrl,
+ Reference< XDriver >& _rxDriver,
+ OUString& _rsImplName,
+ Reference< XInterface >& _rxDriverNode)
+{
+ bool bEnabled = false;
+ _rxDriver = m_xManager->getDriverByURL(_sUrl);
+ if (_rxDriver.is() && isPoolingEnabled())
+ {
+ Reference< XServiceInfo > xServiceInfo(_rxDriver,UNO_QUERY);
+ OSL_ENSURE(xServiceInfo.is(),"Each driver should have a XServiceInfo interface!");
+
+ if(xServiceInfo.is())
+ {
+ // look for the implementation name of the driver
+ _rsImplName = xServiceInfo->getImplementationName();
+ bEnabled = isDriverPoolingEnabled(_rsImplName,_rxDriverNode);
+ }
+ }
+ return bEnabled;
+}
+
+void OPoolCollection::clearConnectionPools(bool _bDispose)
+{
+ for(auto& rEntry : m_aPools)
+ {
+ rEntry.second->clear(_bDispose);
+ }
+ m_aPools.clear();
+}
+
+OConnectionPool* OPoolCollection::getConnectionPool(const OUString& _sImplName,
+ const Reference< XDriver >& _xDriver,
+ const Reference< XInterface >& _xDriverNode)
+{
+ OConnectionPool *pRet = nullptr;
+ OConnectionPools::const_iterator aFind = m_aPools.find(_sImplName);
+ if (aFind != m_aPools.end())
+ pRet = aFind->second.get();
+ else if (_xDriver.is() && _xDriverNode.is())
+ {
+ Reference<XPropertySet> xProp(_xDriverNode,UNO_QUERY);
+ if(xProp.is())
+ xProp->addPropertyChangeListener(getEnableNodeName(),this);
+ rtl::Reference<OConnectionPool> pConnectionPool = new OConnectionPool(_xDriver,_xDriverNode,m_xProxyFactory);
+ m_aPools.emplace(_sImplName,pConnectionPool);
+ pRet = pConnectionPool.get();
+ }
+
+ OSL_ENSURE(pRet, "Could not query DriverManager from ConnectionPool!");
+
+ return pRet;
+}
+
+Reference< XInterface > OPoolCollection::createWithProvider(const Reference< XMultiServiceFactory >& _rxConfProvider,
+ const OUString& _rPath)
+{
+ OSL_ASSERT(_rxConfProvider.is());
+ Sequence< Any > args{ Any(NamedValue( "nodepath", Any(_rPath))) };
+ Reference< XInterface > xInterface(
+ _rxConfProvider->createInstanceWithArguments(
+ "com.sun.star.configuration.ConfigurationAccess",
+ args));
+ OSL_ENSURE(
+ xInterface.is(),
+ "::createWithProvider: could not create the node access!");
+ return xInterface;
+}
+
+Reference<XInterface> OPoolCollection::openNode(const OUString& _rPath,const Reference<XInterface>& _xTreeNode) noexcept
+{
+ Reference< XHierarchicalNameAccess > xHierarchyAccess(_xTreeNode, UNO_QUERY);
+ Reference< XNameAccess > xDirectAccess(_xTreeNode, UNO_QUERY);
+ Reference< XInterface > xNode;
+
+ try
+ {
+ if (xDirectAccess.is() && xDirectAccess->hasByName(_rPath))
+ {
+ xNode.set(xDirectAccess->getByName(_rPath), css::uno::UNO_QUERY);
+ SAL_WARN_IF(
+ !xNode.is(), "connectivity.cpool",
+ "OConfigurationNode::openNode: could not open the node!");
+ }
+ else if (xHierarchyAccess.is())
+ {
+ xNode.set(
+ xHierarchyAccess->getByHierarchicalName(_rPath),
+ css::uno::UNO_QUERY);
+ SAL_WARN_IF(
+ !xNode.is(), "connectivity.cpool",
+ "OConfigurationNode::openNode: could not open the node!");
+ }
+
+ }
+ catch(const NoSuchElementException&)
+ {
+ SAL_WARN("connectivity.cpool", "::openNode: there is no element named " <<
+ _rPath << "!");
+ }
+ catch(const Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("connectivity.cpool", "OConfigurationNode::openNode: caught an exception while retrieving the node");
+ }
+ return xNode;
+}
+
+Any OPoolCollection::getNodeValue(const OUString& _rPath,const Reference<XInterface>& _xTreeNode) noexcept
+{
+ Reference< XHierarchicalNameAccess > xHierarchyAccess(_xTreeNode, UNO_QUERY);
+ Reference< XNameAccess > xDirectAccess(_xTreeNode, UNO_QUERY);
+ Any aReturn;
+ try
+ {
+ if (xDirectAccess.is() && xDirectAccess->hasByName(_rPath) )
+ {
+ aReturn = xDirectAccess->getByName(_rPath);
+ }
+ else if (xHierarchyAccess.is())
+ {
+ aReturn = xHierarchyAccess->getByHierarchicalName(_rPath);
+ }
+ }
+ catch(const NoSuchElementException&)
+ {
+ TOOLS_WARN_EXCEPTION("connectivity.cpool", "" );
+ }
+ return aReturn;
+}
+
+void SAL_CALL OPoolCollection::queryTermination( const EventObject& /*Event*/ )
+{
+}
+
+void SAL_CALL OPoolCollection::notifyTermination( const EventObject& /*Event*/ )
+{
+ clearDesktop();
+}
+
+void SAL_CALL OPoolCollection::disposing( const EventObject& Source )
+{
+ MutexGuard aGuard(m_aMutex);
+ if ( m_xDesktop == Source.Source )
+ {
+ clearDesktop();
+ }
+ else
+ {
+ try
+ {
+ Reference<XPropertySet> xProp(Source.Source,UNO_QUERY);
+ if(Source.Source == m_xConfigNode)
+ {
+ if ( xProp.is() )
+ xProp->removePropertyChangeListener(getEnablePoolingNodeName(),this);
+ m_xConfigNode.clear();
+ }
+ else if ( xProp.is() )
+ xProp->removePropertyChangeListener(getEnableNodeName(),this);
+ }
+ catch(const Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("connectivity.cpool", "");
+ }
+ }
+}
+
+void SAL_CALL OPoolCollection::propertyChange( const css::beans::PropertyChangeEvent& evt )
+{
+ MutexGuard aGuard(m_aMutex);
+ if(evt.Source == m_xConfigNode)
+ {
+ bool bEnabled = true;
+ evt.NewValue >>= bEnabled;
+ if(!bEnabled )
+ {
+ m_aDriverProxies.clear();
+ m_aDriverProxies = MapDriver2DriverRef();
+ clearConnectionPools(false);
+ }
+ }
+ else if(evt.Source.is())
+ {
+ bool bEnabled = true;
+ evt.NewValue >>= bEnabled;
+ if(!bEnabled)
+ {
+ OUString sThisDriverName;
+ getNodeValue(getDriverNameNodeName(),evt.Source) >>= sThisDriverName;
+ // 1st release the driver
+ // look if we already have a proxy for this driver
+ MapDriver2DriverRef::iterator aLookup = m_aDriverProxies.begin();
+ while( aLookup != m_aDriverProxies.end())
+ {
+ MapDriver2DriverRef::iterator aFind = aLookup;
+ Reference<XServiceInfo> xInfo(aLookup->first,UNO_QUERY);
+ ++aLookup;
+ if(xInfo.is() && xInfo->getImplementationName() == sThisDriverName)
+ m_aDriverProxies.erase(aFind);
+ }
+
+ // 2nd clear the connectionpool
+ OConnectionPools::iterator aFind = m_aPools.find(sThisDriverName);
+ if(aFind != m_aPools.end())
+ {
+ aFind->second->clear(false);
+ m_aPools.erase(aFind);
+ }
+ }
+ }
+}
+
+void OPoolCollection::clearDesktop()
+{
+ clearConnectionPools(true);
+ if ( m_xDesktop.is() )
+ m_xDesktop->removeTerminateListener(this);
+ m_xDesktop.clear();
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+connectivity_OPoolCollection_get_implementation(
+ css::uno::XComponentContext* context , css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new OPoolCollection(context));
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/cpool/ZPoolCollection.hxx b/connectivity/source/cpool/ZPoolCollection.hxx
new file mode 100644
index 0000000000..3fdade8a9d
--- /dev/null
+++ b/connectivity/source/cpool/ZPoolCollection.hxx
@@ -0,0 +1,133 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <sal/config.h>
+
+#include <map>
+
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/weakref.hxx>
+#include <com/sun/star/beans/XPropertyChangeListener.hpp>
+#include <com/sun/star/sdbc/XDriver.hpp>
+#include <com/sun/star/sdbc/XDriverManager2.hpp>
+#include <com/sun/star/sdbc/XConnectionPool.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/frame/XDesktop2.hpp>
+#include <com/sun/star/frame/XTerminateListener.hpp>
+#include <com/sun/star/reflection/XProxyFactory.hpp>
+#include <osl/mutex.hxx>
+#include <rtl/ref.hxx>
+
+namespace connectivity
+{
+ class OConnectionPool;
+
+ // OPoolCollection - the one-instance service for PooledConnections
+ // manages the active connections and the connections in the pool
+
+ typedef ::cppu::WeakImplHelper< css::sdbc::XConnectionPool,
+ css::lang::XServiceInfo,
+ css::frame::XTerminateListener,
+ css::beans::XPropertyChangeListener
+ > OPoolCollection_Base;
+
+ /// OPoolCollection: control the whole connection pooling for oo
+ class OPoolCollection : public OPoolCollection_Base
+ {
+
+
+ typedef std::map<OUString, rtl::Reference<OConnectionPool>> OConnectionPools;
+
+ typedef std::map<
+ css::uno::Reference< css::sdbc::XDriver >,
+ css::uno::WeakReference< css::sdbc::XDriver >>
+ MapDriver2DriverRef;
+
+ MapDriver2DriverRef m_aDriverProxies;
+ ::osl::Mutex m_aMutex;
+ OConnectionPools m_aPools; // the driver pools
+ css::uno::Reference< css::uno::XComponentContext > m_xContext;
+ css::uno::Reference< css::sdbc::XDriverManager2 > m_xManager;
+ css::uno::Reference< css::reflection::XProxyFactory > m_xProxyFactory;
+ css::uno::Reference< css::uno::XInterface > m_xConfigNode; // config node for general connection pooling
+ css::uno::Reference< css::frame::XDesktop2> m_xDesktop;
+
+ public:
+ OPoolCollection(const OPoolCollection&) = delete;
+ int operator= (const OPoolCollection&) = delete;
+
+ explicit OPoolCollection(
+ const css::uno::Reference< css::uno::XComponentContext >& _rxContext);
+
+ private:
+ // some configuration helper methods
+ css::uno::Reference< css::uno::XInterface > const & getConfigPoolRoot();
+ static css::uno::Reference< css::uno::XInterface > createWithProvider( const css::uno::Reference< css::lang::XMultiServiceFactory >& _rxConfProvider,
+ const OUString& _rPath);
+ static css::uno::Reference< css::uno::XInterface > openNode( const OUString& _rPath,
+ const css::uno::Reference< css::uno::XInterface >& _xTreeNode) noexcept;
+ bool isPoolingEnabled();
+ bool isDriverPoolingEnabled(std::u16string_view _sDriverImplName,
+ css::uno::Reference< css::uno::XInterface >& _rxDriverNode);
+ bool isPoolingEnabledByUrl( const OUString& _sUrl,
+ css::uno::Reference< css::sdbc::XDriver >& _rxDriver,
+ OUString& _rsImplName,
+ css::uno::Reference< css::uno::XInterface >& _rxDriverNode);
+
+ OConnectionPool* getConnectionPool( const OUString& _sImplName,
+ const css::uno::Reference< css::sdbc::XDriver >& _xDriver,
+ const css::uno::Reference< css::uno::XInterface >& _rxDriverNode);
+ void clearConnectionPools(bool _bDispose);
+ void clearDesktop();
+ protected:
+ virtual ~OPoolCollection() override;
+ public:
+
+ static css::uno::Any getNodeValue( const OUString& _rPath,
+ const css::uno::Reference< css::uno::XInterface>& _xTreeNode)noexcept;
+
+ // XDriverManager
+ virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL getConnection( const OUString& url ) override;
+ virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL getConnectionWithInfo( const OUString& url, const css::uno::Sequence< css::beans::PropertyValue >& info ) override;
+ virtual void SAL_CALL setLoginTimeout( sal_Int32 seconds ) override;
+ virtual sal_Int32 SAL_CALL getLoginTimeout( ) override;
+
+ //XDriverAccess
+ virtual css::uno::Reference< css::sdbc::XDriver > SAL_CALL getDriverByURL( const OUString& url ) override;
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+ // XEventListener
+ virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override;
+ // XPropertyChangeListener
+ virtual void SAL_CALL propertyChange( const css::beans::PropertyChangeEvent& evt ) override;
+
+ // XTerminateListener
+ virtual void SAL_CALL queryTermination( const css::lang::EventObject& Event ) override;
+ virtual void SAL_CALL notifyTermination( const css::lang::EventObject& Event ) override;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/cpool/ZPooledConnection.cxx b/connectivity/source/cpool/ZPooledConnection.cxx
new file mode 100644
index 0000000000..42e8d6c02d
--- /dev/null
+++ b/connectivity/source/cpool/ZPooledConnection.cxx
@@ -0,0 +1,72 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "ZPooledConnection.hxx"
+#include "ZConnectionWrapper.hxx"
+#include <comphelper/types.hxx>
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::reflection;
+using namespace connectivity;
+using namespace ::osl;
+
+OPooledConnection::OPooledConnection(const Reference< XConnection >& _xConnection,
+ const Reference< css::reflection::XProxyFactory >& _rxProxyFactory)
+ : OPooledConnection_Base(m_aMutex)
+ ,m_xRealConnection(_xConnection)
+ ,m_xProxyFactory(_rxProxyFactory)
+{
+
+}
+
+// OComponentHelper
+void SAL_CALL OPooledConnection::disposing()
+{
+ MutexGuard aGuard(m_aMutex);
+ if (m_xComponent.is())
+ m_xComponent->removeEventListener(this);
+ m_xComponent.clear();
+ ::comphelper::disposeComponent(m_xRealConnection);
+}
+
+// XEventListener
+void SAL_CALL OPooledConnection::disposing( const EventObject& /*Source*/ )
+{
+m_xComponent.clear();
+}
+
+//XPooledConnection
+Reference< XConnection > OPooledConnection::getConnection()
+{
+ if(!m_xComponent.is() && m_xRealConnection.is())
+ {
+ Reference< XAggregation > xConProxy = m_xProxyFactory->createProxy(m_xRealConnection);
+ m_xComponent = new OConnectionWeakWrapper(xConProxy);
+ // register as event listener for the new connection
+ if (m_xComponent.is())
+ m_xComponent->addEventListener(this);
+ }
+ return Reference< XConnection >(m_xComponent,UNO_QUERY);
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/cpool/ZPooledConnection.hxx b/connectivity/source/cpool/ZPooledConnection.hxx
new file mode 100644
index 0000000000..79450ea081
--- /dev/null
+++ b/connectivity/source/cpool/ZPooledConnection.hxx
@@ -0,0 +1,58 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+#include <cppuhelper/compbase.hxx>
+#include <cppuhelper/basemutex.hxx>
+#include <com/sun/star/sdbc/XPooledConnection.hpp>
+#include <com/sun/star/lang/XEventListener.hpp>
+#include <com/sun/star/reflection/XProxyFactory.hpp>
+
+
+namespace connectivity
+{
+
+ // OPooledConnection -
+ // allows to pool a real connection
+
+ typedef ::cppu::WeakComponentImplHelper< css::sdbc::XPooledConnection
+ ,css::lang::XEventListener> OPooledConnection_Base;
+
+ class OPooledConnection : public ::cppu::BaseMutex
+ ,public OPooledConnection_Base
+ {
+ css::uno::Reference< css::sdbc::XConnection > m_xRealConnection; // the connection from driver
+ css::uno::Reference< css::lang::XComponent > m_xComponent; // the connection which wraps the real connection
+ css::uno::Reference< css::reflection::XProxyFactory > m_xProxyFactory;
+ public:
+ // OComponentHelper
+ virtual void SAL_CALL disposing() override;
+
+ OPooledConnection(const css::uno::Reference< css::sdbc::XConnection >& _xConnection,
+ const css::uno::Reference< css::reflection::XProxyFactory >& _rxProxyFactory);
+
+ //XPooledConnection
+ virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL getConnection( ) override;
+
+ // XEventListener
+ virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override;
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/cpool/dbpool2.component b/connectivity/source/cpool/dbpool2.component
new file mode 100644
index 0000000000..13f3bac383
--- /dev/null
+++ b/connectivity/source/cpool/dbpool2.component
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ -->
+
+<component loader="com.sun.star.loader.SharedLibrary" environment="@CPPU_ENV@"
+ xmlns="http://openoffice.org/2010/uno-components">
+ <implementation name="com.sun.star.sdbc.OConnectionPool"
+ constructor="connectivity_OPoolCollection_get_implementation">
+ <service name="com.sun.star.sdbc.ConnectionPool"/>
+ </implementation>
+</component>
diff --git a/connectivity/source/dbtools/dbtools.component b/connectivity/source/dbtools/dbtools.component
new file mode 100644
index 0000000000..76dadcc033
--- /dev/null
+++ b/connectivity/source/dbtools/dbtools.component
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ -->
+
+<component loader="com.sun.star.loader.SharedLibrary" environment="@CPPU_ENV@"
+ xmlns="http://openoffice.org/2010/uno-components">
+ <implementation name="org.openoffice.comp.helper.DatabaseMetaDataResultSet"
+ constructor="connectivity_dbtools_ODatabaseMetaDataResultSet_get_implementation">
+ <service name="com.sun.star.sdbc.ResultSet"/>
+ </implementation>
+ <implementation name="org.openoffice.comp.helper.ParameterSubstitution"
+ constructor="connectivity_dbtools_ParameterSubstitution_get_implementation">
+ <service name="com.sun.star.sdb.ParameterSubstitution"/>
+ </implementation>
+</component>
diff --git a/connectivity/source/drivers/ado/ACallableStatement.cxx b/connectivity/source/drivers/ado/ACallableStatement.cxx
new file mode 100644
index 0000000000..94ad744d01
--- /dev/null
+++ b/connectivity/source/drivers/ado/ACallableStatement.cxx
@@ -0,0 +1,253 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <ado/ACallableStatement.hxx>
+#include <connectivity/dbexception.hxx>
+#include <cppuhelper/queryinterface.hxx>
+
+using namespace connectivity::ado;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::sdbc;
+using namespace com::sun::star::container;
+
+IMPLEMENT_SERVICE_INFO(OCallableStatement,"com.sun.star.sdbcx.ACallableStatement","com.sun.star.sdbc.CallableStatement");
+
+//************ Class: java.sql.CallableStatement
+
+OCallableStatement::OCallableStatement( OConnection* _pConnection, const OUString& sql )
+ : OPreparedStatement( _pConnection, sql )
+{
+ m_Command.put_CommandType(adCmdStoredProc);
+}
+
+
+Any SAL_CALL OCallableStatement::queryInterface( const Type & rType )
+{
+ Any aRet = OPreparedStatement::queryInterface(rType);
+ return aRet.hasValue() ? aRet : ::cppu::queryInterface(rType,static_cast< XRow*>(this));
+}
+
+
+sal_Bool SAL_CALL OCallableStatement::wasNull( )
+{
+ return m_aValue.isNull();
+}
+
+
+sal_Bool SAL_CALL OCallableStatement::getBoolean( sal_Int32 columnIndex )
+{
+ ADOParameter* pParam = nullptr;
+ m_pParameters->get_Item(OLEVariant(sal_Int32(columnIndex-1)),&pParam);
+ if(pParam)
+ pParam->get_Value(&m_aValue);
+ return m_aValue.getBool();
+}
+
+sal_Int8 SAL_CALL OCallableStatement::getByte( sal_Int32 columnIndex )
+{
+ ADOParameter* pParam = nullptr;
+ m_pParameters->get_Item(OLEVariant(sal_Int32(columnIndex-1)),&pParam);
+ if(pParam)
+ pParam->get_Value(&m_aValue);
+ return m_aValue.getInt8();
+}
+
+Sequence< sal_Int8 > SAL_CALL OCallableStatement::getBytes( sal_Int32 columnIndex )
+{
+ ADOParameter* pParam = nullptr;
+ m_pParameters->get_Item(OLEVariant(sal_Int32(columnIndex-1)),&pParam);
+ if(pParam)
+ pParam->get_Value(&m_aValue);
+ return m_aValue.getByteSequence();
+}
+
+css::util::Date SAL_CALL OCallableStatement::getDate( sal_Int32 columnIndex )
+{
+ ADOParameter* pParam = nullptr;
+ m_pParameters->get_Item(OLEVariant(sal_Int32(columnIndex-1)),&pParam);
+ if(pParam)
+ pParam->get_Value(&m_aValue);
+ return m_aValue.getDate();
+}
+
+double SAL_CALL OCallableStatement::getDouble( sal_Int32 columnIndex )
+{
+ ADOParameter* pParam = nullptr;
+ m_pParameters->get_Item(OLEVariant(sal_Int32(columnIndex-1)),&pParam);
+ if(pParam)
+ pParam->get_Value(&m_aValue);
+ return m_aValue.getDouble();
+}
+
+
+float SAL_CALL OCallableStatement::getFloat( sal_Int32 columnIndex )
+{
+ ADOParameter* pParam = nullptr;
+ m_pParameters->get_Item(OLEVariant(sal_Int32(columnIndex-1)),&pParam);
+ if(pParam)
+ pParam->get_Value(&m_aValue);
+ return m_aValue.getFloat();
+}
+
+
+sal_Int32 SAL_CALL OCallableStatement::getInt( sal_Int32 columnIndex )
+{
+ ADOParameter* pParam = nullptr;
+ m_pParameters->get_Item(OLEVariant(sal_Int32(columnIndex-1)),&pParam);
+ if(pParam)
+ pParam->get_Value(&m_aValue);
+ return m_aValue.getInt32();
+}
+
+
+sal_Int64 SAL_CALL OCallableStatement::getLong( sal_Int32 columnIndex )
+{
+ ADOParameter* pParam = nullptr;
+ m_pParameters->get_Item(OLEVariant(sal_Int32(columnIndex-1)),&pParam);
+ if(pParam)
+ pParam->get_Value(&m_aValue);
+ return static_cast<sal_Int64>(m_aValue.getCurrency().int64);
+}
+
+
+Any SAL_CALL OCallableStatement::getObject( sal_Int32 /*columnIndex*/, const Reference< css::container::XNameAccess >& /*typeMap*/ )
+{
+ ::dbtools::throwFeatureNotImplementedSQLException( "XRow::getObject", *this );
+ return Any();
+}
+
+
+sal_Int16 SAL_CALL OCallableStatement::getShort( sal_Int32 columnIndex )
+{
+ ADOParameter* pParam = nullptr;
+ m_pParameters->get_Item(OLEVariant(sal_Int32(columnIndex-1)),&pParam);
+ if(pParam)
+ pParam->get_Value(&m_aValue);
+ return m_aValue.getInt16();
+}
+
+
+OUString SAL_CALL OCallableStatement::getString( sal_Int32 columnIndex )
+{
+ ADOParameter* pParam = nullptr;
+ m_pParameters->get_Item(OLEVariant(sal_Int32(columnIndex-1)),&pParam);
+ if(pParam)
+ pParam->get_Value(&m_aValue);
+ return m_aValue.getString();
+}
+
+
+ css::util::Time SAL_CALL OCallableStatement::getTime( sal_Int32 columnIndex )
+{
+ ADOParameter* pParam = nullptr;
+ m_pParameters->get_Item(OLEVariant(sal_Int32(columnIndex-1)),&pParam);
+ if(pParam)
+ pParam->get_Value(&m_aValue);
+ return m_aValue.getTime();
+}
+
+
+ css::util::DateTime SAL_CALL OCallableStatement::getTimestamp( sal_Int32 columnIndex )
+{
+ ADOParameter* pParam = nullptr;
+ m_pParameters->get_Item(OLEVariant(sal_Int32(columnIndex-1)),&pParam);
+ if(pParam)
+ pParam->get_Value(&m_aValue);
+ return m_aValue.getDateTime();
+}
+
+
+void SAL_CALL OCallableStatement::registerOutParameter( sal_Int32 parameterIndex, sal_Int32 sqlType, const OUString& /*typeName*/ )
+{
+ ADOParameter* pParam = nullptr;
+ m_pParameters->get_Item(OLEVariant(sal_Int32(parameterIndex-1)),&pParam);
+ if(pParam)
+ {
+ pParam->put_Type(ADOS::MapJdbc2ADOType(sqlType,m_pConnection->getEngineType()));
+ pParam->put_Direction(adParamOutput);
+ }
+}
+
+void SAL_CALL OCallableStatement::registerNumericOutParameter( sal_Int32 parameterIndex, sal_Int32 sqlType, sal_Int32 scale )
+{
+ ADOParameter* pParam = nullptr;
+ m_pParameters->get_Item(OLEVariant(sal_Int32(parameterIndex-1)),&pParam);
+ if(pParam)
+ {
+ pParam->put_Type(ADOS::MapJdbc2ADOType(sqlType,m_pConnection->getEngineType()));
+ pParam->put_Direction(adParamOutput);
+ pParam->put_NumericScale(static_cast<sal_Int8>(scale));
+ }
+}
+
+
+Reference< css::io::XInputStream > SAL_CALL OCallableStatement::getBinaryStream( sal_Int32 /*columnIndex*/ )
+{
+ ::dbtools::throwFeatureNotImplementedSQLException( "XRow::getBinaryStream", *this );
+ return nullptr;
+}
+
+Reference< css::io::XInputStream > SAL_CALL OCallableStatement::getCharacterStream( sal_Int32 /*columnIndex*/ )
+{
+ ::dbtools::throwFeatureNotImplementedSQLException( "XRow::getCharacterStream", *this );
+ return nullptr;
+}
+
+
+Reference< XArray > SAL_CALL OCallableStatement::getArray( sal_Int32 /*columnIndex*/ )
+{
+ ::dbtools::throwFeatureNotImplementedSQLException( "XRow::getArray", *this );
+ return nullptr;
+}
+
+
+Reference< XClob > SAL_CALL OCallableStatement::getClob( sal_Int32 /*columnIndex*/ )
+{
+ ::dbtools::throwFeatureNotImplementedSQLException( "XRow::getClob", *this );
+ return nullptr;
+}
+
+Reference< XBlob > SAL_CALL OCallableStatement::getBlob( sal_Int32 /*columnIndex*/ )
+{
+ ::dbtools::throwFeatureNotImplementedSQLException( "XRow::getBlob", *this );
+ return nullptr;
+}
+
+
+Reference< XRef > SAL_CALL OCallableStatement::getRef( sal_Int32 /*columnIndex*/)
+{
+ ::dbtools::throwFeatureNotImplementedSQLException( "XRow::getRef", *this );
+ return nullptr;
+}
+
+
+void SAL_CALL OCallableStatement::acquire() noexcept
+{
+ OPreparedStatement::acquire();
+}
+
+void SAL_CALL OCallableStatement::release() noexcept
+{
+ OPreparedStatement::release();
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/ado/ACatalog.cxx b/connectivity/source/drivers/ado/ACatalog.cxx
new file mode 100644
index 0000000000..efab28344f
--- /dev/null
+++ b/connectivity/source/drivers/ado/ACatalog.cxx
@@ -0,0 +1,115 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <ado/ACatalog.hxx>
+#include <ado/AConnection.hxx>
+#include <ado/AGroups.hxx>
+#include <ado/AUsers.hxx>
+#include <ado/ATables.hxx>
+#include <ado/AViews.hxx>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XResultSet.hpp>
+
+
+using namespace connectivity;
+using namespace connectivity::ado;
+
+OCatalog::OCatalog(_ADOCatalog* _pCatalog,OConnection* _pCon) : connectivity::sdbcx::OCatalog(_pCon)
+ ,m_aCatalog(_pCatalog)
+ ,m_pConnection(_pCon)
+{
+}
+
+OCatalog::~OCatalog()
+{
+ if(m_aCatalog.IsValid())
+ m_aCatalog.putref_ActiveConnection(nullptr);
+ m_aCatalog.clear();
+}
+
+void OCatalog::refreshTables()
+{
+ ::std::vector< OUString> aVector;
+
+ WpADOTables aTables(m_aCatalog.get_Tables());
+ if ( aTables.IsValid() )
+ {
+ aTables.Refresh();
+ sal_Int32 nCount = aTables.GetItemCount();
+ aVector.reserve(nCount);
+ for(sal_Int32 i=0;i< nCount;++i)
+ {
+ WpADOTable aElement = aTables.GetItem(i);
+ if ( aElement.IsValid() )
+ {
+ OUString sTypeName = aElement.get_Type();
+ if ( !sTypeName.equalsIgnoreAsciiCase("SYSTEM TABLE")
+ && !sTypeName.equalsIgnoreAsciiCase("ACCESS TABLE") )
+ aVector.push_back(aElement.get_Name());
+ }
+ }
+ }
+
+ if(m_pTables)
+ m_pTables->reFill(aVector);
+ else
+ m_pTables.reset( new OTables(this,m_aMutex,aVector,aTables,m_pConnection->getMetaData()->supportsMixedCaseQuotedIdentifiers()) );
+}
+
+void OCatalog::refreshViews()
+{
+ ::std::vector< OUString> aVector;
+
+ WpADOViews aViews = m_aCatalog.get_Views();
+ aViews.fillElementNames(aVector);
+
+ if(m_pViews)
+ m_pViews->reFill(aVector);
+ else
+ m_pViews.reset( new OViews(this,m_aMutex,aVector,aViews,m_pConnection->getMetaData()->supportsMixedCaseQuotedIdentifiers()) );
+}
+
+void OCatalog::refreshGroups()
+{
+ ::std::vector< OUString> aVector;
+
+ WpADOGroups aGroups = m_aCatalog.get_Groups();
+ aGroups.fillElementNames(aVector);
+
+ if(m_pGroups)
+ m_pGroups->reFill(aVector);
+ else
+ m_pGroups.reset( new OGroups(this,m_aMutex,aVector,aGroups,m_pConnection->getMetaData()->supportsMixedCaseQuotedIdentifiers()) );
+}
+
+void OCatalog::refreshUsers()
+{
+ ::std::vector< OUString> aVector;
+
+ WpADOUsers aUsers = m_aCatalog.get_Users();
+ aUsers.fillElementNames(aVector);
+
+ if(m_pUsers)
+ m_pUsers->reFill(aVector);
+ else
+ m_pUsers.reset( new OUsers(this,m_aMutex,aVector,aUsers,m_pConnection->getMetaData()->supportsMixedCaseQuotedIdentifiers()) );
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/ado/AColumn.cxx b/connectivity/source/drivers/ado/AColumn.cxx
new file mode 100644
index 0000000000..a40c4f7234
--- /dev/null
+++ b/connectivity/source/drivers/ado/AColumn.cxx
@@ -0,0 +1,234 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <string_view>
+
+#include <ado/AColumn.hxx>
+#include <ado/AConnection.hxx>
+#include <ado/Awrapado.hxx>
+#include <com/sun/star/sdbc/ColumnValue.hpp>
+#include <comphelper/extract.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <comphelper/types.hxx>
+#include <ado/ACatalog.hxx>
+
+using namespace ::comphelper;
+
+using namespace connectivity::ado;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::sdbc;
+
+void WpADOColumn::Create()
+{
+ pInterface.CoCreateInstance(ADOS::CLSID_ADOCOLUMN_25, nullptr, CLSCTX_INPROC_SERVER);
+}
+
+OAdoColumn::OAdoColumn(bool _bCase,OConnection* _pConnection,_ADOColumn* _pColumn)
+ : connectivity::sdbcx::OColumn(_bCase)
+ ,m_pConnection(_pConnection)
+{
+ construct();
+ OSL_ENSURE(_pColumn,"Column can not be null!");
+ m_aColumn.set(_pColumn);
+ // m_aColumn.put_ParentCatalog(_pConnection->getAdoCatalog()->getCatalog());
+ fillPropertyValues();
+}
+
+OAdoColumn::OAdoColumn(bool _bCase,OConnection* _pConnection)
+ : connectivity::sdbcx::OColumn(_bCase)
+ ,m_pConnection(_pConnection)
+{
+ m_aColumn.Create();
+ m_aColumn.put_ParentCatalog(_pConnection->getAdoCatalog()->getCatalog());
+ construct();
+ fillPropertyValues();
+ m_Type = DataType::OTHER;
+}
+
+
+void OAdoColumn::construct()
+{
+ sal_Int32 nAttrib = isNew() ? 0 : PropertyAttribute::READONLY;
+
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISASCENDING), PROPERTY_ID_ISASCENDING, nAttrib,&m_IsAscending, cppu::UnoType<bool>::get());
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RELATEDCOLUMN), PROPERTY_ID_RELATEDCOLUMN, nAttrib,&m_ReferencedColumn, ::cppu::UnoType<OUString>::get());
+}
+
+void OAdoColumn::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,const Any& rValue)
+{
+ if(m_aColumn.IsValid())
+ {
+ std::u16string_view sAdoPropertyName;
+
+ switch(nHandle)
+ {
+ case PROPERTY_ID_ISASCENDING:
+ m_aColumn.put_SortOrder(::cppu::any2bool(rValue) ? adSortAscending : adSortDescending);
+ break;
+ case PROPERTY_ID_RELATEDCOLUMN:
+ {
+ OUString aVal;
+ rValue >>= aVal;
+ m_aColumn.put_RelatedColumn(aVal);
+ }
+ break;
+ case PROPERTY_ID_NAME:
+ {
+ OUString aVal;
+ rValue >>= aVal;
+ m_aColumn.put_Name(aVal);
+ }
+ break;
+ case PROPERTY_ID_TYPE:
+ {
+ sal_Int32 nVal=0;
+ rValue >>= nVal;
+ m_aColumn.put_Type(ADOS::MapJdbc2ADOType(nVal,m_pConnection->getEngineType()));
+ }
+ break;
+ case PROPERTY_ID_TYPENAME:
+ // rValue <<= m_pTable->getCatalog()->getConnection()->getTypeInfo()->find();
+ break;
+ case PROPERTY_ID_PRECISION:
+ {
+ sal_Int32 nVal=0;
+ rValue >>= nVal;
+ m_aColumn.put_Precision(nVal);
+ }
+ break;
+ case PROPERTY_ID_SCALE:
+ {
+ sal_Int32 nVal=0;
+ rValue >>= nVal;
+ if ( !m_IsCurrency )
+ m_aColumn.put_NumericScale(static_cast<sal_Int8>(nVal));
+ }
+ break;
+ case PROPERTY_ID_ISNULLABLE:
+ {
+ sal_Int32 nVal=0;
+ rValue >>= nVal;
+ if ( nVal == ColumnValue::NULLABLE )
+ m_aColumn.put_Attributes( adColNullable );
+ }
+ break;
+ case PROPERTY_ID_ISROWVERSION:
+ break;
+
+ case PROPERTY_ID_ISAUTOINCREMENT:
+ OTools::putValue(
+ m_aColumn.get_Properties(), std::u16string_view(u"Autoincrement"),
+ getBOOL(rValue));
+ break;
+
+ case PROPERTY_ID_IM001:
+ case PROPERTY_ID_DESCRIPTION:
+ sAdoPropertyName = u"Description";
+ break;
+
+ case PROPERTY_ID_DEFAULTVALUE:
+ sAdoPropertyName = u"Default";
+ break;
+ }
+
+ if (!sAdoPropertyName.empty())
+ OTools::putValue(m_aColumn.get_Properties(), sAdoPropertyName, getString(rValue));
+ }
+ OColumn_ADO::setFastPropertyValue_NoBroadcast(nHandle,rValue);
+}
+
+void OAdoColumn::fillPropertyValues()
+{
+ if(m_aColumn.IsValid())
+ {
+ m_IsAscending = m_aColumn.get_SortOrder() == adSortAscending;
+ m_ReferencedColumn = m_aColumn.get_RelatedColumn();
+ m_Name = m_aColumn.get_Name();
+ m_Precision = m_aColumn.get_Precision();
+ m_Scale = m_aColumn.get_NumericScale();
+ m_IsNullable = ((m_aColumn.get_Attributes() & adColNullable) == adColNullable) ? ColumnValue::NULLABLE : ColumnValue::NO_NULLS;
+
+ DataTypeEnum eType = m_aColumn.get_Type();
+ m_IsCurrency = (eType == adCurrency);
+ if ( m_IsCurrency && !m_Scale)
+ m_Scale = 4;
+ m_Type = ADOS::MapADOType2Jdbc(eType);
+
+ bool bForceTo = true;
+ const OTypeInfoMap* pTypeInfoMap = m_pConnection->getTypeInfo();
+ const OExtendedTypeInfo* pTypeInfo = OConnection::getTypeInfoFromType(*m_pConnection->getTypeInfo(),eType,OUString(),m_Precision,m_Scale,bForceTo);
+ if ( pTypeInfo )
+ m_TypeName = pTypeInfo->aSimpleType.aTypeName;
+ else if ( eType == adVarBinary && ADOS::isJetEngine(m_pConnection->getEngineType()) )
+ {
+ ::comphelper::UStringMixEqual aCase(false);
+ OTypeInfoMap::const_iterator aFind = std::find_if(pTypeInfoMap->begin(), pTypeInfoMap->end(),
+ [&aCase] (const OTypeInfoMap::value_type& typeInfo) {
+ return aCase(typeInfo.second->getDBName(), u"VarBinary");
+ });
+
+ if ( aFind != pTypeInfoMap->end() ) // change column type if necessary
+ {
+ eType = aFind->first;
+ pTypeInfo = aFind->second;
+ }
+
+ if ( !pTypeInfo )
+ {
+ pTypeInfo = OConnection::getTypeInfoFromType(*m_pConnection->getTypeInfo(),adBinary,OUString(),m_Precision,m_Scale,bForceTo);
+ eType = adBinary;
+ }
+
+ if ( pTypeInfo )
+ {
+ m_TypeName = pTypeInfo->aSimpleType.aTypeName;
+ m_Type = ADOS::MapADOType2Jdbc(eType);
+ }
+ }
+
+
+ // fill some specific props
+ {
+ WpADOProperties aProps( m_aColumn.get_Properties() );
+
+ if ( aProps.IsValid() )
+ {
+ m_IsAutoIncrement
+ = OTools::getValue(aProps, std::u16string_view(u"Autoincrement")).getBool();
+
+ m_Description
+ = OTools::getValue(aProps, std::u16string_view(u"Description")).getString();
+
+ m_DefaultValue
+ = OTools::getValue(aProps, std::u16string_view(u"Default")).getString();
+ }
+ }
+ }
+}
+
+WpADOColumn OAdoColumn::getColumnImpl() const
+{
+ return m_aColumn;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/ado/AColumns.cxx b/connectivity/source/drivers/ado/AColumns.cxx
new file mode 100644
index 0000000000..f56a6d8d00
--- /dev/null
+++ b/connectivity/source/drivers/ado/AColumns.cxx
@@ -0,0 +1,125 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <ado/AColumns.hxx>
+#include <ado/AColumn.hxx>
+#include <ado/AConnection.hxx>
+#include <ado/Awrapado.hxx>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XResultSet.hpp>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <com/sun/star/sdbc/ColumnValue.hpp>
+#include <comphelper/property.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <comphelper/types.hxx>
+#include <connectivity/dbexception.hxx>
+#include <rtl/ref.hxx>
+#include <algorithm>
+#include <string_view>
+#include <strings.hrc>
+
+using namespace connectivity::ado;
+using namespace connectivity;
+using namespace comphelper;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::sdbc;
+using namespace com::sun::star::container;
+
+sdbcx::ObjectType OColumns::createObject(const OUString& _rName)
+{
+ return new OAdoColumn(isCaseSensitive(),m_pConnection,m_aCollection.GetItem(_rName));
+}
+
+
+void OColumns::impl_refresh()
+{
+ m_aCollection.Refresh();
+}
+
+Reference< XPropertySet > OColumns::createDescriptor()
+{
+ return new OAdoColumn(isCaseSensitive(),m_pConnection);
+}
+
+// XAppend
+sdbcx::ObjectType OColumns::appendObject( const OUString&, const Reference< XPropertySet >& descriptor )
+{
+ rtl::Reference<OAdoColumn> pColumn = dynamic_cast<OAdoColumn*>( descriptor.get() );
+ Reference< XPropertySet > xColumn;
+ if ( !pColumn.is() )
+ {
+ // m_pConnection->throwGenericSQLException( STR_INVALID_COLUMN_DESCRIPTOR_ERROR,static_cast<XTypeProvider*>(this) );
+ pColumn = new OAdoColumn(isCaseSensitive(),m_pConnection);
+ xColumn = pColumn;
+ ::comphelper::copyProperties(descriptor,xColumn);
+ }
+
+ WpADOColumn aColumn = pColumn->getColumnImpl();
+
+ OUString sTypeName;
+ pColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPENAME)) >>= sTypeName;
+
+ const OTypeInfoMap* pTypeInfoMap = m_pConnection->getTypeInfo();
+ ::comphelper::UStringMixEqual aCase(false);
+ // search for typeinfo where the typename is equal sTypeName
+ OTypeInfoMap::const_iterator aFind = std::find_if(pTypeInfoMap->begin(), pTypeInfoMap->end(),
+ [&aCase, &sTypeName] (const OTypeInfoMap::value_type& typeInfo) {
+ return aCase(typeInfo.second->getDBName(), sTypeName);
+ });
+
+ if ( aFind != pTypeInfoMap->end() ) // change column type if necessary
+ aColumn.put_Type(aFind->first);
+
+ if ( SUCCEEDED(static_cast<ADOColumns*>(m_aCollection)->Append(OLEVariant(aColumn.get_Name()),aColumn.get_Type(),aColumn.get_DefinedSize())) )
+ {
+ WpADOColumn aAddedColumn = m_aCollection.GetItem(OLEVariant(aColumn.get_Name()));
+ if ( aAddedColumn.IsValid() )
+ {
+ bool bAutoIncrement = false;
+ pColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISAUTOINCREMENT)) >>= bAutoIncrement;
+ if ( bAutoIncrement )
+ OTools::putValue(
+ aAddedColumn.get_Properties(), std::u16string_view(u"Autoincrement"),
+ bAutoIncrement);
+
+ if ( aFind != pTypeInfoMap->end() && aColumn.get_Type() != aAddedColumn.get_Type() ) // change column type if necessary
+ aColumn.put_Type(aFind->first);
+ aAddedColumn.put_Precision(aColumn.get_Precision());
+ aAddedColumn.put_NumericScale(aColumn.get_NumericScale());
+ aAddedColumn.put_Attributes(aColumn.get_Attributes());
+ aAddedColumn.put_SortOrder(aColumn.get_SortOrder());
+ aAddedColumn.put_RelatedColumn(aColumn.get_RelatedColumn());
+ }
+ }
+ ADOS::ThrowException(m_pConnection->getConnection(),static_cast<XTypeProvider*>(this));
+
+ return new OAdoColumn(isCaseSensitive(),m_pConnection,pColumn->getColumnImpl());
+}
+
+// XDrop
+void OColumns::dropObject(sal_Int32 /*_nPos*/,const OUString& _sElementName)
+{
+ if(!m_aCollection.Delete(_sElementName))
+ ADOS::ThrowException(m_pConnection->getConnection(),static_cast<XTypeProvider*>(this));
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/ado/AConnection.cxx b/connectivity/source/drivers/ado/AConnection.cxx
new file mode 100644
index 0000000000..686a9fed58
--- /dev/null
+++ b/connectivity/source/drivers/ado/AConnection.cxx
@@ -0,0 +1,568 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <cstddef>
+#include <string_view>
+
+#include <ado/AConnection.hxx>
+#include <ado/ADatabaseMetaData.hxx>
+#include <ado/ADriver.hxx>
+#include <ado/AStatement.hxx>
+#include <ado/ACallableStatement.hxx>
+#include <ado/APreparedStatement.hxx>
+#include <ado/ACatalog.hxx>
+#include <com/sun/star/sdbc/ColumnValue.hpp>
+#include <com/sun/star/sdbc/TransactionIsolation.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <comphelper/servicehelper.hxx>
+#include <connectivity/dbexception.hxx>
+#include <o3tl/string_view.hxx>
+#include <osl/file.hxx>
+#include <systools/win32/oleauto.hxx>
+#include <strings.hrc>
+
+using namespace dbtools;
+using namespace connectivity::ado;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::sdbc;
+using namespace com::sun::star::sdbcx;
+
+
+IMPLEMENT_SERVICE_INFO(OConnection,"com.sun.star.sdbcx.AConnection","com.sun.star.sdbc.Connection");
+
+OConnection::OConnection(ODriver* _pDriver)
+ : m_xCatalog(nullptr),
+ m_pDriver(_pDriver),
+ m_pCatalog(nullptr),
+ m_nEngineType(0),
+ m_bClosed(false),
+ m_bAutocommit(true)
+{
+ osl_atomic_increment( &m_refCount );
+
+ sal::systools::COMReference<IClassFactory2> pIUnknown;
+ if (!FAILED(pIUnknown.CoGetClassObject(ADOS::CLSID_ADOCONNECTION_21, CLSCTX_INPROC_SERVER)))
+ {
+ HRESULT hr = pIUnknown->CreateInstanceLic(nullptr,
+ nullptr,
+ ADOS::IID_ADOCONNECTION_21,
+ ADOS::GetKeyStr(),
+ reinterpret_cast<void**>(&m_aAdoConnection));
+
+ if( !FAILED( hr ) )
+ {
+ OSL_ENSURE(m_aAdoConnection, "OConnection::OConnection: invalid ADO object!");
+ }
+ }
+
+ osl_atomic_decrement( &m_refCount );
+}
+
+OConnection::~OConnection()
+{
+}
+
+void OConnection::construct(std::u16string_view url,const Sequence< PropertyValue >& info)
+{
+ osl_atomic_increment( &m_refCount );
+
+ setConnectionInfo(info);
+
+ std::size_t nLen = url.find(':');
+ nLen = url.find(':',nLen == std::u16string_view::npos ? 0 : nLen+1);
+ std::u16string_view aDSN(url.substr(nLen == std::u16string_view::npos ? 0 : nLen+1));
+ OUString aUID,aPWD;
+ o3tl::starts_with(aDSN, u"access:", &aDSN);
+
+ sal_Int32 nTimeout = 20;
+ const PropertyValue *pIter = info.getConstArray();
+ const PropertyValue *pEnd = pIter + info.getLength();
+ for(;pIter != pEnd;++pIter)
+ {
+ if(pIter->Name == "Timeout")
+ pIter->Value >>= nTimeout;
+ else if(pIter->Name == "user")
+ pIter->Value >>= aUID;
+ else if(pIter->Name == "password")
+ pIter->Value >>= aPWD;
+ }
+ try
+ {
+ if(m_aAdoConnection)
+ {
+ if(m_aAdoConnection.Open(aDSN,aUID,aPWD,adConnectUnspecified))
+ m_aAdoConnection.PutCommandTimeout(nTimeout);
+ else
+ ADOS::ThrowException(m_aAdoConnection,*this);
+ if(m_aAdoConnection.get_State() != adStateOpen)
+ throwGenericSQLException( STR_NO_CONNECTION,*this );
+
+ WpADOProperties aProps = m_aAdoConnection.get_Properties();
+ if(aProps.IsValid())
+ {
+ OTools::putValue(aProps, std::u16string_view(u"Jet OLEDB:ODBC Parsing"), true);
+ OLEVariant aVar(
+ OTools::getValue(aProps, std::u16string_view(u"Jet OLEDB:Engine Type")));
+ if(!aVar.isNull() && !aVar.isEmpty())
+ m_nEngineType = aVar.getInt32();
+ }
+ buildTypeInfo();
+ //bErg = TRUE;
+ }
+ else
+ ::dbtools::throwFunctionSequenceException(*this);
+
+ }
+ catch(const Exception& )
+ {
+ osl_atomic_decrement( &m_refCount );
+ throw;
+ }
+ osl_atomic_decrement( &m_refCount );
+}
+
+Reference< XStatement > SAL_CALL OConnection::createStatement( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OConnection_BASE::rBHelper.bDisposed);
+
+ Reference< XStatement > xStmt = new OStatement(this);
+ m_aStatements.push_back(WeakReferenceHelper(xStmt));
+ return xStmt;
+}
+
+Reference< XPreparedStatement > SAL_CALL OConnection::prepareStatement( const OUString& sql )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OConnection_BASE::rBHelper.bDisposed);
+
+
+ Reference< XPreparedStatement > xPStmt = new OPreparedStatement(this, sql);
+ m_aStatements.push_back(WeakReferenceHelper(xPStmt));
+ return xPStmt;
+}
+
+Reference< XPreparedStatement > SAL_CALL OConnection::prepareCall( const OUString& sql )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OConnection_BASE::rBHelper.bDisposed);
+
+
+ Reference< XPreparedStatement > xPStmt = new OCallableStatement(this, sql);
+ m_aStatements.push_back(WeakReferenceHelper(xPStmt));
+ return xPStmt;
+}
+
+OUString SAL_CALL OConnection::nativeSQL( const OUString& _sql )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OConnection_BASE::rBHelper.bDisposed);
+
+
+ OUString sql = _sql;
+ WpADOProperties aProps = m_aAdoConnection.get_Properties();
+ if(aProps.IsValid())
+ {
+ OTools::putValue(aProps, std::u16string_view(u"Jet OLEDB:ODBC Parsing"), true);
+ WpADOCommand aCommand;
+ aCommand.Create();
+ aCommand.put_ActiveConnection(static_cast<IDispatch*>(m_aAdoConnection));
+ aCommand.put_CommandText(sql);
+ sql = aCommand.get_CommandText();
+ }
+
+ return sql;
+}
+
+void SAL_CALL OConnection::setAutoCommit( sal_Bool autoCommit )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OConnection_BASE::rBHelper.bDisposed);
+
+
+ m_bAutocommit = autoCommit;
+ if(!autoCommit)
+ m_aAdoConnection.BeginTrans();
+ else
+ m_aAdoConnection.RollbackTrans();
+}
+
+sal_Bool SAL_CALL OConnection::getAutoCommit( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OConnection_BASE::rBHelper.bDisposed);
+
+
+ return m_bAutocommit;
+}
+
+void SAL_CALL OConnection::commit( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OConnection_BASE::rBHelper.bDisposed);
+
+
+ m_aAdoConnection.CommitTrans();
+}
+
+void SAL_CALL OConnection::rollback( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OConnection_BASE::rBHelper.bDisposed);
+
+
+ m_aAdoConnection.RollbackTrans();
+}
+
+sal_Bool SAL_CALL OConnection::isClosed( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ return OConnection_BASE::rBHelper.bDisposed && !m_aAdoConnection.get_State();
+}
+
+Reference< XDatabaseMetaData > SAL_CALL OConnection::getMetaData( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OConnection_BASE::rBHelper.bDisposed);
+
+
+ Reference< XDatabaseMetaData > xMetaData = m_xMetaData;
+ if(!xMetaData.is())
+ {
+ xMetaData = new ODatabaseMetaData(this);
+ m_xMetaData = xMetaData;
+ }
+
+ return xMetaData;
+}
+
+void SAL_CALL OConnection::setReadOnly( sal_Bool readOnly )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OConnection_BASE::rBHelper.bDisposed);
+
+
+ m_aAdoConnection.put_Mode(readOnly ? adModeRead : adModeReadWrite);
+ ADOS::ThrowException(m_aAdoConnection,*this);
+}
+
+sal_Bool SAL_CALL OConnection::isReadOnly( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OConnection_BASE::rBHelper.bDisposed);
+
+
+ return m_aAdoConnection.get_Mode() == adModeRead;
+}
+
+void SAL_CALL OConnection::setCatalog( const OUString& catalog )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OConnection_BASE::rBHelper.bDisposed);
+
+ m_aAdoConnection.PutDefaultDatabase(catalog);
+ ADOS::ThrowException(m_aAdoConnection,*this);
+}
+
+OUString SAL_CALL OConnection::getCatalog( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OConnection_BASE::rBHelper.bDisposed);
+
+ return m_aAdoConnection.GetDefaultDatabase();
+}
+
+void SAL_CALL OConnection::setTransactionIsolation( sal_Int32 level )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OConnection_BASE::rBHelper.bDisposed);
+
+
+ IsolationLevelEnum eIso;
+ switch(level)
+ {
+ case TransactionIsolation::NONE:
+ eIso = adXactUnspecified;
+ break;
+ case TransactionIsolation::READ_UNCOMMITTED:
+ eIso = adXactReadUncommitted;
+ break;
+ case TransactionIsolation::READ_COMMITTED:
+ eIso = adXactReadCommitted;
+ break;
+ case TransactionIsolation::REPEATABLE_READ:
+ eIso = adXactRepeatableRead;
+ break;
+ case TransactionIsolation::SERIALIZABLE:
+ eIso = adXactSerializable;
+ break;
+ default:
+ OSL_FAIL("OConnection::setTransactionIsolation invalid level");
+ return;
+ }
+ m_aAdoConnection.put_IsolationLevel(eIso);
+ ADOS::ThrowException(m_aAdoConnection,*this);
+}
+
+sal_Int32 SAL_CALL OConnection::getTransactionIsolation( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OConnection_BASE::rBHelper.bDisposed);
+
+
+ sal_Int32 nRet = 0;
+ switch(m_aAdoConnection.get_IsolationLevel())
+ {
+ case adXactUnspecified:
+ nRet = TransactionIsolation::NONE;
+ break;
+ case adXactReadUncommitted:
+ nRet = TransactionIsolation::READ_UNCOMMITTED;
+ break;
+ case adXactReadCommitted:
+ nRet = TransactionIsolation::READ_COMMITTED;
+ break;
+ case adXactRepeatableRead:
+ nRet = TransactionIsolation::REPEATABLE_READ;
+ break;
+ case adXactSerializable:
+ nRet = TransactionIsolation::SERIALIZABLE;
+ break;
+ default:
+ OSL_FAIL("OConnection::setTransactionIsolation invalid level");
+ }
+ ADOS::ThrowException(m_aAdoConnection,*this);
+ return nRet;
+}
+
+Reference< css::container::XNameAccess > SAL_CALL OConnection::getTypeMap( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OConnection_BASE::rBHelper.bDisposed);
+
+
+ return nullptr;
+}
+
+void SAL_CALL OConnection::setTypeMap( const Reference< css::container::XNameAccess >& /*typeMap*/ )
+{
+ ::dbtools::throwFeatureNotImplementedSQLException( "XConnection::setTypeMap", *this );
+}
+
+// XCloseable
+void SAL_CALL OConnection::close( )
+{
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OConnection_BASE::rBHelper.bDisposed);
+
+ }
+ dispose();
+}
+
+// XWarningsSupplier
+Any SAL_CALL OConnection::getWarnings( )
+{
+ return Any();
+}
+
+void SAL_CALL OConnection::clearWarnings( )
+{
+}
+
+void OConnection::buildTypeInfo()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ ADORecordset *pRecordset = m_aAdoConnection.getTypeInfo();
+ if ( pRecordset )
+ {
+ pRecordset->AddRef();
+ VARIANT_BOOL bIsAtBOF;
+ pRecordset->get_BOF(&bIsAtBOF);
+
+ bool bOk = true;
+ if ( bIsAtBOF == VARIANT_TRUE )
+ bOk = SUCCEEDED(pRecordset->MoveNext());
+
+ if ( bOk )
+ {
+ // HACK for access
+ static const char s_sVarChar[] = "VarChar";
+ do
+ {
+ sal_Int32 nPos = 1;
+ OExtendedTypeInfo* aInfo = new OExtendedTypeInfo;
+ aInfo->aSimpleType.aTypeName = ADOS::getField(pRecordset,nPos++).get_Value().getString();
+ aInfo->eType = static_cast<DataTypeEnum>(ADOS::getField(pRecordset,nPos++).get_Value().getInt32());
+ if ( aInfo->eType == adWChar && aInfo->aSimpleType.aTypeName == s_sVarChar )
+ aInfo->eType = adVarWChar;
+ aInfo->aSimpleType.nType = static_cast<sal_Int16>(ADOS::MapADOType2Jdbc(aInfo->eType));
+ aInfo->aSimpleType.nPrecision = ADOS::getField(pRecordset,nPos++).get_Value().getInt32();
+ nPos++; // aLiteralPrefix
+ nPos++; // aLiteralSuffix
+ nPos++; // aCreateParams
+ nPos++; // bNullable
+ nPos++; // bCaseSensitive
+ nPos++; // nSearchType
+ nPos++; // bUnsigned
+ nPos++; // bCurrency
+ nPos++; // bAutoIncrement
+ aInfo->aSimpleType.aLocalTypeName = ADOS::getField(pRecordset,nPos++).get_Value().getString();
+ nPos++; // nMinimumScale
+ aInfo->aSimpleType.nMaximumScale = ADOS::getField(pRecordset,nPos++).get_Value().getInt16();
+ if ( adCurrency == aInfo->eType && !aInfo->aSimpleType.nMaximumScale)
+ {
+ aInfo->aSimpleType.nMaximumScale = 4;
+ }
+ nPos++; // nNumPrecRadix
+ // Now that we have the type info, save it
+ // in the Hashtable if we don't already have an
+ // entry for this SQL type.
+
+ m_aTypeInfo.emplace(aInfo->eType,aInfo);
+ }
+ while ( SUCCEEDED(pRecordset->MoveNext()) );
+ }
+ pRecordset->Release();
+ }
+}
+
+void OConnection::disposing()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+
+ OConnection_BASE::disposing();
+
+ m_bClosed = true;
+ m_xMetaData = css::uno::WeakReference< css::sdbc::XDatabaseMetaData>();
+ m_xCatalog = css::uno::WeakReference< css::sdbcx::XTablesSupplier>();
+ m_pDriver = nullptr;
+
+ m_aAdoConnection.Close();
+
+ for (auto& rEntry : m_aTypeInfo)
+ delete rEntry.second;
+
+ m_aTypeInfo.clear();
+
+ m_aAdoConnection.clear();
+}
+
+sal_Int64 SAL_CALL OConnection::getSomething( const css::uno::Sequence< sal_Int8 >& rId )
+{
+ return comphelper::getSomethingImpl(rId, this,
+ comphelper::FallbackToGetSomethingOf<OConnection_BASE>{});
+}
+
+Sequence< sal_Int8 > OConnection::getUnoTunnelId()
+{
+ static const comphelper::UnoIdInit implId;
+ return implId.getSeq();
+}
+
+const OExtendedTypeInfo* OConnection::getTypeInfoFromType(const OTypeInfoMap& _rTypeInfo,
+ DataTypeEnum _nType,
+ const OUString& _sTypeName,
+ sal_Int32 _nPrecision,
+ sal_Int32 _nScale,
+ bool& _brForceToType)
+{
+ const OExtendedTypeInfo* pTypeInfo = nullptr;
+ _brForceToType = false;
+ // search for type
+ std::pair<OTypeInfoMap::const_iterator, OTypeInfoMap::const_iterator> aPair = _rTypeInfo.equal_range(_nType);
+ OTypeInfoMap::const_iterator aIter = aPair.first;
+ if(aIter != _rTypeInfo.end()) // compare with end is correct here
+ {
+ for(;aIter != aPair.second;++aIter)
+ {
+ // search the best matching type
+ OExtendedTypeInfo* pInfo = aIter->second;
+ if ( ( !_sTypeName.getLength()
+ || (pInfo->aSimpleType.aTypeName.equalsIgnoreAsciiCase(_sTypeName))
+ )
+ && (pInfo->aSimpleType.nPrecision >= _nPrecision)
+ && (pInfo->aSimpleType.nMaximumScale >= _nScale)
+
+ )
+ break;
+ }
+
+ if (aIter == aPair.second)
+ {
+ for(aIter = aPair.first; aIter != aPair.second; ++aIter)
+ {
+ // search the best matching type (now comparing the local names)
+ if ( (aIter->second->aSimpleType.aLocalTypeName.equalsIgnoreAsciiCase(_sTypeName))
+ && (aIter->second->aSimpleType.nPrecision >= _nPrecision)
+ && (aIter->second->aSimpleType.nMaximumScale >= _nScale)
+ )
+ {
+// we can not assert here because we could be in d&d
+/*
+ OSL_FAIL(( OString("getTypeInfoFromType: assuming column type ")
+ += OString(aIter->second->aTypeName.getStr(), aIter->second->aTypeName.getLength(), osl_getThreadTextEncoding())
+ += OString("\" (expected type name ")
+ += OString(_sTypeName.getStr(), _sTypeName.getLength(), osl_getThreadTextEncoding())
+ += OString(" matches the type's local name).")).getStr());
+*/
+ break;
+ }
+ }
+ }
+
+ if (aIter == aPair.second)
+ { // no match for the names, no match for the local names
+ // -> drop the precision and the scale restriction, accept any type with the property
+ // type id (nType)
+
+ // we can not assert here because we could be in d&d
+ pTypeInfo = aPair.first->second;
+ _brForceToType = true;
+ }
+ else
+ pTypeInfo = aIter->second;
+ }
+ else if ( _sTypeName.getLength() )
+ {
+ ::comphelper::UStringMixEqual aCase(false);
+ // search for typeinfo where the typename is equal _sTypeName
+ OTypeInfoMap::const_iterator aFind = std::find_if(_rTypeInfo.begin(), _rTypeInfo.end(),
+ [&aCase, &_sTypeName] (const OTypeInfoMap::value_type& typeInfo) {
+ return aCase(typeInfo.second->getDBName(), _sTypeName);
+ });
+
+ if(aFind != _rTypeInfo.end())
+ pTypeInfo = aFind->second;
+ }
+
+// we can not assert here because we could be in d&d
+// OSL_ENSURE(pTypeInfo, "getTypeInfoFromType: no type info found for this type!");
+ return pTypeInfo;
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/ado/ADatabaseMetaData.cxx b/connectivity/source/drivers/ado/ADatabaseMetaData.cxx
new file mode 100644
index 0000000000..65e0a80f52
--- /dev/null
+++ b/connectivity/source/drivers/ado/ADatabaseMetaData.cxx
@@ -0,0 +1,1034 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <ado/ADatabaseMetaData.hxx>
+#include <ado/ADatabaseMetaDataResultSet.hxx>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <com/sun/star/sdbc/ResultSetType.hpp>
+#include <com/sun/star/sdbc/ResultSetConcurrency.hpp>
+#include <com/sun/star/sdbc/TransactionIsolation.hpp>
+#include <ado/AConnection.hxx>
+#include <ado/adoimp.hxx>
+#include <FDatabaseMetaDataResultSet.hxx>
+#include <comphelper/types.hxx>
+#include <connectivity/dbexception.hxx>
+#include <rtl/ref.hxx>
+
+using namespace ::comphelper;
+
+using namespace connectivity;
+using namespace connectivity::ado;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::sdbc;
+
+
+ODatabaseMetaData::ODatabaseMetaData(OConnection* _pCon)
+ : ::connectivity::ODatabaseMetaDataBase(_pCon,_pCon->getConnectionInfo())
+ ,m_rADOConnection(_pCon->getConnection())
+ ,m_pConnection(_pCon)
+{
+}
+
+sal_Int32 ODatabaseMetaData::getInt32Property(const OUString& _aProperty)
+{
+ connectivity::ado::WpADOProperties aProps(m_rADOConnection.get_Properties());
+ // ADOS::ThrowException(m_rADOConnection,*this);
+ OSL_ENSURE(aProps.IsValid(),"There are no properties at the connection");
+ ADO_PROP(_aProperty);
+ sal_Int32 nValue(0);
+ if(!aVar.isNull() && !aVar.isEmpty())
+ nValue = aVar.getInt32();
+ return nValue;
+}
+
+
+bool ODatabaseMetaData::getBoolProperty(const OUString& _aProperty)
+{
+ connectivity::ado::WpADOProperties aProps(m_rADOConnection.get_Properties());
+ ADOS::ThrowException(m_rADOConnection,*this);
+ OSL_ENSURE(aProps.IsValid(),"There are no properties at the connection");
+ ADO_PROP(_aProperty);
+ return !aVar.isNull() && !aVar.isEmpty() && aVar.getBool();
+}
+
+OUString ODatabaseMetaData::getStringProperty(const OUString& _aProperty)
+{
+ connectivity::ado::WpADOProperties aProps(m_rADOConnection.get_Properties());
+ ADOS::ThrowException(m_rADOConnection,*this);
+ OSL_ENSURE(aProps.IsValid(),"There are no properties at the connection");
+
+ ADO_PROP(_aProperty);
+ OUString aValue;
+ if(!aVar.isNull() && !aVar.isEmpty() && aVar.getType() == VT_BSTR)
+ aValue = aVar.getString();
+
+ return aValue;
+}
+
+Reference< XResultSet > ODatabaseMetaData::impl_getTypeInfo_throw( )
+{
+ ADORecordset *pRecordset = m_rADOConnection.getTypeInfo();
+
+ rtl::Reference<ODatabaseMetaDataResultSet> pResult = new ODatabaseMetaDataResultSet(pRecordset);
+ pResult->setTypeInfoMap(ADOS::isJetEngine(m_pConnection->getEngineType()));
+ return pResult;
+}
+
+Reference< XResultSet > SAL_CALL ODatabaseMetaData::getCatalogs( )
+{
+ OLEVariant vtEmpty;
+ vtEmpty.setNoArg();
+
+ ADORecordset *pRecordset = nullptr;
+ m_rADOConnection.OpenSchema(adSchemaCatalogs,vtEmpty,vtEmpty,&pRecordset);
+ ADOS::ThrowException(m_rADOConnection,*this);
+
+ rtl::Reference<ODatabaseMetaDataResultSet> pResult = new ODatabaseMetaDataResultSet(pRecordset);
+ pResult->setCatalogsMap();
+
+ return pResult;
+}
+
+OUString ODatabaseMetaData::impl_getCatalogSeparator_throw( )
+{
+ return getLiteral(DBLITERAL_CATALOG_SEPARATOR);
+}
+
+Reference< XResultSet > SAL_CALL ODatabaseMetaData::getSchemas( )
+{
+ OLEVariant vtEmpty;
+ vtEmpty.setNoArg();
+
+ ADORecordset *pRecordset = nullptr;
+ m_rADOConnection.OpenSchema(adSchemaSchemata,vtEmpty,vtEmpty,&pRecordset);
+ ADOS::ThrowException(m_rADOConnection,*this);
+
+ rtl::Reference<ODatabaseMetaDataResultSet> pResult = new ODatabaseMetaDataResultSet(pRecordset);
+ pResult->setSchemasMap();
+ return pResult;
+}
+
+Reference< XResultSet > SAL_CALL ODatabaseMetaData::getColumnPrivileges(
+ const Any& catalog, const OUString& schema, const OUString& table,
+ const OUString& columnNamePattern )
+{
+ ADORecordset *pRecordset = m_rADOConnection.getColumnPrivileges(catalog,schema,table,columnNamePattern);
+ ADOS::ThrowException(m_rADOConnection,*this);
+
+ rtl::Reference<ODatabaseMetaDataResultSet> pResult = new ODatabaseMetaDataResultSet(pRecordset);
+ pResult->setColumnPrivilegesMap();
+ return pResult;
+}
+
+Reference< XResultSet > SAL_CALL ODatabaseMetaData::getColumns(
+ const Any& catalog, const OUString& schemaPattern, const OUString& tableNamePattern,
+ const OUString& columnNamePattern )
+{
+ ADORecordset *pRecordset = m_rADOConnection.getColumns(catalog,schemaPattern,tableNamePattern,columnNamePattern);
+ ADOS::ThrowException(m_rADOConnection,*this);
+
+ rtl::Reference<ODatabaseMetaDataResultSet> pResult = new ODatabaseMetaDataResultSet(pRecordset);
+ pResult->setColumnsMap();
+
+ return pResult;
+}
+
+Reference< XResultSet > SAL_CALL ODatabaseMetaData::getTables(
+ const Any& catalog, const OUString& schemaPattern,
+ const OUString& tableNamePattern, const Sequence< OUString >& types )
+{
+ ADORecordset *pRecordset = m_rADOConnection.getTables(catalog,schemaPattern,tableNamePattern,types);
+ ADOS::ThrowException(m_rADOConnection,*this);
+
+ rtl::Reference<ODatabaseMetaDataResultSet> pResult = new ODatabaseMetaDataResultSet(pRecordset);
+ pResult->setTablesMap();
+
+ return pResult;
+}
+
+Reference< XResultSet > SAL_CALL ODatabaseMetaData::getProcedureColumns(
+ const Any& catalog, const OUString& schemaPattern,
+ const OUString& procedureNamePattern, const OUString& columnNamePattern )
+{
+ ADORecordset *pRecordset = m_rADOConnection.getProcedureColumns(catalog,schemaPattern,procedureNamePattern,columnNamePattern);
+ ADOS::ThrowException(m_rADOConnection,*this);
+
+ rtl::Reference<ODatabaseMetaDataResultSet> pResult = new ODatabaseMetaDataResultSet(pRecordset);
+ pResult->setProcedureColumnsMap();
+
+ return pResult;
+}
+
+Reference< XResultSet > SAL_CALL ODatabaseMetaData::getProcedures(
+ const Any& catalog, const OUString& schemaPattern,
+ const OUString& procedureNamePattern )
+{
+ // Create elements used in the array
+ ADORecordset *pRecordset = m_rADOConnection.getProcedures(catalog,schemaPattern,procedureNamePattern);
+ ADOS::ThrowException(m_rADOConnection,*this);
+
+ rtl::Reference<ODatabaseMetaDataResultSet> pResult = new ODatabaseMetaDataResultSet(pRecordset);
+ pResult->setProceduresMap();
+
+ return pResult;
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxBinaryLiteralLength( )
+{
+ return getMaxSize(DBLITERAL_BINARY_LITERAL);
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxRowSize( )
+{
+ return getInt32Property("Maximum Row Size");
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxCatalogNameLength( )
+{
+ return getMaxSize(DBLITERAL_CATALOG_NAME);
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxCharLiteralLength( )
+{
+ return getMaxSize(DBLITERAL_CHAR_LITERAL);
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxColumnNameLength( )
+{
+ return getMaxSize(DBLITERAL_COLUMN_NAME);
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxColumnsInIndex( )
+{
+ return 0;
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxCursorNameLength( )
+{
+ return getMaxSize(DBLITERAL_CURSOR_NAME);
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxConnections( )
+{
+ return getInt32Property("Active Sessions");
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxColumnsInTable( )
+{
+ return getInt32Property("Max Columns in Table");
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxStatementLength( )
+{
+ return getMaxSize(DBLITERAL_TEXT_COMMAND);
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxTableNameLength( )
+{
+ return getMaxSize(DBLITERAL_TABLE_NAME);
+}
+
+sal_Int32 ODatabaseMetaData::impl_getMaxTablesInSelect_throw( )
+{
+ return getInt32Property("Maximum Tables in SELECT");
+}
+
+Reference< XResultSet > SAL_CALL ODatabaseMetaData::getExportedKeys(
+ const Any& catalog, const OUString& schema, const OUString& table )
+{
+ ADORecordset *pRecordset = m_rADOConnection.getExportedKeys(catalog,schema,table);
+ ADOS::ThrowException(m_rADOConnection,*this);
+
+ rtl::Reference<ODatabaseMetaDataResultSet> pResult = new ODatabaseMetaDataResultSet(pRecordset);
+ pResult->setCrossReferenceMap();
+
+ return pResult;
+}
+
+Reference< XResultSet > SAL_CALL ODatabaseMetaData::getImportedKeys(
+ const Any& catalog, const OUString& schema, const OUString& table )
+{
+ ADORecordset *pRecordset = m_rADOConnection.getImportedKeys(catalog,schema,table);
+ ADOS::ThrowException(m_rADOConnection,*this);
+
+ rtl::Reference<ODatabaseMetaDataResultSet> pResult = new ODatabaseMetaDataResultSet(pRecordset);
+ pResult->setCrossReferenceMap();
+
+ return pResult;
+}
+
+Reference< XResultSet > SAL_CALL ODatabaseMetaData::getPrimaryKeys(
+ const Any& catalog, const OUString& schema, const OUString& table )
+{
+ ADORecordset *pRecordset = m_rADOConnection.getPrimaryKeys(catalog,schema,table);
+ ADOS::ThrowException(m_rADOConnection,*this);
+
+ rtl::Reference<ODatabaseMetaDataResultSet> pResult = new ODatabaseMetaDataResultSet(pRecordset);
+ pResult->setPrimaryKeysMap();
+
+ return pResult;
+}
+
+Reference< XResultSet > SAL_CALL ODatabaseMetaData::getIndexInfo(
+ const Any& catalog, const OUString& schema, const OUString& table,
+ sal_Bool unique, sal_Bool approximate )
+{
+ ADORecordset *pRecordset = m_rADOConnection.getIndexInfo(catalog,schema,table,unique,approximate);
+ ADOS::ThrowException(m_rADOConnection,*this);
+
+ rtl::Reference<ODatabaseMetaDataResultSet> pResult = new ODatabaseMetaDataResultSet(pRecordset);
+ pResult->setIndexInfoMap();
+
+ return pResult;
+}
+
+Reference< XResultSet > SAL_CALL ODatabaseMetaData::getTablePrivileges(
+ const Any& catalog, const OUString& schemaPattern, const OUString& tableNamePattern )
+{
+ Reference< XResultSet > xRef;
+ if(!ADOS::isJetEngine(m_pConnection->getEngineType()))
+ { // the jet provider doesn't support this method
+ // Create elements used in the array
+
+ ADORecordset *pRecordset = m_rADOConnection.getTablePrivileges(catalog,schemaPattern,tableNamePattern);
+ ADOS::ThrowException(m_rADOConnection,*this);
+
+ rtl::Reference<ODatabaseMetaDataResultSet> pResult = new ODatabaseMetaDataResultSet(pRecordset);
+ pResult->setTablePrivilegesMap();
+ xRef = pResult;
+ }
+ else
+ {
+ rtl::Reference<::connectivity::ODatabaseMetaDataResultSet> pResult = new ::connectivity::ODatabaseMetaDataResultSet(::connectivity::ODatabaseMetaDataResultSet::eTablePrivileges);
+ xRef = pResult;
+ ::connectivity::ODatabaseMetaDataResultSet::ORows aRows;
+ ::connectivity::ODatabaseMetaDataResultSet::ORow aRow(8);
+ aRows.reserve(8);
+
+ aRow[0] = ::connectivity::ODatabaseMetaDataResultSet::getEmptyValue();
+ aRow[1] = ::connectivity::ODatabaseMetaDataResultSet::getEmptyValue();
+ aRow[2] = new ::connectivity::ORowSetValueDecorator(tableNamePattern);
+ aRow[3] = ::connectivity::ODatabaseMetaDataResultSet::getEmptyValue();
+ aRow[4] = ::connectivity::ODatabaseMetaDataResultSet::getEmptyValue();
+ aRow[5] = new ::connectivity::ORowSetValueDecorator(getUserName());
+ aRow[6] = ::connectivity::ODatabaseMetaDataResultSet::getSelectValue();
+ aRow[7] = new ::connectivity::ORowSetValueDecorator(OUString("NO"));
+
+ aRows.push_back(aRow);
+ aRow[6] = ::connectivity::ODatabaseMetaDataResultSet::getInsertValue();
+ aRows.push_back(aRow);
+ aRow[6] = ::connectivity::ODatabaseMetaDataResultSet::getDeleteValue();
+ aRows.push_back(aRow);
+ aRow[6] = ::connectivity::ODatabaseMetaDataResultSet::getUpdateValue();
+ aRows.push_back(aRow);
+ aRow[6] = ::connectivity::ODatabaseMetaDataResultSet::getCreateValue();
+ aRows.push_back(aRow);
+ aRow[6] = ::connectivity::ODatabaseMetaDataResultSet::getReadValue();
+ aRows.push_back(aRow);
+ aRow[6] = ::connectivity::ODatabaseMetaDataResultSet::getAlterValue();
+ aRows.push_back(aRow);
+ aRow[6] = ::connectivity::ODatabaseMetaDataResultSet::getDropValue();
+ aRows.push_back(aRow);
+ pResult->setRows(std::move(aRows));
+ }
+
+ return xRef;
+}
+
+Reference< XResultSet > SAL_CALL ODatabaseMetaData::getCrossReference(
+ const Any& primaryCatalog, const OUString& primarySchema,
+ const OUString& primaryTable, const Any& foreignCatalog,
+ const OUString& foreignSchema, const OUString& foreignTable )
+{
+ ADORecordset *pRecordset = m_rADOConnection.getCrossReference(primaryCatalog,primarySchema,primaryTable,foreignCatalog,foreignSchema,foreignTable);
+ ADOS::ThrowException(m_rADOConnection,*this);
+
+ rtl::Reference<ODatabaseMetaDataResultSet> pResult = new ODatabaseMetaDataResultSet(pRecordset);
+ pResult->setCrossReferenceMap();
+
+ return pResult;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::doesMaxRowSizeIncludeBlobs( )
+{
+ return getBoolProperty("Maximum Row Size Includes BLOB");
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::storesLowerCaseQuotedIdentifiers( )
+{
+ return (getInt32Property("Identifier Case Sensitivity") & DBPROPVAL_IC_LOWER) == DBPROPVAL_IC_LOWER ;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::storesLowerCaseIdentifiers( )
+{
+ return (getInt32Property("Identifier Case Sensitivity") & DBPROPVAL_IC_LOWER) == DBPROPVAL_IC_LOWER ;
+}
+
+bool ODatabaseMetaData::impl_storesMixedCaseQuotedIdentifiers_throw( )
+{
+ return (getInt32Property("Identifier Case Sensitivity") & DBPROPVAL_IC_MIXED) == DBPROPVAL_IC_MIXED ;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::storesMixedCaseIdentifiers( )
+{
+ return (getInt32Property("Identifier Case Sensitivity") & DBPROPVAL_IC_MIXED) == DBPROPVAL_IC_MIXED ;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::storesUpperCaseQuotedIdentifiers( )
+{
+ return (getInt32Property("Identifier Case Sensitivity") & DBPROPVAL_IC_UPPER) == DBPROPVAL_IC_UPPER ;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::storesUpperCaseIdentifiers( )
+{
+ return (getInt32Property("Identifier Case Sensitivity") & DBPROPVAL_IC_UPPER) == DBPROPVAL_IC_UPPER ;
+}
+
+bool ODatabaseMetaData::impl_supportsAlterTableWithAddColumn_throw( )
+{
+ return true;
+}
+
+bool ODatabaseMetaData::impl_supportsAlterTableWithDropColumn_throw( )
+{
+ return true;
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxIndexLength( )
+{
+ return getInt32Property("Maximum Index Size");
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsNonNullableColumns( )
+{
+ return getInt32Property("NULL Concatenation Behavior") == DBPROPVAL_CB_NON_NULL;
+}
+
+OUString SAL_CALL ODatabaseMetaData::getCatalogTerm( )
+{
+ return getStringProperty("Catalog Term");
+}
+
+OUString ODatabaseMetaData::impl_getIdentifierQuoteString_throw( )
+{
+ return getLiteral(DBLITERAL_QUOTE_PREFIX);
+
+}
+
+OUString SAL_CALL ODatabaseMetaData::getExtraNameCharacters( )
+{
+ return OUString();
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsDifferentTableCorrelationNames( )
+{
+ return isCapable(DBLITERAL_CORRELATION_NAME);
+}
+
+bool ODatabaseMetaData::impl_isCatalogAtStart_throw( )
+{
+ return getInt32Property("Catalog Location") == DBPROPVAL_CL_START;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::dataDefinitionIgnoredInTransactions( )
+{
+ return getInt32Property("Transaction DDL") == DBPROPVAL_TC_DDL_IGNORE;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::dataDefinitionCausesTransactionCommit( )
+{
+ return getInt32Property("Transaction DDL") == DBPROPVAL_TC_DDL_COMMIT;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsDataManipulationTransactionsOnly( )
+{
+ return getInt32Property("Transaction DDL") == DBPROPVAL_TC_DML;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsDataDefinitionAndDataManipulationTransactions( )
+{
+ return getInt32Property("Transaction DDL") == DBPROPVAL_TC_ALL;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsPositionedDelete( )
+{
+ return true;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsPositionedUpdate( )
+{
+ return true;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsOpenStatementsAcrossRollback( )
+{
+ return getInt32Property("Prepare Abort Behavior") == DBPROPVAL_CB_PRESERVE;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsOpenStatementsAcrossCommit( )
+{
+ return getInt32Property("Prepare Commit Behavior") == DBPROPVAL_CB_PRESERVE;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsOpenCursorsAcrossCommit( )
+{
+ return (getInt32Property("Isolation Retention") & DBPROPVAL_TR_COMMIT) == DBPROPVAL_TR_COMMIT;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsOpenCursorsAcrossRollback( )
+{
+ return (getInt32Property("Isolation Retention") & DBPROPVAL_TR_ABORT) == DBPROPVAL_TR_ABORT;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsTransactionIsolationLevel( sal_Int32 level )
+{
+ bool bValue(false);
+
+ sal_Int32 nTxn = getInt32Property("Isolation Levels");
+ if(level == TransactionIsolation::NONE)
+ bValue = true;
+ else if(level == TransactionIsolation::READ_UNCOMMITTED)
+ bValue = (nTxn & DBPROPVAL_TI_READUNCOMMITTED) == DBPROPVAL_TI_READUNCOMMITTED;
+ else if(level == TransactionIsolation::READ_COMMITTED)
+ bValue = (nTxn & DBPROPVAL_TI_READCOMMITTED) == DBPROPVAL_TI_READCOMMITTED;
+ else if(level == TransactionIsolation::REPEATABLE_READ)
+ bValue = (nTxn & DBPROPVAL_TI_REPEATABLEREAD) == DBPROPVAL_TI_REPEATABLEREAD;
+ else if(level == TransactionIsolation::SERIALIZABLE)
+ bValue = (nTxn & DBPROPVAL_TI_SERIALIZABLE) == DBPROPVAL_TI_SERIALIZABLE;
+
+ return bValue;
+}
+
+bool ODatabaseMetaData::impl_supportsSchemasInDataManipulation_throw( )
+{
+ return (getInt32Property("Schema Usage") & DBPROPVAL_SU_DML_STATEMENTS) == DBPROPVAL_SU_DML_STATEMENTS;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsANSI92FullSQL( )
+{
+ sal_Int32 nProp = getInt32Property("SQL Support");
+ return (nProp == 512) || ((nProp & DBPROPVAL_SQL_ANSI92_FULL) == DBPROPVAL_SQL_ANSI92_FULL);
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsANSI92EntryLevelSQL( )
+{
+ sal_Int32 nProp = getInt32Property("SQL Support");
+ return (nProp == 512) || ((nProp & DBPROPVAL_SQL_ANSI92_ENTRY) == DBPROPVAL_SQL_ANSI92_ENTRY);
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsIntegrityEnhancementFacility( )
+{
+ sal_Int32 nProp = getInt32Property("SQL Support");
+ return (nProp == 512) || ((nProp & DBPROPVAL_SQL_ANSI89_IEF) == DBPROPVAL_SQL_ANSI89_IEF);
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsSchemasInIndexDefinitions( )
+{
+ return (getInt32Property("Schema Usage") & DBPROPVAL_SU_INDEX_DEFINITION) == DBPROPVAL_SU_INDEX_DEFINITION;
+}
+
+bool ODatabaseMetaData::impl_supportsSchemasInTableDefinitions_throw( )
+{
+ return (getInt32Property("Schema Usage") & DBPROPVAL_SU_TABLE_DEFINITION) == DBPROPVAL_SU_TABLE_DEFINITION;
+}
+
+bool ODatabaseMetaData::impl_supportsCatalogsInTableDefinitions_throw( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsCatalogsInIndexDefinitions( )
+{
+ return false;
+}
+
+bool ODatabaseMetaData::impl_supportsCatalogsInDataManipulation_throw( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsOuterJoins( )
+{
+ if ( ADOS::isJetEngine(m_pConnection->getEngineType()) )
+ return true;
+ return getBoolProperty("Outer Join Capabilities");
+}
+
+Reference< XResultSet > SAL_CALL ODatabaseMetaData::getTableTypes( )
+{
+ return new ::connectivity::ODatabaseMetaDataResultSet(::connectivity::ODatabaseMetaDataResultSet::eTableTypes);
+}
+
+sal_Int32 ODatabaseMetaData::impl_getMaxStatements_throw( )
+{
+ return 0;
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxProcedureNameLength( )
+{
+ return getMaxSize(DBLITERAL_PROCEDURE_NAME);
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxSchemaNameLength( )
+{
+ return getMaxSize(DBLITERAL_SCHEMA_NAME);
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsTransactions( )
+{
+ return getInt32Property("Transaction DDL") == DBPROPVAL_TC_NONE;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::allProceduresAreCallable( )
+{
+ return true;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsStoredProcedures( )
+{
+ return true;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsSelectForUpdate( )
+{
+ return true;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::allTablesAreSelectable( )
+{
+ return true;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::isReadOnly( )
+{
+ return getBoolProperty("Read-Only Data Source");
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::usesLocalFiles( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::usesLocalFilePerTable( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsTypeConversion( )
+{
+ return true;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::nullPlusNonNullIsNull( )
+{
+ return getInt32Property("NULL Concatenation Behavior") == DBPROPVAL_CB_NULL;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsColumnAliasing( )
+{
+ return isCapable(DBLITERAL_COLUMN_ALIAS);
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsTableCorrelationNames( )
+{
+ return isCapable(DBLITERAL_CORRELATION_NAME);
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsConvert( sal_Int32 /*fromType*/, sal_Int32 /*toType*/ )
+{
+ return getBoolProperty("Rowset Conversions on Command");
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsExpressionsInOrderBy( )
+{
+ return getBoolProperty("ORDER BY Columns in Select List");
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsGroupBy( )
+{
+ return getInt32Property("GROUP BY Support") != DBPROPVAL_GB_NOT_SUPPORTED;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsGroupByBeyondSelect( )
+{
+ return getInt32Property("GROUP BY Support") != DBPROPVAL_GB_CONTAINS_SELECT;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsGroupByUnrelated( )
+{
+ return getInt32Property("GROUP BY Support") == DBPROPVAL_GB_NO_RELATION;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsMultipleTransactions( )
+{
+ return true;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsMultipleResultSets( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsLikeEscapeClause( )
+{
+ return isCapable(DBLITERAL_ESCAPE_PERCENT);
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsOrderByUnrelated( )
+{
+ return getBoolProperty("ORDER BY Columns in Select List");
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsUnion( )
+{
+ return true;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsUnionAll( )
+{
+ return true;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsMixedCaseIdentifiers( )
+{
+ return (getInt32Property("Identifier Case Sensitivity") & DBPROPVAL_IC_MIXED) == DBPROPVAL_IC_MIXED;
+}
+
+bool ODatabaseMetaData::impl_supportsMixedCaseQuotedIdentifiers_throw( )
+{
+ return (getInt32Property("Identifier Case Sensitivity") & DBPROPVAL_IC_MIXED) == DBPROPVAL_IC_MIXED;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::nullsAreSortedAtEnd( )
+{
+ return (getInt32Property("NULL Collation Order") & DBPROPVAL_NC_END) == DBPROPVAL_NC_END;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::nullsAreSortedAtStart( )
+{
+ return (getInt32Property("NULL Collation Order") & DBPROPVAL_NC_START) == DBPROPVAL_NC_START;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::nullsAreSortedHigh( )
+{
+ return (getInt32Property("NULL Collation Order") & DBPROPVAL_NC_HIGH) == DBPROPVAL_NC_HIGH;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::nullsAreSortedLow( )
+{
+ return (getInt32Property("NULL Collation Order") & DBPROPVAL_NC_LOW) == DBPROPVAL_NC_LOW;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsSchemasInProcedureCalls( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsSchemasInPrivilegeDefinitions( )
+{
+ return (getInt32Property("Schema Usage") & DBPROPVAL_SU_PRIVILEGE_DEFINITION) == DBPROPVAL_SU_PRIVILEGE_DEFINITION;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsCatalogsInProcedureCalls( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsCatalogsInPrivilegeDefinitions( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsCorrelatedSubqueries( )
+{
+ return (getInt32Property("Subquery Support") & DBPROPVAL_SQ_CORRELATEDSUBQUERIES) == DBPROPVAL_SQ_CORRELATEDSUBQUERIES;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsSubqueriesInComparisons( )
+{
+ return (getInt32Property("Subquery Support") & DBPROPVAL_SQ_COMPARISON) == DBPROPVAL_SQ_COMPARISON;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsSubqueriesInExists( )
+{
+ return (getInt32Property("Subquery Support") & DBPROPVAL_SQ_EXISTS) == DBPROPVAL_SQ_EXISTS;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsSubqueriesInIns( )
+{
+ return (getInt32Property("Subquery Support") & DBPROPVAL_SQ_IN) == DBPROPVAL_SQ_IN;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsSubqueriesInQuantifieds( )
+{
+ return (getInt32Property("Subquery Support") & DBPROPVAL_SQ_QUANTIFIED) == DBPROPVAL_SQ_QUANTIFIED;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsANSI92IntermediateSQL( )
+{
+ sal_Int32 nProp = getInt32Property("SQL Support");
+ return (nProp == 512) || ((nProp & DBPROPVAL_SQL_ANSI92_INTERMEDIATE) == DBPROPVAL_SQL_ANSI92_INTERMEDIATE);
+}
+
+OUString SAL_CALL ODatabaseMetaData::getURL( )
+{
+ return "sdbc:ado:"+ m_rADOConnection.GetConnectionString();
+}
+
+OUString SAL_CALL ODatabaseMetaData::getUserName( )
+{
+ return getStringProperty("User Name");
+}
+
+OUString SAL_CALL ODatabaseMetaData::getDriverName( )
+{
+ return getStringProperty("Provider Friendly Name");
+}
+
+OUString SAL_CALL ODatabaseMetaData::getDriverVersion( )
+{
+ return getStringProperty("Provider Version");
+}
+
+OUString SAL_CALL ODatabaseMetaData::getDatabaseProductVersion( )
+{
+ return getStringProperty("DBMS Version");
+}
+
+OUString SAL_CALL ODatabaseMetaData::getDatabaseProductName( )
+{
+ return getStringProperty("DBMS Name");
+}
+
+OUString SAL_CALL ODatabaseMetaData::getProcedureTerm( )
+{
+ return getStringProperty("Procedure Term");
+}
+
+OUString SAL_CALL ODatabaseMetaData::getSchemaTerm( )
+{
+ return getStringProperty("Schema Term");
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getDriverMajorVersion( )
+{
+ return 1;
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getDefaultTransactionIsolation( )
+{
+ sal_Int32 nRet = TransactionIsolation::NONE;
+ switch(m_rADOConnection.get_IsolationLevel())
+ {
+ case adXactReadCommitted:
+ nRet = TransactionIsolation::READ_COMMITTED;
+ break;
+ case adXactRepeatableRead:
+ nRet = TransactionIsolation::REPEATABLE_READ;
+ break;
+ case adXactSerializable:
+ nRet = TransactionIsolation::SERIALIZABLE;
+ break;
+ case adXactReadUncommitted:
+ nRet = TransactionIsolation::READ_UNCOMMITTED;
+ break;
+ default:
+ ;
+ }
+ return nRet;
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getDriverMinorVersion( )
+{
+ return 0;
+}
+
+OUString SAL_CALL ODatabaseMetaData::getSQLKeywords( )
+{
+ WpADORecordset aRecordset;
+ OLEVariant vtEmpty;
+ vtEmpty.setNoArg();
+ m_rADOConnection.OpenSchema(adSchemaDBInfoKeywords,vtEmpty,vtEmpty,&aRecordset);
+ OSL_ENSURE(aRecordset,"getSQLKeywords: no resultset!");
+ ADOS::ThrowException(m_rADOConnection,*this);
+ if ( aRecordset )
+ {
+ aRecordset.MoveFirst();
+ OLEVariant aValue;
+ OUString aRet;
+ while(!aRecordset.IsAtEOF())
+ {
+ WpOLEAppendCollection<ADOFields, WpADOField> aFields(aRecordset.GetFields());
+ WpADOField aField(aFields.GetItem(0));
+ aField.get_Value(aValue);
+ aRet += aValue.getString() + ",";
+ aRecordset.MoveNext();
+ }
+ aRecordset.Close();
+ if ( !aRet.isEmpty() )
+ return aRet.copy(0,aRet.lastIndexOf(','));
+ }
+ return OUString();
+}
+
+OUString SAL_CALL ODatabaseMetaData::getSearchStringEscape( )
+{
+ return getLiteral(DBLITERAL_ESCAPE_PERCENT);
+}
+
+OUString SAL_CALL ODatabaseMetaData::getStringFunctions( )
+{
+ return OUString();
+}
+
+OUString SAL_CALL ODatabaseMetaData::getTimeDateFunctions( )
+{
+ return OUString();
+}
+
+OUString SAL_CALL ODatabaseMetaData::getSystemFunctions( )
+{
+ return OUString();
+}
+
+OUString SAL_CALL ODatabaseMetaData::getNumericFunctions( )
+{
+ return OUString();
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsExtendedSQLGrammar( )
+{
+ sal_Int32 nProp = getInt32Property("SQL Support");
+ return (nProp == 512) || ((nProp & DBPROPVAL_SQL_ODBC_EXTENDED) == DBPROPVAL_SQL_ODBC_EXTENDED);
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsCoreSQLGrammar( )
+{
+ sal_Int32 nProp = getInt32Property("SQL Support");
+ return (nProp == 512) || ((nProp & DBPROPVAL_SQL_ODBC_CORE) == DBPROPVAL_SQL_ODBC_CORE);
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsMinimumSQLGrammar( )
+{
+ sal_Int32 nProp = getInt32Property("SQL Support");
+ return (nProp == 512) || ((nProp & DBPROPVAL_SQL_ODBC_MINIMUM) == DBPROPVAL_SQL_ODBC_MINIMUM);
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsFullOuterJoins( )
+{
+ if ( ADOS::isJetEngine(m_pConnection->getEngineType()) )
+ return true;
+ return (getInt32Property("Outer Join Capabilities") & 0x00000004L) == 0x00000004L;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsLimitedOuterJoins( )
+{
+ return supportsFullOuterJoins( );
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxColumnsInGroupBy( )
+{
+ return getInt32Property("Max Columns in GROUP BY");
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxColumnsInOrderBy( )
+{
+ return getInt32Property("Max Columns in ORDER BY");
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxColumnsInSelect( )
+{
+ return 0;
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxUserNameLength( )
+{
+ return getMaxSize(DBLITERAL_USER_NAME);
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsResultSetType( sal_Int32 /*setType*/ )
+{
+ return true;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsResultSetConcurrency( sal_Int32 /*setType*/, sal_Int32 /*concurrency*/ )
+{
+ return true;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::ownUpdatesAreVisible( sal_Int32 setType )
+{
+ return ResultSetType::FORWARD_ONLY != setType;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::ownDeletesAreVisible( sal_Int32 setType )
+{
+ return ResultSetType::FORWARD_ONLY != setType;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::ownInsertsAreVisible( sal_Int32 setType )
+{
+ return ResultSetType::FORWARD_ONLY != setType;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::othersUpdatesAreVisible( sal_Int32 setType )
+{
+ return ResultSetType::FORWARD_ONLY != setType;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::othersDeletesAreVisible( sal_Int32 setType )
+{
+ return ResultSetType::FORWARD_ONLY != setType;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::othersInsertsAreVisible( sal_Int32 setType )
+{
+ return ResultSetType::FORWARD_ONLY != setType;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::updatesAreDetected( sal_Int32 setType )
+{
+ return ResultSetType::FORWARD_ONLY != setType;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::deletesAreDetected( sal_Int32 setType )
+{
+ return ResultSetType::FORWARD_ONLY != setType;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::insertsAreDetected( sal_Int32 setType )
+{
+ return ResultSetType::FORWARD_ONLY != setType;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsBatchUpdates( )
+{
+ return true;
+}
+
+Reference< XResultSet > SAL_CALL ODatabaseMetaData::getUDTs( const Any& /*catalog*/, const OUString& /*schemaPattern*/, const OUString& /*typeNamePattern*/, const Sequence< sal_Int32 >& /*types*/ )
+{
+ ::dbtools::throwFeatureNotImplementedSQLException( "XDatabaseMetaData::getUDTs", *this );
+ return Reference< XResultSet >();
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/ado/ADatabaseMetaDataImpl.cxx b/connectivity/source/drivers/ado/ADatabaseMetaDataImpl.cxx
new file mode 100644
index 0000000000..b787207060
--- /dev/null
+++ b/connectivity/source/drivers/ado/ADatabaseMetaDataImpl.cxx
@@ -0,0 +1,543 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <string_view>
+
+#include <ado/ADatabaseMetaData.hxx>
+#include <ado/ADatabaseMetaDataResultSetMetaData.hxx>
+#include <ado/Awrapado.hxx>
+#include <ado/AGroup.hxx>
+#include <ado/adoimp.hxx>
+#include <ado/AIndex.hxx>
+#include <ado/AKey.hxx>
+#include <ado/ATable.hxx>
+
+#include <systools/win32/oleauto.hxx>
+
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <com/sun/star/sdbc/ProcedureResult.hpp>
+#include <com/sun/star/sdbc/ColumnValue.hpp>
+#ifdef DELETE
+#undef DELETE
+#endif
+#include <com/sun/star/sdbcx/Privilege.hpp>
+#include <com/sun/star/sdbcx/PrivilegeObject.hpp>
+#include <com/sun/star/sdbc/KeyRule.hpp>
+#include <com/sun/star/sdbcx/KeyType.hpp>
+
+using namespace connectivity::ado;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::uno;
+
+
+void ODatabaseMetaData::fillLiterals()
+{
+ WpADORecordset aRecordset;
+ OLEVariant vtEmpty;
+ vtEmpty.setNoArg();
+ m_rADOConnection.OpenSchema(adSchemaDBInfoLiterals,vtEmpty,vtEmpty,&aRecordset);
+
+ ADOS::ThrowException(m_rADOConnection,*this);
+
+ OSL_ENSURE(aRecordset,"fillLiterals: no resultset!");
+ if ( aRecordset )
+ {
+ aRecordset.MoveFirst();
+ OLEVariant aValue;
+ LiteralInfo aInfo;
+ while(!aRecordset.IsAtEOF())
+ {
+ WpOLEAppendCollection<ADOFields, WpADOField> aFields(aRecordset.GetFields());
+ WpADOField aField(aFields.GetItem(1));
+ aInfo.pwszLiteralValue = aField.get_Value().getString();
+ aField = aFields.GetItem(5);
+ aInfo.fSupported = aField.get_Value().getBool();
+ aField = aFields.GetItem(6);
+ aInfo.cchMaxLen = aField.get_Value().getUInt32();
+
+ aField = aFields.GetItem(4);
+ sal_uInt32 nId = aField.get_Value().getUInt32();
+ m_aLiteralInfo[nId] = aInfo;
+
+ aRecordset.MoveNext();
+ }
+ aRecordset.Close();
+ }
+}
+
+sal_Int32 ODatabaseMetaData::getMaxSize(sal_uInt32 _nId)
+{
+ if(m_aLiteralInfo.empty())
+ fillLiterals();
+
+ sal_Int32 nSize = 0;
+ std::map<sal_uInt32,LiteralInfo>::const_iterator aIter = m_aLiteralInfo.find(_nId);
+ if(aIter != m_aLiteralInfo.end() && (*aIter).second.fSupported)
+ nSize = (static_cast<sal_Int32>((*aIter).second.cchMaxLen) == -1) ? 0 : (*aIter).second.cchMaxLen;
+ return nSize;
+}
+
+bool ODatabaseMetaData::isCapable(sal_uInt32 _nId)
+{
+ if(m_aLiteralInfo.empty())
+ fillLiterals();
+ bool bSupported = false;
+ std::map<sal_uInt32,LiteralInfo>::const_iterator aIter = m_aLiteralInfo.find(_nId);
+ if(aIter != m_aLiteralInfo.end())
+ bSupported = (*aIter).second.fSupported;
+ return bSupported;
+}
+
+
+OUString ODatabaseMetaData::getLiteral(sal_uInt32 _nId)
+{
+ if(m_aLiteralInfo.empty())
+ fillLiterals();
+ OUString sStr;
+ std::map<sal_uInt32,LiteralInfo>::const_iterator aIter = m_aLiteralInfo.find(_nId);
+ if(aIter != m_aLiteralInfo.end() && (*aIter).second.fSupported)
+ sStr = (*aIter).second.pwszLiteralValue;
+ return sStr;
+}
+
+
+void ODatabaseMetaDataResultSetMetaData::setColumnPrivilegesMap()
+{
+ m_mColumns[8] = OColumn(OUString(),"IS_GRANTABLE",
+ ColumnValue::NULLABLE,
+ 3,3,0,
+ DataType::VARCHAR);
+}
+
+void ODatabaseMetaDataResultSetMetaData::setColumnsMap()
+{
+ m_mColumns[6] = OColumn(OUString(),"TYPE_NAME",
+ ColumnValue::NO_NULLS,
+ 0,0,0,
+ DataType::VARCHAR);
+ m_mColumns[11] = OColumn(OUString(),"NULLABLE",
+ ColumnValue::NO_NULLS,
+ 1,1,0,
+ DataType::INTEGER);
+ m_mColumns[12] = OColumn(OUString(),"REMARKS",
+ ColumnValue::NULLABLE,
+ 0,0,0,
+ DataType::VARCHAR);
+ m_mColumns[13] = OColumn(OUString(),"COLUMN_DEF",
+ ColumnValue::NULLABLE,
+ 0,0,0,
+ DataType::VARCHAR);
+ m_mColumns[14] = OColumn(OUString(),"SQL_DATA_TYPE",
+ ColumnValue::NO_NULLS,
+ 1,1,0,
+ DataType::INTEGER);
+ m_mColumns[15] = OColumn(OUString(),"SQL_DATETIME_SUB",
+ ColumnValue::NO_NULLS,
+ 1,1,0,
+ DataType::INTEGER);
+ m_mColumns[16] = OColumn(OUString(),"CHAR_OCTET_LENGTH",
+ ColumnValue::NO_NULLS,
+ 1,1,0,
+ DataType::INTEGER);
+}
+
+void ODatabaseMetaDataResultSetMetaData::setTablesMap()
+{
+ m_mColumns[5] = OColumn(OUString(),"REMARKS",
+ ColumnValue::NULLABLE,
+ 0,0,0,
+ DataType::VARCHAR);
+}
+
+void ODatabaseMetaDataResultSetMetaData::setProcedureColumnsMap()
+{
+ m_mColumns[12] = OColumn(OUString(),"NULLABLE",
+ ColumnValue::NO_NULLS,
+ 1,1,0,
+ DataType::INTEGER);
+}
+
+void ODatabaseMetaDataResultSetMetaData::setPrimaryKeysMap()
+{
+ m_mColumns[5] = OColumn(OUString(),"KEY_SEQ",
+ ColumnValue::NO_NULLS,
+ 1,1,0,
+ DataType::INTEGER);
+ m_mColumns[6] = OColumn(OUString(),"PK_NAME",
+ ColumnValue::NULLABLE,
+ 0,0,0,
+ DataType::VARCHAR);
+}
+
+void ODatabaseMetaDataResultSetMetaData::setIndexInfoMap()
+{
+ m_mColumns[4] = OColumn(OUString(),"NON_UNIQUE",
+ ColumnValue::NO_NULLS,
+ 1,1,0,
+ DataType::BIT);
+ m_mColumns[5] = OColumn(OUString(),"INDEX_QUALIFIER",
+ ColumnValue::NULLABLE,
+ 0,0,0,
+ DataType::VARCHAR);
+ m_mColumns[10] = OColumn(OUString(),"ASC_OR_DESC",
+ ColumnValue::NULLABLE,
+ 0,0,0,
+ DataType::VARCHAR);
+}
+
+void ODatabaseMetaDataResultSetMetaData::setTablePrivilegesMap()
+{
+ m_mColumns[6] = OColumn(OUString(),"PRIVILEGE",
+ ColumnValue::NULLABLE,
+ 0,0,0,
+ DataType::VARCHAR);
+ m_mColumns[7] = OColumn(OUString(),"IS_GRANTABLE",
+ ColumnValue::NULLABLE,
+ 0,0,0,
+ DataType::VARCHAR);
+}
+
+void ODatabaseMetaDataResultSetMetaData::setCrossReferenceMap()
+{
+ m_mColumns[9] = OColumn(OUString(),"KEY_SEQ",
+ ColumnValue::NO_NULLS,
+ 1,1,0,
+ DataType::INTEGER);
+}
+
+void ODatabaseMetaDataResultSetMetaData::setTypeInfoMap()
+{
+ m_mColumns[3] = OColumn(OUString(),"PRECISION",
+ ColumnValue::NO_NULLS,
+ 1,1,0,
+ DataType::INTEGER);
+ m_mColumns[7] = OColumn(OUString(),"NULLABLE",
+ ColumnValue::NO_NULLS,
+ 1,1,0,
+ DataType::INTEGER);
+ m_mColumns[12] = OColumn(OUString(),"AUTO_INCREMENT",
+ ColumnValue::NO_NULLS,
+ 1,1,0,
+ DataType::BIT);
+ m_mColumns[16] = OColumn(OUString(),"SQL_DATA_TYPE",
+ ColumnValue::NO_NULLS,
+ 1,1,0,
+ DataType::INTEGER);
+ m_mColumns[17] = OColumn(OUString(),"SQL_DATETIME_SUB",
+ ColumnValue::NO_NULLS,
+ 1,1,0,
+ DataType::INTEGER);
+ m_mColumns[18] = OColumn(OUString(),"NUM_PREC_RADIX",
+ ColumnValue::NO_NULLS,
+ 1,1,0,
+ DataType::INTEGER);
+}
+
+void ODatabaseMetaDataResultSetMetaData::setProceduresMap()
+{
+ m_mColumns[7] = OColumn(OUString(),"REMARKS",
+ ColumnValue::NULLABLE,
+ 0,0,0,
+ DataType::VARCHAR);
+}
+
+sal_Bool SAL_CALL ODatabaseMetaDataResultSetMetaData::isSearchable( sal_Int32 column )
+{
+ if(!m_mColumns.empty() && (m_mColumnsIter = m_mColumns.find(column)) != m_mColumns.end())
+ return (*m_mColumnsIter).second.isSearchable();
+ return true;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaDataResultSetMetaData::isAutoIncrement( sal_Int32 column )
+{
+ if(!m_mColumns.empty() && (m_mColumnsIter = m_mColumns.find(column)) != m_mColumns.end())
+ return (*m_mColumnsIter).second.isAutoIncrement();
+ return false;
+}
+
+OUString SAL_CALL ODatabaseMetaDataResultSetMetaData::getColumnServiceName( sal_Int32 /*column*/ )
+{
+ return OUString();
+}
+
+OUString SAL_CALL ODatabaseMetaDataResultSetMetaData::getTableName( sal_Int32 column )
+{
+ if(!m_mColumns.empty() && (m_mColumnsIter = m_mColumns.find(column)) != m_mColumns.end())
+ return (*m_mColumnsIter).second.getTableName();
+ return OUString();
+}
+
+OUString SAL_CALL ODatabaseMetaDataResultSetMetaData::getCatalogName( sal_Int32 /*column*/ )
+{
+ return OUString();
+}
+
+OUString SAL_CALL ODatabaseMetaDataResultSetMetaData::getColumnTypeName( sal_Int32 /*column*/ )
+{
+ return OUString();
+}
+
+
+sal_Bool SAL_CALL ODatabaseMetaDataResultSetMetaData::isCaseSensitive( sal_Int32 column )
+{
+ if(!m_mColumns.empty() && (m_mColumnsIter = m_mColumns.find(column)) != m_mColumns.end())
+ return (*m_mColumnsIter).second.isCaseSensitive();
+ return true;
+}
+
+
+OUString SAL_CALL ODatabaseMetaDataResultSetMetaData::getSchemaName( sal_Int32 /*column*/ )
+{
+ return OUString();
+}
+
+
+ObjectTypeEnum OAdoGroup::MapObjectType(sal_Int32 ObjType)
+{
+ ObjectTypeEnum eNumType= adPermObjTable;
+ switch(ObjType)
+ {
+ case PrivilegeObject::TABLE:
+ break;
+ case PrivilegeObject::VIEW:
+ eNumType = adPermObjView;
+ break;
+ case PrivilegeObject::COLUMN:
+ eNumType = adPermObjColumn;
+ break;
+ }
+ return eNumType;
+}
+
+sal_Int32 OAdoGroup::MapRight(RightsEnum _eNum)
+{
+ sal_Int32 nRight = 0;
+ if(_eNum & adRightRead)
+ nRight |= Privilege::SELECT;
+ if(_eNum & adRightInsert)
+ nRight |= Privilege::INSERT;
+ if(_eNum & adRightUpdate)
+ nRight |= Privilege::UPDATE;
+ if(_eNum & adRightDelete)
+ nRight |= Privilege::DELETE;
+ if(_eNum & adRightReadDesign)
+ nRight |= Privilege::READ;
+ if(_eNum & adRightCreate)
+ nRight |= Privilege::CREATE;
+ if(_eNum & adRightWriteDesign)
+ nRight |= Privilege::ALTER;
+ if(_eNum & adRightReference)
+ nRight |= Privilege::REFERENCE;
+ if(_eNum & adRightDrop)
+ nRight |= Privilege::DROP;
+
+ return nRight;
+}
+
+RightsEnum OAdoGroup::Map2Right(sal_Int32 _eNum)
+{
+ sal_Int32 nRight = adRightNone;
+ if(_eNum & Privilege::SELECT)
+ nRight |= adRightRead;
+
+ if(_eNum & Privilege::INSERT)
+ nRight |= adRightInsert;
+
+ if(_eNum & Privilege::UPDATE)
+ nRight |= adRightUpdate;
+
+ if(_eNum & Privilege::DELETE)
+ nRight |= adRightDelete;
+
+ if(_eNum & Privilege::READ)
+ nRight |= adRightReadDesign;
+
+ if(_eNum & Privilege::CREATE)
+ nRight |= adRightCreate;
+
+ if(_eNum & Privilege::ALTER)
+ nRight |= adRightWriteDesign;
+
+ if(_eNum & Privilege::REFERENCE)
+ nRight |= adRightReference;
+
+ if(_eNum & Privilege::DROP)
+ nRight |= adRightDrop;
+
+ return static_cast<RightsEnum>(nRight);
+}
+
+void WpADOIndex::Create()
+{
+ pInterface.CoCreateInstance(ADOS::CLSID_ADOINDEX_25, nullptr, CLSCTX_INPROC_SERVER);
+}
+
+void OAdoIndex::fillPropertyValues()
+{
+ if(m_aIndex.IsValid())
+ {
+ m_Name = m_aIndex.get_Name();
+ m_IsUnique = m_aIndex.get_Unique();
+ m_IsPrimaryKeyIndex = m_aIndex.get_PrimaryKey();
+ m_IsClustered = m_aIndex.get_Clustered();
+ }
+}
+
+void WpADOKey::Create()
+{
+ pInterface.CoCreateInstance(ADOS::CLSID_ADOKEY_25, nullptr, CLSCTX_INPROC_SERVER);
+}
+
+void OAdoKey::fillPropertyValues()
+{
+ if(m_aKey.IsValid())
+ {
+ m_aProps->m_Type = MapKeyRule(m_aKey.get_Type());
+ m_Name = m_aKey.get_Name();
+ m_aProps->m_ReferencedTable = m_aKey.get_RelatedTable();
+ m_aProps->m_UpdateRule = MapRule(m_aKey.get_UpdateRule());
+ m_aProps->m_DeleteRule = MapRule(m_aKey.get_DeleteRule());
+ }
+}
+
+sal_Int32 OAdoKey::MapRule(const RuleEnum& _eNum)
+{
+ sal_Int32 eNum = KeyRule::NO_ACTION;
+ switch(_eNum)
+ {
+ case adRICascade:
+ eNum = KeyRule::CASCADE;
+ break;
+ case adRISetNull:
+ eNum = KeyRule::SET_NULL;
+ break;
+ case adRINone:
+ eNum = KeyRule::NO_ACTION;
+ break;
+ case adRISetDefault:
+ eNum = KeyRule::SET_DEFAULT;
+ break;
+ }
+ return eNum;
+}
+
+RuleEnum OAdoKey::Map2Rule(sal_Int32 _eNum)
+{
+ RuleEnum eNum = adRINone;
+ switch(_eNum)
+ {
+ case KeyRule::CASCADE:
+ eNum = adRICascade;
+ break;
+ case KeyRule::SET_NULL:
+ eNum = adRISetNull;
+ break;
+ case KeyRule::NO_ACTION:
+ eNum = adRINone;
+ break;
+ case KeyRule::SET_DEFAULT:
+ eNum = adRISetDefault;
+ break;
+ }
+ return eNum;
+}
+
+sal_Int32 OAdoKey::MapKeyRule(const KeyTypeEnum& _eNum)
+{
+ sal_Int32 nKeyType = KeyType::PRIMARY;
+ switch(_eNum)
+ {
+ case adKeyPrimary:
+ nKeyType = KeyType::PRIMARY;
+ break;
+ case adKeyForeign:
+ nKeyType = KeyType::FOREIGN;
+ break;
+ case adKeyUnique:
+ nKeyType = KeyType::UNIQUE;
+ break;
+ }
+ return nKeyType;
+}
+
+KeyTypeEnum OAdoKey::Map2KeyRule(sal_Int32 _eNum)
+{
+ KeyTypeEnum eNum( adKeyPrimary );
+ switch(_eNum)
+ {
+ case KeyType::PRIMARY:
+ eNum = adKeyPrimary;
+ break;
+ case KeyType::FOREIGN:
+ eNum = adKeyForeign;
+ break;
+ case KeyType::UNIQUE:
+ eNum = adKeyUnique;
+ break;
+ default:
+ OSL_FAIL( "OAdoKey::Map2KeyRule: invalid key type!" );
+ }
+ return eNum;
+}
+
+void WpADOTable::Create()
+{
+ pInterface.CoCreateInstance(ADOS::CLSID_ADOTABLE_25, nullptr, CLSCTX_INPROC_SERVER);
+}
+
+OUString WpADOCatalog::GetObjectOwner(std::u16string_view _rName, ObjectTypeEnum _eNum)
+{
+ OLEVariant _rVar;
+ _rVar.setNoArg();
+ sal::systools::BStr aBSTR;
+ sal::systools::BStr sStr1(_rName);
+ pInterface->GetObjectOwner(sStr1, _eNum, _rVar, &aBSTR);
+ return OUString(aBSTR);
+}
+
+void OAdoTable::fillPropertyValues()
+{
+ if(m_aTable.IsValid())
+ {
+ m_Name = m_aTable.get_Name();
+ m_Type = m_aTable.get_Type();
+ {
+ WpADOCatalog aCat(m_aTable.get_ParentCatalog());
+ if(aCat.IsValid())
+ m_CatalogName = aCat.GetObjectOwner(m_aTable.get_Name(),adPermObjTable);
+ }
+ {
+ WpADOProperties aProps = m_aTable.get_Properties();
+ if(aProps.IsValid())
+ m_Description
+ = OTools::getValue(aProps, std::u16string_view(u"Description")).getString();
+ }
+ }
+}
+
+void WpADOUser::Create()
+{
+ pInterface.CoCreateInstance(ADOS::CLSID_ADOUSER_25, nullptr, CLSCTX_INPROC_SERVER);
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/ado/ADatabaseMetaDataResultSet.cxx b/connectivity/source/drivers/ado/ADatabaseMetaDataResultSet.cxx
new file mode 100644
index 0000000000..bb5bda634c
--- /dev/null
+++ b/connectivity/source/drivers/ado/ADatabaseMetaDataResultSet.cxx
@@ -0,0 +1,1242 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <comphelper/sequence.hxx>
+#include <ado/ADatabaseMetaDataResultSet.hxx>
+#include <ado/ADatabaseMetaDataResultSetMetaData.hxx>
+#include <com/sun/star/sdbc/ColumnSearch.hpp>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <com/sun/star/sdbc/ColumnValue.hpp>
+#include <com/sun/star/sdbc/KeyRule.hpp>
+#include <com/sun/star/sdbc/ProcedureResult.hpp>
+#include <com/sun/star/sdbc/IndexType.hpp>
+#include <comphelper/property.hxx>
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <com/sun/star/sdbc/ResultSetConcurrency.hpp>
+#include <com/sun/star/sdbc/ResultSetType.hpp>
+#include <com/sun/star/sdbc/FetchDirection.hpp>
+#include <cppuhelper/typeprovider.hxx>
+#include <comphelper/seqstream.hxx>
+#include <connectivity/dbexception.hxx>
+#include <rtl/ref.hxx>
+
+#include <oledb.h>
+
+using namespace dbtools;
+using namespace connectivity::ado;
+using namespace cppu;
+using namespace ::comphelper;
+
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::sdbc;
+
+
+ODatabaseMetaDataResultSet::ODatabaseMetaDataResultSet(ADORecordset* _pRecordSet)
+ :ODatabaseMetaDataResultSet_BASE(m_aMutex)
+ ,OPropertySetHelper(ODatabaseMetaDataResultSet_BASE::rBHelper)
+ ,m_pRecordSet(_pRecordSet)
+ ,m_nRowPos(0)
+ ,m_bWasNull(false)
+ ,m_bEOF(false)
+ ,m_bOnFirstAfterOpen(false)
+{
+ osl_atomic_increment( &m_refCount );
+ m_aColMapping.push_back(-1);
+ if(_pRecordSet)
+ {
+ m_pRecordSet->AddRef();
+ VARIANT_BOOL bIsAtBOF;
+ m_pRecordSet->get_BOF(&bIsAtBOF);
+ m_bOnFirstAfterOpen = bIsAtBOF != VARIANT_TRUE;
+ }
+ else
+ m_bOnFirstAfterOpen = false;
+ osl_atomic_decrement( &m_refCount );
+ // allocBuffer();
+}
+
+
+ODatabaseMetaDataResultSet::~ODatabaseMetaDataResultSet()
+{
+ if(m_pRecordSet)
+ m_pRecordSet->Release();
+}
+
+void ODatabaseMetaDataResultSet::disposing()
+{
+ OPropertySetHelper::disposing();
+
+ ::osl::MutexGuard aGuard(m_aMutex);
+ if(m_pRecordSet)
+ m_pRecordSet->Close();
+ m_aStatement.clear();
+ m_xMetaData.clear();
+}
+
+Any SAL_CALL ODatabaseMetaDataResultSet::queryInterface( const Type & rType )
+{
+ Any aRet = OPropertySetHelper::queryInterface(rType);
+ return aRet.hasValue() ? aRet : ODatabaseMetaDataResultSet_BASE::queryInterface(rType);
+}
+
+css::uno::Sequence< css::uno::Type > SAL_CALL ODatabaseMetaDataResultSet::getTypes( )
+{
+ ::cppu::OTypeCollection aTypes( cppu::UnoType<css::beans::XMultiPropertySet>::get(),
+ cppu::UnoType<css::beans::XFastPropertySet>::get(),
+ cppu::UnoType<css::beans::XPropertySet>::get());
+
+ return ::comphelper::concatSequences(aTypes.getTypes(),ODatabaseMetaDataResultSet_BASE::getTypes());
+}
+
+void ODatabaseMetaDataResultSet::checkRecordSet()
+{
+ if(!m_pRecordSet)
+ throwFunctionSequenceException(*this);
+}
+
+
+sal_Int32 SAL_CALL ODatabaseMetaDataResultSet::findColumn( const OUString& columnName )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed );
+
+
+ Reference< XResultSetMetaData > xMeta = getMetaData();
+ sal_Int32 nLen = xMeta->getColumnCount();
+ sal_Int32 i = 1;
+ for(;i<=nLen;++i)
+ {
+ if(xMeta->isCaseSensitive(i) ? columnName == xMeta->getColumnName(i) :
+ columnName.equalsIgnoreAsciiCase(xMeta->getColumnName(i)))
+ return i;
+ }
+
+ ::dbtools::throwInvalidColumnException( columnName, *this );
+ assert(false);
+ return 0; // Never reached
+}
+#define BLOCK_SIZE 256
+
+Reference< css::io::XInputStream > SAL_CALL ODatabaseMetaDataResultSet::getBinaryStream( sal_Int32 columnIndex )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed);
+
+ checkRecordSet();
+
+
+ columnIndex = mapColumn(columnIndex);
+ WpADOField aField = ADOS::getField(m_pRecordSet,columnIndex);
+ if((aField.GetAttributes() & adFldLong) == adFldLong)
+ {
+ //Copy the data only up to the Actual Size of Field.
+ sal_Int32 nSize = aField.GetActualSize();
+ Sequence<sal_Int8> aData(nSize);
+ sal_Int32 index = 0;
+ while(index < nSize)
+ {
+ m_aValue = aField.GetChunk(BLOCK_SIZE);
+ if(m_aValue.isNull())
+ break;
+ UCHAR chData;
+ for(LONG index2 = 0;index2 < BLOCK_SIZE;++index2)
+ {
+ HRESULT hr = ::SafeArrayGetElement(m_aValue.parray,&index2,&chData);
+ if(SUCCEEDED(hr))
+ {
+ //Take BYTE by BYTE and advance Memory Location
+ aData.getArray()[index++] = chData;
+ }
+ else
+ break;
+ }
+ }
+ return index ? Reference< css::io::XInputStream >(new SequenceInputStream(aData)) : Reference< css::io::XInputStream >();
+ }
+ // else we ask for a bytesequence
+ aField.get_Value(m_aValue);
+ if(m_aValue.isNull())
+ return nullptr;
+ return new SequenceInputStream(m_aValue.getByteSequence());
+}
+
+Reference< css::io::XInputStream > SAL_CALL ODatabaseMetaDataResultSet::getCharacterStream( sal_Int32 /*columnIndex*/ )
+{
+ ::dbtools::throwFeatureNotImplementedSQLException( "XRow::getCharacterStream", *this );
+ return nullptr;
+}
+
+
+sal_Bool SAL_CALL ODatabaseMetaDataResultSet::getBoolean( sal_Int32 columnIndex )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ if ( !m_aValueRange.empty() && columnIndex == 11 && (m_aValueRangeIter = m_aValueRange.find(columnIndex)) != m_aValueRange.end() )
+ {
+ getValue(2);
+ if ( m_aValue.getInt16() != adCurrency )
+ return false;
+ }
+ return getValue(columnIndex).getBool();
+}
+
+
+sal_Int8 SAL_CALL ODatabaseMetaDataResultSet::getByte( sal_Int32 columnIndex )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ getValue(columnIndex);
+
+ columnIndex = mapColumn(columnIndex);
+
+ if(m_aValue.isNull())
+ return 0;
+ if ( !m_aValueRange.empty() && (m_aValueRangeIter = m_aValueRange.find(columnIndex)) != m_aValueRange.end())
+ return static_cast<sal_Int8>((*m_aValueRangeIter).second[m_aValue.getInt32()]);
+ else if(m_aStrValueRange.size() && (m_aStrValueRangeIter = m_aStrValueRange.find(columnIndex)) != m_aStrValueRange.end())
+ return static_cast<sal_Int8>((*m_aStrValueRangeIter).second[m_aValue.getString()]);
+
+ return m_aValue.getInt8();
+}
+
+
+Sequence< sal_Int8 > SAL_CALL ODatabaseMetaDataResultSet::getBytes( sal_Int32 columnIndex )
+{
+ return getValue(columnIndex).getByteSequence();
+}
+
+
+css::util::Date SAL_CALL ODatabaseMetaDataResultSet::getDate( sal_Int32 columnIndex )
+{
+ return getValue(columnIndex).getDate();
+}
+
+
+double SAL_CALL ODatabaseMetaDataResultSet::getDouble( sal_Int32 columnIndex )
+{
+ return getValue(columnIndex).getDouble();
+}
+
+
+float SAL_CALL ODatabaseMetaDataResultSet::getFloat( sal_Int32 columnIndex )
+{
+ return getValue(columnIndex).getFloat();
+}
+
+
+sal_Int32 SAL_CALL ODatabaseMetaDataResultSet::getInt( sal_Int32 columnIndex )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+
+ getValue(columnIndex);
+
+ columnIndex = mapColumn(columnIndex);
+ if(m_aValue.isNull())
+ return 0;
+
+ if(m_aValueRange.size() && (m_aValueRangeIter = m_aValueRange.find(columnIndex)) != m_aValueRange.end())
+ return (*m_aValueRangeIter).second[m_aValue.getInt32()];
+ else if(m_aStrValueRange.size() && (m_aStrValueRangeIter = m_aStrValueRange.find(columnIndex)) != m_aStrValueRange.end())
+ return (*m_aStrValueRangeIter).second[m_aValue.getString()];
+
+ return m_aValue.getInt32();
+}
+
+
+sal_Int32 SAL_CALL ODatabaseMetaDataResultSet::getRow( )
+{
+ ::dbtools::throwFeatureNotImplementedSQLException( "XResultSet::getRow", *this );
+ return 0;
+}
+
+
+sal_Int64 SAL_CALL ODatabaseMetaDataResultSet::getLong( sal_Int32 /*columnIndex*/ )
+{
+ ::dbtools::throwFeatureNotImplementedSQLException( "XRow::getLong", *this );
+ return sal_Int64(0);
+}
+
+
+Reference< XResultSetMetaData > SAL_CALL ODatabaseMetaDataResultSet::getMetaData( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed);
+
+ checkRecordSet();
+
+
+ if(!m_xMetaData.is())
+ m_xMetaData = new ODatabaseMetaDataResultSetMetaData(m_pRecordSet,this);
+
+ return m_xMetaData;
+}
+
+Reference< XArray > SAL_CALL ODatabaseMetaDataResultSet::getArray( sal_Int32 /*columnIndex*/ )
+{
+ ::dbtools::throwFeatureNotImplementedSQLException( "XRow::getRow", *this );
+ return nullptr;
+}
+
+
+Reference< XClob > SAL_CALL ODatabaseMetaDataResultSet::getClob( sal_Int32 /*columnIndex*/ )
+{
+ ::dbtools::throwFeatureNotImplementedSQLException( "XRow::getRow", *this );
+ return nullptr;
+}
+
+Reference< XBlob > SAL_CALL ODatabaseMetaDataResultSet::getBlob( sal_Int32 /*columnIndex*/ )
+{
+ ::dbtools::throwFeatureNotImplementedSQLException( "XRow::getRow", *this );
+ return nullptr;
+}
+
+
+Reference< XRef > SAL_CALL ODatabaseMetaDataResultSet::getRef( sal_Int32 /*columnIndex*/ )
+{
+ ::dbtools::throwFeatureNotImplementedSQLException( "XRow::getRow", *this );
+ return nullptr;
+}
+
+
+Any SAL_CALL ODatabaseMetaDataResultSet::getObject( sal_Int32 columnIndex, const Reference< css::container::XNameAccess >& /*typeMap*/ )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed);
+
+ checkRecordSet();
+
+
+ columnIndex = mapColumn(columnIndex);
+ return Any();
+}
+
+
+sal_Int16 SAL_CALL ODatabaseMetaDataResultSet::getShort( sal_Int32 columnIndex )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ getValue(columnIndex);
+
+ columnIndex = mapColumn(columnIndex);
+ if(m_aValue.isNull())
+ return 0;
+
+ if(m_aValueRange.size() && (m_aValueRangeIter = m_aValueRange.find(columnIndex)) != m_aValueRange.end())
+ return static_cast<sal_Int16>((*m_aValueRangeIter).second[m_aValue.getInt32()]);
+ else if(m_aStrValueRange.size() && (m_aStrValueRangeIter = m_aStrValueRange.find(columnIndex)) != m_aStrValueRange.end())
+ return static_cast<sal_Int16>((*m_aStrValueRangeIter).second[m_aValue.getString()]);
+
+ return m_aValue.getInt16();
+}
+
+
+OUString SAL_CALL ODatabaseMetaDataResultSet::getString( sal_Int32 columnIndex )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ getValue(columnIndex);
+
+
+ columnIndex = mapColumn(columnIndex);
+ if(m_aValue.isNull())
+ return OUString();
+ if(m_aIntValueRange.size() && (m_aIntValueRangeIter = m_aIntValueRange.find(columnIndex)) != m_aIntValueRange.end())
+ return (*m_aIntValueRangeIter).second[m_aValue.getInt32()];
+
+ return m_aValue.getString();
+}
+
+
+css::util::Time SAL_CALL ODatabaseMetaDataResultSet::getTime( sal_Int32 columnIndex )
+{
+ return getValue(columnIndex).getTime();
+}
+
+
+css::util::DateTime SAL_CALL ODatabaseMetaDataResultSet::getTimestamp( sal_Int32 columnIndex )
+{
+ return getValue(columnIndex).getDateTime();
+}
+
+
+sal_Bool SAL_CALL ODatabaseMetaDataResultSet::isAfterLast( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed);
+
+ checkRecordSet();
+
+
+ VARIANT_BOOL bIsAtEOF;
+ m_pRecordSet->get_EOF(&bIsAtEOF);
+ return bIsAtEOF == VARIANT_TRUE;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaDataResultSet::isFirst( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed);
+
+ checkRecordSet();
+
+
+ return m_nRowPos == 1;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaDataResultSet::isLast( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed);
+
+ checkRecordSet();
+
+
+ return true;
+}
+
+void SAL_CALL ODatabaseMetaDataResultSet::beforeFirst( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed);
+
+ checkRecordSet();
+
+
+ if(first())
+ previous();
+}
+
+void SAL_CALL ODatabaseMetaDataResultSet::afterLast( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed);
+
+ checkRecordSet();
+
+
+ if(last())
+ next();
+ m_bEOF = true;
+}
+
+
+void SAL_CALL ODatabaseMetaDataResultSet::close( )
+{
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed);
+
+ }
+ dispose();
+}
+
+
+sal_Bool SAL_CALL ODatabaseMetaDataResultSet::first( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed);
+
+
+ if(!m_pRecordSet)
+ return false;
+
+ bool bRet = SUCCEEDED(m_pRecordSet->MoveFirst());
+ if ( bRet )
+ m_nRowPos = 1;
+ return bRet;
+}
+
+
+sal_Bool SAL_CALL ODatabaseMetaDataResultSet::last( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed );
+
+
+ return m_pRecordSet && SUCCEEDED(m_pRecordSet->MoveLast());
+}
+
+sal_Bool SAL_CALL ODatabaseMetaDataResultSet::absolute( sal_Int32 row )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed);
+
+
+ if(first())
+ {
+ OLEVariant aEmpty;
+ aEmpty.setNoArg();
+ bool bRet = SUCCEEDED(m_pRecordSet->Move(row,aEmpty));
+ if(bRet)
+ m_nRowPos = row;
+ return bRet;
+ }
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaDataResultSet::relative( sal_Int32 row )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed);
+
+
+ if(!m_pRecordSet)
+ return false;
+
+ OLEVariant aEmpty;
+ aEmpty.setNoArg();
+ bool bRet = SUCCEEDED(m_pRecordSet->Move(row,aEmpty));
+ if(bRet)
+ m_nRowPos += row;
+ return bRet;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaDataResultSet::previous( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed);
+
+
+ if(!m_pRecordSet)
+ return false;
+
+ bool bRet = SUCCEEDED(m_pRecordSet->MovePrevious());
+ if(bRet)
+ --m_nRowPos;
+ return bRet;
+}
+
+Reference< XInterface > SAL_CALL ODatabaseMetaDataResultSet::getStatement( )
+{
+ return m_aStatement.get();
+}
+
+
+sal_Bool SAL_CALL ODatabaseMetaDataResultSet::rowDeleted( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed);
+
+ checkRecordSet();
+
+
+ sal_Int32 eRec;
+ m_pRecordSet->get_Status(&eRec);
+ return (RecordStatusEnum(eRec) & adRecDeleted) == adRecDeleted;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaDataResultSet::rowInserted( )
+{ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed);
+
+ checkRecordSet();
+
+
+ sal_Int32 eRec;
+ m_pRecordSet->get_Status(&eRec);
+ return (RecordStatusEnum(eRec) & adRecNew) == adRecNew;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaDataResultSet::rowUpdated( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed);
+
+ checkRecordSet();
+
+
+ sal_Int32 eRec;
+ m_pRecordSet->get_Status(&eRec);
+ return (RecordStatusEnum(eRec) & adRecModified) == adRecModified;
+}
+
+
+sal_Bool SAL_CALL ODatabaseMetaDataResultSet::isBeforeFirst( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed);
+
+
+ if(!m_pRecordSet)
+ return true;
+
+ VARIANT_BOOL bIsAtBOF;
+ m_pRecordSet->get_BOF(&bIsAtBOF);
+ return bIsAtBOF == VARIANT_TRUE;
+}
+
+
+sal_Bool SAL_CALL ODatabaseMetaDataResultSet::next( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed);
+
+
+ if(!m_pRecordSet)
+ return false;
+
+ if(m_bOnFirstAfterOpen)
+ {
+ m_bOnFirstAfterOpen = false;
+ return true;
+ }
+ else
+ return SUCCEEDED(m_pRecordSet->MoveNext());
+}
+
+
+sal_Bool SAL_CALL ODatabaseMetaDataResultSet::wasNull( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed);
+
+ checkRecordSet();
+
+
+ return m_aValue.isNull();
+}
+
+void SAL_CALL ODatabaseMetaDataResultSet::refreshRow( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed);
+
+ checkRecordSet();
+
+
+ m_pRecordSet->Resync(adAffectCurrent);
+}
+
+
+void SAL_CALL ODatabaseMetaDataResultSet::cancel( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed);
+
+ checkRecordSet();
+
+
+ m_pRecordSet->Cancel();
+}
+
+void SAL_CALL ODatabaseMetaDataResultSet::clearWarnings( )
+{
+}
+
+Any SAL_CALL ODatabaseMetaDataResultSet::getWarnings( )
+{
+ return Any();
+}
+
+sal_Int32 ODatabaseMetaDataResultSet::getResultSetConcurrency()
+{
+ return ResultSetConcurrency::READ_ONLY;
+}
+
+sal_Int32 ODatabaseMetaDataResultSet::getResultSetType()
+{
+ return ResultSetType::FORWARD_ONLY;
+}
+
+sal_Int32 ODatabaseMetaDataResultSet::getFetchDirection()
+{
+ return FetchDirection::FORWARD;
+}
+
+sal_Int32 ODatabaseMetaDataResultSet::getFetchSize() const
+{
+ sal_Int32 nValue=-1;
+ if(m_pRecordSet)
+ m_pRecordSet->get_CacheSize(&nValue);
+ return nValue;
+}
+
+OUString ODatabaseMetaDataResultSet::getCursorName()
+{
+ return OUString();
+}
+
+
+void ODatabaseMetaDataResultSet::setFetchDirection(sal_Int32 /*_par0*/)
+{
+ ::dbtools::throwFeatureNotImplementedSQLException( "ResultSet::FetchDirection", *this );
+}
+
+void ODatabaseMetaDataResultSet::setFetchSize(sal_Int32 _par0)
+{
+ if(m_pRecordSet)
+ m_pRecordSet->put_CacheSize(_par0);
+}
+
+::cppu::IPropertyArrayHelper* ODatabaseMetaDataResultSet::createArrayHelper( ) const
+{
+
+ return new ::cppu::OPropertyArrayHelper
+ {
+ {
+ {
+ ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_CURSORNAME),
+ PROPERTY_ID_CURSORNAME,
+ cppu::UnoType<OUString>::get(),
+ 0
+ },
+ {
+ ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHDIRECTION),
+ PROPERTY_ID_FETCHDIRECTION,
+ cppu::UnoType<sal_Int32>::get(),
+ 0
+ },
+ {
+ ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHSIZE),
+ PROPERTY_ID_FETCHSIZE,
+ cppu::UnoType<sal_Int32>::get(),
+ 0
+ },
+ {
+ ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETCONCURRENCY),
+ PROPERTY_ID_RESULTSETCONCURRENCY,
+ cppu::UnoType<sal_Int32>::get(),
+ 0
+ },
+ {
+ ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETTYPE),
+ PROPERTY_ID_RESULTSETTYPE,
+ cppu::UnoType<sal_Int32>::get(),
+ 0
+ }
+ }
+ };
+}
+
+::cppu::IPropertyArrayHelper & ODatabaseMetaDataResultSet::getInfoHelper()
+{
+ return *getArrayHelper();
+}
+
+sal_Bool ODatabaseMetaDataResultSet::convertFastPropertyValue(
+ Any & rConvertedValue,
+ Any & rOldValue,
+ sal_Int32 nHandle,
+ const Any& rValue )
+{
+ switch(nHandle)
+ {
+ case PROPERTY_ID_CURSORNAME:
+ case PROPERTY_ID_RESULTSETCONCURRENCY:
+ case PROPERTY_ID_RESULTSETTYPE:
+ throw css::lang::IllegalArgumentException();
+ case PROPERTY_ID_FETCHDIRECTION:
+ return ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, getFetchDirection());
+ case PROPERTY_ID_FETCHSIZE:
+ return ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, getFetchSize());
+ default:
+ ;
+ }
+ return false;
+}
+
+void ODatabaseMetaDataResultSet::setFastPropertyValue_NoBroadcast(
+ sal_Int32 nHandle,
+ const Any& /*rValue*/
+ )
+{
+ switch(nHandle)
+ {
+ case PROPERTY_ID_CURSORNAME:
+ case PROPERTY_ID_RESULTSETCONCURRENCY:
+ case PROPERTY_ID_RESULTSETTYPE:
+ case PROPERTY_ID_FETCHDIRECTION:
+ case PROPERTY_ID_FETCHSIZE:
+ throw Exception("cannot set prop " + OUString::number(nHandle), nullptr);
+ default:
+ OSL_FAIL("setFastPropertyValue_NoBroadcast: Illegal handle value!");
+ }
+}
+
+void ODatabaseMetaDataResultSet::getFastPropertyValue(
+ Any& rValue,
+ sal_Int32 nHandle
+ ) const
+{
+ switch(nHandle)
+ {
+ case PROPERTY_ID_CURSORNAME:
+ rValue <<= getCursorName();
+ break;
+ case PROPERTY_ID_RESULTSETCONCURRENCY:
+ rValue <<= getResultSetConcurrency();
+ break;
+ case PROPERTY_ID_RESULTSETTYPE:
+ rValue <<= getResultSetType();
+ break;
+ case PROPERTY_ID_FETCHDIRECTION:
+ rValue <<= getFetchDirection();
+ break;
+ case PROPERTY_ID_FETCHSIZE:
+ rValue <<= getFetchSize();
+ break;
+ }
+}
+
+void ODatabaseMetaDataResultSet::setProceduresMap()
+{
+ for(sal_Int32 i=1;i<4;i++)
+ m_aColMapping.push_back(i);
+ m_aColMapping.push_back(5);
+ m_aColMapping.push_back(7);
+ m_aColMapping.push_back(8);
+ m_aColMapping.push_back(6);
+ m_aColMapping.push_back(4);
+
+ ::std::map<sal_Int32,sal_Int32> aMap
+ {
+ {DB_PT_UNKNOWN, ProcedureResult::UNKNOWN},
+ {DB_PT_PROCEDURE, ProcedureResult::NONE},
+ {DB_PT_FUNCTION, ProcedureResult::RETURN}
+ };
+ m_aValueRange[4] = aMap;
+
+ rtl::Reference<ODatabaseMetaDataResultSetMetaData> pMetaData = new ODatabaseMetaDataResultSetMetaData(m_pRecordSet,this);
+ pMetaData->setProceduresMap();
+ m_xMetaData = pMetaData;
+}
+
+void ODatabaseMetaDataResultSet::setCatalogsMap()
+{
+ m_aColMapping.push_back(1);
+
+ m_xMetaData = new ODatabaseMetaDataResultSetMetaData(m_pRecordSet,this);
+}
+
+void ODatabaseMetaDataResultSet::setSchemasMap()
+{
+ m_aColMapping.push_back(2);
+
+ m_xMetaData = new ODatabaseMetaDataResultSetMetaData(m_pRecordSet,this);
+}
+
+void ODatabaseMetaDataResultSet::setColumnPrivilegesMap()
+{
+
+ m_aColMapping.push_back(3);
+ m_aColMapping.push_back(4);
+ m_aColMapping.push_back(5);
+ m_aColMapping.push_back(6);
+ m_aColMapping.push_back(2);
+ m_aColMapping.push_back(9);
+ m_aColMapping.push_back(10);
+
+ rtl::Reference<ODatabaseMetaDataResultSetMetaData> pMetaData = new ODatabaseMetaDataResultSetMetaData(m_pRecordSet,this);
+ pMetaData->setColumnPrivilegesMap();
+ m_xMetaData = pMetaData;
+}
+
+void ODatabaseMetaDataResultSet::setColumnsMap()
+{
+
+ for(sal_Int32 i=1;i<5;++i)
+ m_aColMapping.push_back(i);
+
+ m_aColMapping.push_back(12);
+ m_aColMapping.push_back(12); // is used as TYPE_NAME
+
+ m_aColMapping.push_back(14);
+ m_aColMapping.push_back(6);
+ m_aColMapping.push_back(17);
+ m_aColMapping.push_back(18);
+
+ m_aColMapping.push_back(11);
+ m_aColMapping.push_back(29);
+ m_aColMapping.push_back(9);
+ m_aColMapping.push_back(18);
+ m_aColMapping.push_back(18);
+
+ m_aColMapping.push_back(15);
+ m_aColMapping.push_back(7);
+ m_aColMapping.push_back(11);
+
+ ::std::map<sal_Int32,sal_Int32> aMap {
+ {adEmpty, ADOS::MapADOType2Jdbc(adEmpty)},
+ {adTinyInt, ADOS::MapADOType2Jdbc(adTinyInt)},
+ {adSmallInt, ADOS::MapADOType2Jdbc(adSmallInt)},
+ {adInteger, ADOS::MapADOType2Jdbc(adInteger)},
+ {adBigInt, ADOS::MapADOType2Jdbc(adBigInt)},
+ {adUnsignedTinyInt, ADOS::MapADOType2Jdbc(adUnsignedTinyInt)},
+ {adUnsignedSmallInt, ADOS::MapADOType2Jdbc(adUnsignedSmallInt)},
+ {adUnsignedInt, ADOS::MapADOType2Jdbc(adUnsignedInt)},
+ {adUnsignedBigInt, ADOS::MapADOType2Jdbc(adUnsignedBigInt)},
+ {adSingle, ADOS::MapADOType2Jdbc(adSingle)},
+ {adDouble, ADOS::MapADOType2Jdbc(adDouble)},
+ {adCurrency, ADOS::MapADOType2Jdbc(adCurrency)},
+ {adDecimal, ADOS::MapADOType2Jdbc(adDecimal)},
+ {adNumeric, ADOS::MapADOType2Jdbc(adNumeric)},
+ {adBoolean, ADOS::MapADOType2Jdbc(adBoolean)},
+ {adError, ADOS::MapADOType2Jdbc(adError)},
+ {adUserDefined, ADOS::MapADOType2Jdbc(adUserDefined)},
+ {adVariant, ADOS::MapADOType2Jdbc(adVariant)},
+ {adIDispatch, ADOS::MapADOType2Jdbc(adIDispatch)},
+ {adIUnknown, ADOS::MapADOType2Jdbc(adIUnknown)},
+ {adGUID, ADOS::MapADOType2Jdbc(adGUID)},
+ {adDate, ADOS::MapADOType2Jdbc(adDate)},
+ {adDBDate, ADOS::MapADOType2Jdbc(adDBDate)},
+ {adDBTime, ADOS::MapADOType2Jdbc(adDBTime)},
+ {adDBTimeStamp, ADOS::MapADOType2Jdbc(adDBTimeStamp)},
+ {adBSTR, ADOS::MapADOType2Jdbc(adBSTR)},
+ {adChar, ADOS::MapADOType2Jdbc(adChar)},
+ {adVarChar, ADOS::MapADOType2Jdbc(adVarChar)},
+ {adLongVarChar, ADOS::MapADOType2Jdbc(adLongVarChar)},
+ {adWChar, ADOS::MapADOType2Jdbc(adWChar)},
+ {adVarWChar, ADOS::MapADOType2Jdbc(adVarWChar)},
+ {adLongVarWChar, ADOS::MapADOType2Jdbc(adLongVarWChar)},
+ {adBinary, ADOS::MapADOType2Jdbc(adBinary)},
+ {adVarBinary, ADOS::MapADOType2Jdbc(adVarBinary)},
+ {adLongVarBinary, ADOS::MapADOType2Jdbc(adLongVarBinary)},
+ {adChapter, ADOS::MapADOType2Jdbc(adChapter)},
+ {adFileTime, ADOS::MapADOType2Jdbc(adFileTime)},
+ {adPropVariant, ADOS::MapADOType2Jdbc(adPropVariant)},
+ {adVarNumeric, ADOS::MapADOType2Jdbc(adVarNumeric)}
+ };
+ m_aValueRange[12] = aMap;
+
+ std::map< sal_Int32,OUString> aMap2 {
+ {0, "YES"},
+ {1, "NO"}
+ };
+ m_aIntValueRange[18] = aMap2;
+
+ rtl::Reference<ODatabaseMetaDataResultSetMetaData> pMetaData = new ODatabaseMetaDataResultSetMetaData(m_pRecordSet,this);
+ pMetaData->setColumnsMap();
+ m_xMetaData = pMetaData;
+}
+
+void ODatabaseMetaDataResultSet::setTablesMap()
+{
+
+ for(sal_Int32 i=1;i<5;i++)
+ m_aColMapping.push_back(i);
+ m_aColMapping.push_back(6);
+
+ rtl::Reference<ODatabaseMetaDataResultSetMetaData> pMetaData = new ODatabaseMetaDataResultSetMetaData(m_pRecordSet,this);
+ pMetaData->setTablesMap();
+ m_xMetaData = pMetaData;
+}
+
+void ODatabaseMetaDataResultSet::setProcedureColumnsMap()
+{
+
+ for(sal_Int32 i=1;i<5;i++)
+ m_aColMapping.push_back(i);
+ m_aColMapping.push_back(6);
+ m_aColMapping.push_back(10);
+ m_aColMapping.push_back(16);
+ m_aColMapping.push_back(13);
+ m_aColMapping.push_back(11);
+ m_aColMapping.push_back(12);
+
+ m_aColMapping.push_back(9);
+ m_aColMapping.push_back(14);
+
+ ::std::map<sal_Int32,sal_Int32> aMap
+ {
+ {DBTYPE_EMPTY, DataType::SQLNULL},
+ {DBTYPE_NULL, DataType::SQLNULL},
+ {DBTYPE_I2, DataType::SMALLINT},
+ {DBTYPE_I4, DataType::INTEGER},
+ {DBTYPE_R4, DataType::FLOAT},
+ {DBTYPE_R8, DataType::DOUBLE},
+ {DBTYPE_CY, DataType::BIGINT},
+ {DBTYPE_DATE, DataType::DATE},
+ {DBTYPE_BSTR, DataType::VARCHAR},
+ {DBTYPE_IDISPATCH, DataType::OBJECT},
+ {DBTYPE_ERROR, DataType::OTHER},
+ {DBTYPE_BOOL, DataType::BIT},
+ {DBTYPE_VARIANT, DataType::STRUCT},
+ {DBTYPE_IUNKNOWN, DataType::OTHER},
+ {DBTYPE_DECIMAL, DataType::DECIMAL},
+ {DBTYPE_UI1, DataType::TINYINT},
+ {DBTYPE_ARRAY, DataType::ARRAY},
+ {DBTYPE_BYREF, DataType::REF},
+ {DBTYPE_I1, DataType::CHAR},
+ {DBTYPE_UI2, DataType::SMALLINT},
+ {DBTYPE_UI4, DataType::INTEGER},
+
+ // aMap[The] = ;
+ // aMap[in] = ;
+ {DBTYPE_I8, DataType::BIGINT},
+ {DBTYPE_UI8, DataType::BIGINT},
+ {DBTYPE_GUID, DataType::OTHER},
+ {DBTYPE_VECTOR, DataType::OTHER},
+ {DBTYPE_FILETIME, DataType::OTHER},
+ {DBTYPE_RESERVED, DataType::OTHER},
+
+ // aMap[The] = ;
+ {DBTYPE_BYTES, DataType::VARBINARY},
+ {DBTYPE_STR, DataType::LONGVARCHAR},
+ {DBTYPE_WSTR, DataType::LONGVARCHAR},
+ {DBTYPE_NUMERIC, DataType::NUMERIC},
+ {DBTYPE_UDT, DataType::OTHER},
+ {DBTYPE_DBDATE, DataType::DATE},
+ {DBTYPE_DBTIME, DataType::TIME},
+ {DBTYPE_DBTIMESTAMP, DataType::TIMESTAMP},
+ {DBTYPE_HCHAPTER, DataType::OTHER},
+ {DBTYPE_PROPVARIANT, DataType::OTHER},
+ {DBTYPE_VARNUMERIC, DataType::NUMERIC}
+ };
+
+ m_aValueRange[10] = aMap;
+
+ rtl::Reference<ODatabaseMetaDataResultSetMetaData> pMetaData = new ODatabaseMetaDataResultSetMetaData(m_pRecordSet,this);
+ pMetaData->setProcedureColumnsMap();
+ m_xMetaData = pMetaData;
+}
+
+void ODatabaseMetaDataResultSet::setPrimaryKeysMap()
+{
+
+ sal_Int32 i=1;
+ for(;i<5;i++)
+ m_aColMapping.push_back(i);
+ m_aColMapping.push_back(7);
+ m_aColMapping.push_back(8);
+
+ rtl::Reference<ODatabaseMetaDataResultSetMetaData> pMetaData = new ODatabaseMetaDataResultSetMetaData(m_pRecordSet,this);
+ pMetaData->setProcedureColumnsMap();
+ m_xMetaData = pMetaData;
+}
+
+void ODatabaseMetaDataResultSet::setIndexInfoMap()
+{
+
+ sal_Int32 i=1;
+ for(;i<4;i++)
+ m_aColMapping.push_back(i);
+ m_aColMapping.push_back(8);
+ m_aColMapping.push_back(4);
+ m_aColMapping.push_back(6);
+ m_aColMapping.push_back(10);
+ m_aColMapping.push_back(17);
+ m_aColMapping.push_back(18);
+ m_aColMapping.push_back(21);
+ m_aColMapping.push_back(22);
+ m_aColMapping.push_back(23);
+ m_aColMapping.push_back(24);
+
+ ::std::map<sal_Int32,sal_Int32> aMap
+ {
+ { DBPROPVAL_IT_HASH, IndexType::HASHED },
+ { DBPROPVAL_IT_CONTENT, IndexType::OTHER },
+ { DBPROPVAL_IT_OTHER, IndexType::OTHER },
+ { DBPROPVAL_IT_BTREE, IndexType::OTHER }
+ };
+
+ m_aValueRange[10] = aMap;
+
+ ::std::map<sal_Int32,sal_Int32> aMap2
+ {
+ { 0, 1 },
+ { 1, 0 }
+ };
+ m_aValueRange[8] = aMap2;
+
+ std::map< sal_Int32,OUString> aMap3
+ {
+ { 0, "" },
+ { DB_COLLATION_ASC, "A" },
+ { DB_COLLATION_DESC, "D" }
+ };
+
+ m_aIntValueRange[21] = aMap3;
+
+ rtl::Reference<ODatabaseMetaDataResultSetMetaData> pMetaData = new ODatabaseMetaDataResultSetMetaData(m_pRecordSet,this);
+ pMetaData->setIndexInfoMap();
+ m_xMetaData = pMetaData;
+}
+
+void ODatabaseMetaDataResultSet::setTablePrivilegesMap()
+{
+
+ sal_Int32 i=3;
+ for(;i<6;i++)
+ m_aColMapping.push_back(i);
+ m_aColMapping.push_back(1);
+ m_aColMapping.push_back(2);
+ m_aColMapping.push_back(6);
+ m_aColMapping.push_back(7);
+
+ std::map< sal_Int32,OUString> aMap
+ {
+ { 0, "YES" },
+ { 1, "NO" }
+ };
+ m_aIntValueRange[7] = aMap;
+
+
+ rtl::Reference<ODatabaseMetaDataResultSetMetaData> pMetaData = new ODatabaseMetaDataResultSetMetaData(m_pRecordSet,this);
+ pMetaData->setTablePrivilegesMap();
+ m_xMetaData = pMetaData;
+}
+
+void ODatabaseMetaDataResultSet::setCrossReferenceMap()
+{
+
+ sal_Int32 i=1;
+ for(;i<5;i++)
+ m_aColMapping.push_back(i);
+ for(i=7;i<11;i++)
+ m_aColMapping.push_back(i);
+
+ m_aColMapping.push_back(13);
+ m_aColMapping.push_back(14);
+ m_aColMapping.push_back(15);
+ m_aColMapping.push_back(17);
+ m_aColMapping.push_back(16);
+ m_aColMapping.push_back(18);
+
+ std::map< OUString,sal_Int32> aMap
+ {
+ { "CASCADE", KeyRule::CASCADE },
+ { "RESTRICT", KeyRule::RESTRICT },
+ { "SET NULL", KeyRule::SET_NULL },
+ { "SET DEFAULT", KeyRule::SET_DEFAULT },
+ { "NO ACTION", KeyRule::NO_ACTION }
+ };
+
+ m_aStrValueRange[14] = aMap;
+ m_aStrValueRange[15] = aMap;
+
+ rtl::Reference<ODatabaseMetaDataResultSetMetaData> pMetaData = new ODatabaseMetaDataResultSetMetaData(m_pRecordSet,this);
+ pMetaData->setCrossReferenceMap();
+ m_xMetaData = pMetaData;
+}
+
+void ODatabaseMetaDataResultSet::setTypeInfoMap(bool _bJetEngine)
+{
+ sal_Int32 i=1;
+ for(;i<19;i++)
+ m_aColMapping.push_back(i);
+
+ std::map< OUString,sal_Int32> aMap1 { { OUString(), 10 } };
+
+ m_aStrValueRange[18] = aMap1;
+
+ ::std::map<sal_Int32,sal_Int32> aMap
+ {
+ {adEmpty, ADOS::MapADOType2Jdbc(adEmpty)},
+ {adTinyInt, ADOS::MapADOType2Jdbc(adTinyInt)},
+ {adSmallInt, ADOS::MapADOType2Jdbc(adSmallInt)},
+ {adInteger, ADOS::MapADOType2Jdbc(adInteger)},
+ {adBigInt, ADOS::MapADOType2Jdbc(adBigInt)},
+ {adUnsignedTinyInt, ADOS::MapADOType2Jdbc(adUnsignedTinyInt)},
+ {adUnsignedSmallInt, ADOS::MapADOType2Jdbc(adUnsignedSmallInt)},
+ {adUnsignedInt, ADOS::MapADOType2Jdbc(adUnsignedInt)},
+ {adUnsignedBigInt, ADOS::MapADOType2Jdbc(adUnsignedBigInt)},
+ {adSingle, ADOS::MapADOType2Jdbc(adSingle)},
+ {adDouble, ADOS::MapADOType2Jdbc(adDouble)},
+ {adCurrency, ADOS::MapADOType2Jdbc(adCurrency)},
+ {adDecimal, ADOS::MapADOType2Jdbc(adDecimal)},
+ {adNumeric, ADOS::MapADOType2Jdbc(adNumeric)},
+ {adBoolean, ADOS::MapADOType2Jdbc(adBoolean)},
+ {adError, ADOS::MapADOType2Jdbc(adError)},
+ {adUserDefined, ADOS::MapADOType2Jdbc(adUserDefined)},
+ {adVariant, ADOS::MapADOType2Jdbc(adVariant)},
+ {adIDispatch, ADOS::MapADOType2Jdbc(adIDispatch)},
+ {adIUnknown, ADOS::MapADOType2Jdbc(adIUnknown)},
+ {adGUID, ADOS::MapADOType2Jdbc(adGUID)},
+ {adDate, ADOS::MapADOType2Jdbc(_bJetEngine?adDBTimeStamp:adDate)},
+ {adDBDate, ADOS::MapADOType2Jdbc(adDBDate)},
+ {adDBTime, ADOS::MapADOType2Jdbc(adDBTime)},
+ {adDBTimeStamp, ADOS::MapADOType2Jdbc(adDBTimeStamp)},
+ {adBSTR, ADOS::MapADOType2Jdbc(adBSTR)},
+ {adChar, ADOS::MapADOType2Jdbc(adChar)},
+ {adVarChar, ADOS::MapADOType2Jdbc(adVarChar)},
+ {adLongVarChar, ADOS::MapADOType2Jdbc(adLongVarChar)},
+ {adWChar, ADOS::MapADOType2Jdbc(adWChar)},
+ {adVarWChar, ADOS::MapADOType2Jdbc(adVarWChar)},
+ {adLongVarWChar, ADOS::MapADOType2Jdbc(adLongVarWChar)},
+ {adBinary, ADOS::MapADOType2Jdbc(adBinary)},
+ {adVarBinary, ADOS::MapADOType2Jdbc(adVarBinary)},
+ {adLongVarBinary, ADOS::MapADOType2Jdbc(adLongVarBinary)},
+ {adChapter, ADOS::MapADOType2Jdbc(adChapter)},
+ {adFileTime, ADOS::MapADOType2Jdbc(adFileTime)},
+ {adPropVariant, ADOS::MapADOType2Jdbc(adPropVariant)},
+ {adVarNumeric, ADOS::MapADOType2Jdbc(adVarNumeric)}
+// {adArray, ADOS::MapADOType2Jdbc(adArray)}
+ };
+
+ m_aValueRange[2] = aMap;
+
+ ::std::map<sal_Int32,sal_Int32> aColumnValueMapping
+ {
+ { VARIANT_FALSE, ColumnValue::NO_NULLS },
+ { VARIANT_TRUE, ColumnValue::NULLABLE }
+ };
+ m_aValueRange[7] = aColumnValueMapping;
+
+ // now adjust the column mapping
+ // OJ 24.01.2002 96860
+ ::std::map<sal_Int32,sal_Int32> aSearchMapping
+ {
+ { DB_UNSEARCHABLE, ColumnSearch::NONE },
+ { DB_LIKE_ONLY, ColumnSearch::CHAR },
+ { DB_ALL_EXCEPT_LIKE, ColumnSearch::BASIC },
+ { DB_SEARCHABLE, ColumnSearch::FULL }
+ };
+
+ m_aValueRange[9] = aSearchMapping;
+
+ ::std::map<sal_Int32,sal_Int32> aCurrencyMapping;
+ m_aValueRange[11] = aCurrencyMapping;
+
+ rtl::Reference<ODatabaseMetaDataResultSetMetaData> pMetaData = new ODatabaseMetaDataResultSetMetaData(m_pRecordSet,this);
+ pMetaData->setTypeInfoMap();
+ m_xMetaData = pMetaData;
+}
+
+void SAL_CALL ODatabaseMetaDataResultSet::acquire() noexcept
+{
+ ODatabaseMetaDataResultSet_BASE::acquire();
+}
+
+void SAL_CALL ODatabaseMetaDataResultSet::release() noexcept
+{
+ ODatabaseMetaDataResultSet_BASE::release();
+}
+
+css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL ODatabaseMetaDataResultSet::getPropertySetInfo( )
+{
+ return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper());
+}
+
+OLEVariant ODatabaseMetaDataResultSet::getValue(sal_Int32 columnIndex )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed);
+
+ checkRecordSet();
+
+ WpADOField aField = ADOS::getField(m_pRecordSet,columnIndex);
+ aField.get_Value(m_aValue);
+ return m_aValue;
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/ado/ADatabaseMetaDataResultSetMetaData.cxx b/connectivity/source/drivers/ado/ADatabaseMetaDataResultSetMetaData.cxx
new file mode 100644
index 0000000000..3fa13d06b8
--- /dev/null
+++ b/connectivity/source/drivers/ado/ADatabaseMetaDataResultSetMetaData.cxx
@@ -0,0 +1,210 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <ado/ADatabaseMetaDataResultSetMetaData.hxx>
+#include <ado/Awrapado.hxx>
+#include <connectivity/dbexception.hxx>
+
+using namespace connectivity;
+using namespace connectivity::ado;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::sdbc;
+
+ODatabaseMetaDataResultSetMetaData::~ODatabaseMetaDataResultSetMetaData()
+{
+ if (m_pRecordSet)
+ m_pRecordSet->Release();
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaDataResultSetMetaData::getColumnDisplaySize(sal_Int32 column)
+{
+ sal_Int32 nSize = 0;
+ if (m_mColumns.size() && (m_mColumnsIter = m_mColumns.find(column)) != m_mColumns.end())
+ nSize = (*m_mColumnsIter).second.getColumnDisplaySize();
+ else if (m_pRecordSet)
+ {
+ WpADOField aField = ADOS::getField(m_pRecordSet, m_vMapping[column]);
+ if (aField.IsValid())
+ nSize = aField.GetActualSize();
+ }
+ return nSize;
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaDataResultSetMetaData::getColumnType(sal_Int32 column)
+{
+ sal_Int32 nType = 0;
+ if (m_mColumns.size() && (m_mColumnsIter = m_mColumns.find(column)) != m_mColumns.end())
+ nType = (*m_mColumnsIter).second.getColumnType();
+ else if (m_pRecordSet)
+ {
+ WpADOField aField = ADOS::getField(m_pRecordSet, m_vMapping[column]);
+ nType = ADOS::MapADOType2Jdbc(aField.GetADOType());
+ }
+ return nType;
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaDataResultSetMetaData::getColumnCount()
+{
+ if (!m_pRecordSet)
+ return 0;
+ if (m_nColCount != -1)
+ return m_nColCount;
+
+ if (m_vMapping.size())
+ return m_mColumns.size();
+
+ WpOLEAppendCollection<ADOFields, WpADOField> aFields;
+ m_pRecordSet->get_Fields(&aFields);
+ m_nColCount = aFields.GetItemCount();
+ return m_nColCount;
+}
+
+OUString SAL_CALL ODatabaseMetaDataResultSetMetaData::getColumnName(sal_Int32 column)
+{
+ if (m_mColumns.size() && (m_mColumnsIter = m_mColumns.find(column)) != m_mColumns.end())
+ return (*m_mColumnsIter).second.getColumnName();
+ if (!m_pRecordSet)
+ return OUString();
+ WpADOField aField = ADOS::getField(m_pRecordSet, m_vMapping[column]);
+ if (aField.IsValid())
+ return aField.GetName();
+
+ return OUString();
+}
+
+OUString SAL_CALL ODatabaseMetaDataResultSetMetaData::getColumnLabel(sal_Int32 column)
+{
+ if (m_mColumns.size() && (m_mColumnsIter = m_mColumns.find(column)) != m_mColumns.end())
+ return (*m_mColumnsIter).second.getColumnLabel();
+ return getColumnName(column);
+}
+
+sal_Bool SAL_CALL ODatabaseMetaDataResultSetMetaData::isCurrency(sal_Int32 column)
+{
+ if (m_mColumns.size() && (m_mColumnsIter = m_mColumns.find(column)) != m_mColumns.end())
+ return (*m_mColumnsIter).second.isCurrency();
+ if (!m_pRecordSet)
+ return false;
+ WpADOField aField = ADOS::getField(m_pRecordSet, m_vMapping[column]);
+ if (aField.IsValid())
+ {
+ return (aField.GetAttributes() & adFldFixed) == adFldFixed;
+ }
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaDataResultSetMetaData::isSigned(sal_Int32 column)
+{
+ if (m_mColumns.size() && (m_mColumnsIter = m_mColumns.find(column)) != m_mColumns.end())
+ return (*m_mColumnsIter).second.isSigned();
+ if (!m_pRecordSet)
+ return false;
+ WpADOField aField = ADOS::getField(m_pRecordSet, m_vMapping[column]);
+ if (aField.IsValid())
+ {
+ return (aField.GetAttributes() & adFldNegativeScale) == adFldNegativeScale;
+ }
+ return false;
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaDataResultSetMetaData::getPrecision(sal_Int32 column)
+{
+ if (m_mColumns.size() && (m_mColumnsIter = m_mColumns.find(column)) != m_mColumns.end())
+ return (*m_mColumnsIter).second.getPrecision();
+ if (!m_pRecordSet)
+ return 0;
+ WpADOField aField = ADOS::getField(m_pRecordSet, m_vMapping[column]);
+ if (aField.IsValid())
+ return aField.GetPrecision();
+ return 0;
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaDataResultSetMetaData::getScale(sal_Int32 column)
+{
+ if (m_mColumns.size() && (m_mColumnsIter = m_mColumns.find(column)) != m_mColumns.end())
+ return (*m_mColumnsIter).second.getScale();
+
+ if (!m_pRecordSet)
+ return 0;
+
+ WpADOField aField = ADOS::getField(m_pRecordSet, m_vMapping[column]);
+ if (aField.IsValid())
+ return aField.GetNumericScale();
+ return 0;
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaDataResultSetMetaData::isNullable(sal_Int32 column)
+{
+ if (m_mColumns.size() && (m_mColumnsIter = m_mColumns.find(column)) != m_mColumns.end())
+ return (*m_mColumnsIter).second.isNullable();
+
+ if (!m_pRecordSet)
+ return sal_Int32(false);
+
+ WpADOField aField = ADOS::getField(m_pRecordSet, m_vMapping[column]);
+ if (aField.IsValid())
+ {
+ return sal_Int32((aField.GetAttributes() & adFldIsNullable) == adFldIsNullable);
+ }
+ return sal_Int32(false);
+}
+
+sal_Bool SAL_CALL ODatabaseMetaDataResultSetMetaData::isReadOnly(sal_Int32 column)
+{
+ if (m_mColumns.size() && (m_mColumnsIter = m_mColumns.find(column)) != m_mColumns.end())
+ return (*m_mColumnsIter).second.isReadOnly();
+
+ if (!m_pRecordSet)
+ return false;
+
+ WpADOField aField = ADOS::getField(m_pRecordSet, m_vMapping[column]);
+ if (aField.IsValid())
+ {
+ // return (aField.GetStatus() & adFieldReadOnly) == adFieldReadOnly;
+ }
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaDataResultSetMetaData::isDefinitelyWritable(sal_Int32 column)
+{
+ if (m_mColumns.size() && (m_mColumnsIter = m_mColumns.find(column)) != m_mColumns.end())
+ return (*m_mColumnsIter).second.isDefinitelyWritable();
+
+ if (!m_pRecordSet)
+ return false;
+
+ WpADOField aField = ADOS::getField(m_pRecordSet, m_vMapping[column]);
+ if (aField.IsValid())
+ {
+ return (aField.GetAttributes() & adFldUpdatable) == adFldUpdatable;
+ }
+ return false;
+ ;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaDataResultSetMetaData::isWritable(sal_Int32 column)
+{
+ if (m_mColumns.size() && (m_mColumnsIter = m_mColumns.find(column)) != m_mColumns.end())
+ return (*m_mColumnsIter).second.isWritable();
+ return isDefinitelyWritable(column);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/ado/ADriver.cxx b/connectivity/source/drivers/ado/ADriver.cxx
new file mode 100644
index 0000000000..6568f7a1ee
--- /dev/null
+++ b/connectivity/source/drivers/ado/ADriver.cxx
@@ -0,0 +1,250 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <ado/ADriver.hxx>
+#include <ado/AConnection.hxx>
+#include <ado/Awrapadox.hxx>
+#include <ado/ACatalog.hxx>
+#include <ado/Awrapado.hxx>
+#include <ado/adoimp.hxx>
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <comphelper/servicehelper.hxx>
+#include <connectivity/dbexception.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <o3tl/safeCoInitUninit.hxx>
+#include <rtl/ref.hxx>
+#include <strings.hrc>
+#include <objbase.h>
+
+#include <resource/sharedresources.hxx>
+
+using namespace connectivity;
+using namespace connectivity::ado;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::sdbc;
+using namespace com::sun::star::sdbcx;
+
+
+ODriver::ODriver(const css::uno::Reference< css::uno::XComponentContext >& _xORB)
+ : ODriver_BASE(m_aMutex)
+ ,m_xContext(_xORB)
+ ,mnNbCallCoInitializeExForReinit(0)
+{
+ o3tl::safeCoInitializeEx(COINIT_APARTMENTTHREADED, mnNbCallCoInitializeExForReinit);
+}
+
+ODriver::~ODriver()
+{
+ o3tl::safeCoUninitializeReinit(COINIT_MULTITHREADED, mnNbCallCoInitializeExForReinit);
+}
+
+void ODriver::disposing()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+
+
+ for (auto& rxConnection : m_xConnections)
+ {
+ Reference< XComponent > xComp(rxConnection.get(), UNO_QUERY);
+ if (xComp.is())
+ xComp->dispose();
+ }
+ m_xConnections.clear();
+
+ ODriver_BASE::disposing();
+}
+// static ServiceInfo
+
+OUString ODriver::getImplementationName( )
+{
+ return "com.sun.star.comp.sdbc.ado.ODriver";
+}
+
+Sequence< OUString > ODriver::getSupportedServiceNames( )
+{
+ return { "com.sun.star.sdbc.Driver", "com.sun.star.sdbcx.Driver" };
+}
+
+sal_Bool SAL_CALL ODriver::supportsService( const OUString& _rServiceName )
+{
+ return cppu::supportsService(this, _rServiceName);
+}
+
+Reference< XConnection > SAL_CALL ODriver::connect( const OUString& url, const Sequence< PropertyValue >& info )
+{
+ if ( ! acceptsURL(url) )
+ return nullptr;
+
+ // we need to wrap the connection as the construct call might throw
+ rtl::Reference<OConnection> pCon(new OConnection(this));
+ pCon->construct(url,info);
+ OConnection* pPtr = pCon.get();
+ m_xConnections.push_back(WeakReferenceHelper(*pPtr));
+
+ return pCon;
+}
+
+sal_Bool SAL_CALL ODriver::acceptsURL( const OUString& url )
+{
+ return url.startsWith("sdbc:ado:");
+}
+
+void ODriver::impl_checkURL_throw(const OUString& _sUrl)
+{
+ if ( !acceptsURL(_sUrl) )
+ {
+ SharedResources aResources;
+ const OUString sMessage = aResources.getResourceString(STR_URI_SYNTAX_ERROR);
+ ::dbtools::throwGenericSQLException(sMessage ,*this);
+ } // if ( !acceptsURL(_sUrl) )
+}
+
+Sequence< DriverPropertyInfo > SAL_CALL ODriver::getPropertyInfo( const OUString& url, const Sequence< PropertyValue >& /*info*/ )
+{
+ impl_checkURL_throw(url);
+ if ( acceptsURL(url) )
+ {
+ Sequence< OUString > aBooleanValues{ "false", "true" };
+
+ return
+ {
+ {
+ "IgnoreDriverPrivileges",
+ "Ignore the privileges from the database driver.",
+ false,
+ "false",
+ aBooleanValues
+ },
+ {
+ "EscapeDateTime",
+ "Escape date time format.",
+ false,
+ "true",
+ aBooleanValues
+ },
+ {
+ "TypeInfoSettings",
+ "Defines how the type info of the database metadata should be manipulated.",
+ false,
+ {},
+ {}
+ }
+ };
+ }
+ return Sequence< DriverPropertyInfo >();
+}
+
+sal_Int32 SAL_CALL ODriver::getMajorVersion( )
+{
+ return 1;
+}
+
+sal_Int32 SAL_CALL ODriver::getMinorVersion( )
+{
+ return 0;
+}
+
+// XDataDefinitionSupplier
+Reference< XTablesSupplier > SAL_CALL ODriver::getDataDefinitionByConnection( const Reference< css::sdbc::XConnection >& connection )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if (ODriver_BASE::rBHelper.bDisposed)
+ throw DisposedException();
+
+ OConnection* pConnection = nullptr;
+ Reference< css::lang::XUnoTunnel> xTunnel(connection,UNO_QUERY);
+ if (auto pSearchConnection = comphelper::getFromUnoTunnel<OConnection>(xTunnel))
+ {
+ auto foundConnection = std::any_of(m_xConnections.begin(), m_xConnections.end(),
+ [&pSearchConnection](const css::uno::WeakReferenceHelper& rxConnection) {
+ return static_cast<OConnection*>(Reference< XConnection >::query(rxConnection.get()).get()) == pSearchConnection; });
+ if (foundConnection)
+ pConnection = pSearchConnection;
+ }
+
+ Reference< XTablesSupplier > xTab;
+ if(pConnection)
+ {
+ WpADOCatalog aCatalog;
+ aCatalog.Create();
+ if(aCatalog.IsValid())
+ {
+ aCatalog.putref_ActiveConnection(pConnection->getConnection());
+ rtl::Reference<OCatalog> pCatalog = new OCatalog(aCatalog,pConnection);
+ xTab = pCatalog;
+ pConnection->setCatalog(xTab);
+ pConnection->setCatalog(pCatalog.get());
+ }
+ }
+ return xTab;
+}
+
+Reference< XTablesSupplier > SAL_CALL ODriver::getDataDefinitionByURL( const OUString& url, const Sequence< PropertyValue >& info )
+{
+ impl_checkURL_throw(url);
+ return getDataDefinitionByConnection(connect(url,info));
+}
+
+
+void ADOS::ThrowException(ADOConnection* _pAdoCon,const Reference< XInterface >& _xInterface)
+{
+ sal::systools::COMReference<ADOErrors> pErrors;
+ _pAdoCon->get_Errors(&pErrors);
+ if(!pErrors)
+ return; // no error found
+
+ // read all noted errors and issue them
+ sal_Int32 nLen;
+ pErrors->get_Count(&nLen);
+ if (nLen)
+ {
+ SQLException aException;
+ aException.ErrorCode = 1000;
+ for (sal_Int32 i = nLen-1; i>=0; --i)
+ {
+ WpADOError aErr;
+ pErrors->get_Item(OLEVariant(i),&aErr);
+ OSL_ENSURE(aErr,"No error in collection found! BAD!");
+ if(aErr)
+ {
+ if(i==nLen-1)
+ aException = SQLException(aErr.GetDescription(),_xInterface,aErr.GetSQLState(),aErr.GetNumber(),Any());
+ else
+ {
+ SQLException aTemp(aErr.GetDescription(),
+ _xInterface,aErr.GetSQLState(),aErr.GetNumber(),Any(aException));
+ aTemp.NextException <<= aException;
+ aException = aTemp;
+ }
+ }
+ }
+ pErrors->Clear();
+ throw aException;
+ }
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+connectivity_ado_ODriver_get_implementation(
+ css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new ODriver(context));
+}
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/ado/AGroup.cxx b/connectivity/source/drivers/ado/AGroup.cxx
new file mode 100644
index 0000000000..02cd239d76
--- /dev/null
+++ b/connectivity/source/drivers/ado/AGroup.cxx
@@ -0,0 +1,127 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <ado/AGroup.hxx>
+#include <ado/AUsers.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XResultSet.hpp>
+#include <ado/AConnection.hxx>
+#include <TConnection.hxx>
+
+using namespace connectivity::ado;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::sdbc;
+using namespace com::sun::star::sdbcx;
+
+
+void WpADOGroup::Create()
+{
+ pInterface.CoCreateInstance(ADOS::CLSID_ADOGROUP_25, nullptr, CLSCTX_INPROC_SERVER);
+}
+
+OAdoGroup::OAdoGroup(OCatalog* _pParent,bool _bCase, ADOGroup* _pGroup) : OGroup_ADO(_bCase),m_pCatalog(_pParent)
+{
+ construct();
+ if(_pGroup)
+ m_aGroup.set(_pGroup);
+ else
+ m_aGroup.Create();
+
+}
+
+OAdoGroup::OAdoGroup(OCatalog* _pParent,bool _bCase, const OUString& Name) : OGroup_ADO(Name,_bCase),m_pCatalog(_pParent)
+{
+ construct();
+ m_aGroup.Create();
+ m_aGroup.put_Name(Name);
+}
+
+void OAdoGroup::refreshUsers()
+{
+ ::std::vector< OUString> aVector;
+
+ WpADOUsers aUsers = m_aGroup.get_Users();
+ aUsers.fillElementNames(aVector);
+
+ if(m_pUsers)
+ m_pUsers->reFill(aVector);
+ else
+ m_pUsers.reset(new OUsers(m_pCatalog, m_aMutex, aVector, aUsers, isCaseSensitive()));
+}
+
+void OAdoGroup::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,const Any& rValue)
+{
+ if(m_aGroup.IsValid())
+ {
+
+ switch(nHandle)
+ {
+ case PROPERTY_ID_NAME:
+ {
+ OUString aVal;
+ rValue >>= aVal;
+ m_aGroup.put_Name(aVal);
+ }
+ break;
+ }
+ }
+}
+
+void OAdoGroup::getFastPropertyValue(Any& rValue,sal_Int32 nHandle) const
+{
+ if(m_aGroup.IsValid())
+ {
+ switch(nHandle)
+ {
+ case PROPERTY_ID_NAME:
+ rValue <<= m_aGroup.get_Name();
+ break;
+ }
+ }
+}
+
+
+sal_Int32 SAL_CALL OAdoGroup::getPrivileges( const OUString& objName, sal_Int32 objType )
+{
+ return MapRight(m_aGroup.GetPermissions(objName,MapObjectType(objType)));
+}
+
+sal_Int32 SAL_CALL OAdoGroup::getGrantablePrivileges( const OUString& objName, sal_Int32 objType )
+{
+ RightsEnum eNum = m_aGroup.GetPermissions(objName,MapObjectType(objType));
+ if(eNum & adRightWithGrant)
+ return MapRight(eNum);
+ return 0;
+}
+
+void SAL_CALL OAdoGroup::grantPrivileges( const OUString& objName, sal_Int32 objType, sal_Int32 objPrivileges )
+{
+ m_aGroup.SetPermissions(objName,MapObjectType(objType),adAccessGrant,Map2Right(objPrivileges));
+}
+
+void SAL_CALL OAdoGroup::revokePrivileges( const OUString& objName, sal_Int32 objType, sal_Int32 objPrivileges )
+{
+ m_aGroup.SetPermissions(objName,MapObjectType(objType),adAccessDeny,Map2Right(objPrivileges));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/ado/AGroups.cxx b/connectivity/source/drivers/ado/AGroups.cxx
new file mode 100644
index 0000000000..6f7c8b2da8
--- /dev/null
+++ b/connectivity/source/drivers/ado/AGroups.cxx
@@ -0,0 +1,76 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <ado/AGroups.hxx>
+#include <ado/AGroup.hxx>
+#include <ado/ATable.hxx>
+#include <ado/AConnection.hxx>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XResultSet.hpp>
+#include <connectivity/sdbcx/IRefreshable.hxx>
+#include <TConnection.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <comphelper/types.hxx>
+#include <connectivity/dbexception.hxx>
+#include <strings.hrc>
+
+using namespace comphelper;
+using namespace connectivity;
+using namespace connectivity::ado;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::sdbc;
+using namespace com::sun::star::container;
+
+
+sdbcx::ObjectType OGroups::createObject(const OUString& _rName)
+{
+ return new OAdoGroup(m_pCatalog,isCaseSensitive(),_rName);
+}
+
+void OGroups::impl_refresh()
+{
+ m_aCollection.Refresh();
+}
+
+Reference< XPropertySet > OGroups::createDescriptor()
+{
+ return new OAdoGroup(m_pCatalog,isCaseSensitive());
+}
+
+// XAppend
+sdbcx::ObjectType OGroups::appendObject( const OUString& _rForName, const Reference< XPropertySet >& descriptor )
+{
+ OAdoGroup* pGroup = dynamic_cast<OAdoGroup*>(descriptor.get());
+ if ( pGroup == nullptr )
+ m_pCatalog->getConnection()->throwGenericSQLException( STR_INVALID_GROUP_DESCRIPTOR_ERROR,static_cast<XTypeProvider*>(this) );
+
+ m_aCollection.Append( pGroup->getImpl() );
+ return createObject( _rForName );
+}
+
+// XDrop
+void OGroups::dropObject(sal_Int32 /*_nPos*/,const OUString& _sElementName)
+{
+ m_aCollection.Delete(_sElementName);
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/ado/AIndex.cxx b/connectivity/source/drivers/ado/AIndex.cxx
new file mode 100644
index 0000000000..b183d49c24
--- /dev/null
+++ b/connectivity/source/drivers/ado/AIndex.cxx
@@ -0,0 +1,107 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <ado/AIndex.hxx>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XResultSet.hpp>
+#include <ado/AColumns.hxx>
+#include <TConnection.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <comphelper/types.hxx>
+
+using namespace ::comphelper;
+
+using namespace connectivity::ado;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::sdbc;
+
+
+OAdoIndex::OAdoIndex(bool _bCase,OConnection* _pConnection,ADOIndex* _pIndex)
+ : sdbcx::OIndex(OUString(),OUString(),false,false,false,_bCase)
+ ,m_pConnection(_pConnection)
+{
+ construct();
+ m_aIndex.set(_pIndex);
+ fillPropertyValues();
+}
+
+OAdoIndex::OAdoIndex(bool _bCase,OConnection* _pConnection)
+ : sdbcx::OIndex(_bCase)
+ ,m_pConnection(_pConnection)
+{
+ construct();
+ m_aIndex.Create();
+}
+
+
+void OAdoIndex::refreshColumns()
+{
+ ::std::vector< OUString> aVector;
+
+ WpADOColumns aColumns;
+ if ( m_aIndex.IsValid() )
+ {
+ aColumns = m_aIndex.get_Columns();
+ aColumns.fillElementNames(aVector);
+ }
+
+ if ( m_pColumns )
+ m_pColumns->reFill(aVector);
+ else
+ m_pColumns.reset(new OColumns(*this, m_aMutex, aVector, aColumns, isCaseSensitive(), m_pConnection));
+}
+
+
+void SAL_CALL OAdoIndex::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,const Any& rValue)
+{
+ if(m_aIndex.IsValid())
+ {
+ switch(nHandle)
+ {
+ case PROPERTY_ID_NAME:
+ {
+ OUString aVal;
+ rValue >>= aVal;
+ m_aIndex.put_Name(aVal);
+ }
+ break;
+ case PROPERTY_ID_CATALOG:
+ {
+ OUString aVal;
+ rValue >>= aVal;
+ m_aIndex.put_Name(aVal);
+ }
+ break;
+ case PROPERTY_ID_ISUNIQUE:
+ m_aIndex.put_Unique(getBOOL(rValue));
+ break;
+ case PROPERTY_ID_ISPRIMARYKEYINDEX:
+ m_aIndex.put_PrimaryKey(getBOOL(rValue));
+ break;
+ case PROPERTY_ID_ISCLUSTERED:
+ m_aIndex.put_Clustered(getBOOL(rValue));
+ break;
+ }
+ }
+ sdbcx::OIndex::setFastPropertyValue_NoBroadcast(nHandle,rValue);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/ado/AIndexes.cxx b/connectivity/source/drivers/ado/AIndexes.cxx
new file mode 100644
index 0000000000..1e427a2f07
--- /dev/null
+++ b/connectivity/source/drivers/ado/AIndexes.cxx
@@ -0,0 +1,82 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <ado/AIndexes.hxx>
+#include <ado/AIndex.hxx>
+#include <ado/AConnection.hxx>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XResultSet.hpp>
+#include <com/sun/star/sdbc/IndexType.hpp>
+#include <TConnection.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <comphelper/types.hxx>
+#include <connectivity/dbexception.hxx>
+#include <strings.hrc>
+
+using namespace ::comphelper;
+
+
+using namespace connectivity;
+using namespace connectivity::ado;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::sdbc;
+using namespace com::sun::star::container;
+
+sdbcx::ObjectType OIndexes::createObject(const OUString& _rName)
+{
+ return new OAdoIndex(isCaseSensitive(),m_pConnection,m_aCollection.GetItem(_rName));
+}
+
+void OIndexes::impl_refresh()
+{
+ m_aCollection.Refresh();
+}
+
+Reference< XPropertySet > OIndexes::createDescriptor()
+{
+ return new OAdoIndex(isCaseSensitive(),m_pConnection);
+}
+
+// XAppend
+sdbcx::ObjectType OIndexes::appendObject( const OUString& _rForName, const Reference< XPropertySet >& descriptor )
+{
+ OAdoIndex* pIndex = dynamic_cast<OAdoIndex*>(descriptor.get());
+ if ( pIndex == nullptr )
+ m_pConnection->throwGenericSQLException( STR_INVALID_INDEX_DESCRIPTOR_ERROR,static_cast<XTypeProvider*>(this) );
+
+ ADOIndexes* pIndexes = m_aCollection;
+ if ( FAILED( pIndexes->Append( OLEVariant( _rForName ), OLEVariant( pIndex->getImpl() ) ) ) )
+ {
+ ADOS::ThrowException(m_pConnection->getConnection(),static_cast<XTypeProvider*>(this));
+ m_pConnection->throwGenericSQLException( STR_INVALID_INDEX_DESCRIPTOR_ERROR,static_cast<XTypeProvider*>(this) );
+ }
+
+ return new OAdoIndex(isCaseSensitive(),m_pConnection,pIndex->getImpl());
+}
+
+// XDrop
+void OIndexes::dropObject(sal_Int32 /*_nPos*/,const OUString& _sElementName)
+{
+ m_aCollection.Delete(_sElementName);
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/ado/AKey.cxx b/connectivity/source/drivers/ado/AKey.cxx
new file mode 100644
index 0000000000..9c2734ede8
--- /dev/null
+++ b/connectivity/source/drivers/ado/AKey.cxx
@@ -0,0 +1,120 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <ado/AKey.hxx>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XResultSet.hpp>
+#include <comphelper/servicehelper.hxx>
+#include <ado/AColumns.hxx>
+#include <ado/AConnection.hxx>
+
+using namespace connectivity::ado;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::sdbc;
+using namespace com::sun::star::sdbcx;
+
+
+OAdoKey::OAdoKey(bool _bCase,OConnection* _pConnection, ADOKey* _pKey)
+ : OKey_ADO(_bCase)
+ ,m_pConnection(_pConnection)
+{
+ construct();
+ m_aKey.set(_pKey);
+ fillPropertyValues();
+}
+
+OAdoKey::OAdoKey(bool _bCase,OConnection* _pConnection)
+ : OKey_ADO(_bCase)
+ ,m_pConnection(_pConnection)
+{
+ construct();
+ m_aKey.Create();
+}
+
+void OAdoKey::refreshColumns()
+{
+ ::std::vector< OUString> aVector;
+
+ WpADOColumns aColumns;
+ if ( m_aKey.IsValid() )
+ {
+ aColumns = m_aKey.get_Columns();
+ aColumns.fillElementNames(aVector);
+ }
+
+ if(m_pColumns)
+ m_pColumns->reFill(aVector);
+ else
+ m_pColumns.reset(new OColumns(*this, m_aMutex, aVector, aColumns, isCaseSensitive(), m_pConnection));
+}
+
+void OAdoKey::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,const Any& rValue)
+{
+ if(m_aKey.IsValid())
+ {
+ switch(nHandle)
+ {
+ case PROPERTY_ID_NAME:
+ {
+ OUString aVal;
+ rValue >>= aVal;
+ m_aKey.put_Name(aVal);
+ ADOS::ThrowException(m_pConnection->getConnection(),*this);
+ }
+ break;
+ case PROPERTY_ID_TYPE:
+ {
+ sal_Int32 nVal=0;
+ rValue >>= nVal;
+ m_aKey.put_Type(Map2KeyRule(nVal));
+ ADOS::ThrowException(m_pConnection->getConnection(),*this);
+ }
+ break;
+ case PROPERTY_ID_REFERENCEDTABLE:
+ {
+ OUString aVal;
+ rValue >>= aVal;
+ m_aKey.put_RelatedTable(aVal);
+ ADOS::ThrowException(m_pConnection->getConnection(),*this);
+ }
+ break;
+ case PROPERTY_ID_UPDATERULE:
+ {
+ sal_Int32 nVal=0;
+ rValue >>= nVal;
+ m_aKey.put_UpdateRule(Map2Rule(nVal));
+ ADOS::ThrowException(m_pConnection->getConnection(),*this);
+ }
+ break;
+ case PROPERTY_ID_DELETERULE:
+ {
+ sal_Int32 nVal=0;
+ rValue >>= nVal;
+ m_aKey.put_DeleteRule(Map2Rule(nVal));
+ ADOS::ThrowException(m_pConnection->getConnection(),*this);
+ }
+ break;
+ }
+ }
+ OKey_ADO::setFastPropertyValue_NoBroadcast(nHandle,rValue);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/ado/AKeys.cxx b/connectivity/source/drivers/ado/AKeys.cxx
new file mode 100644
index 0000000000..32d02bc743
--- /dev/null
+++ b/connectivity/source/drivers/ado/AKeys.cxx
@@ -0,0 +1,97 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <ado/AKeys.hxx>
+#include <ado/AKey.hxx>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XResultSet.hpp>
+#include <com/sun/star/sdbcx/KeyType.hpp>
+#include <com/sun/star/sdbc/KeyRule.hpp>
+#include <ado/AConnection.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <comphelper/types.hxx>
+#include <ado/Awrapado.hxx>
+#include <connectivity/dbexception.hxx>
+#include <strings.hrc>
+
+using namespace ::comphelper;
+using namespace connectivity;
+using namespace connectivity::ado;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::sdbc;
+using namespace com::sun::star::sdbcx;
+using namespace com::sun::star::container;
+
+sdbcx::ObjectType OKeys::createObject(const OUString& _rName)
+{
+ return new OAdoKey(isCaseSensitive(),m_pConnection,m_aCollection.GetItem(_rName));
+}
+
+void OKeys::impl_refresh()
+{
+ m_aCollection.Refresh();
+}
+
+Reference< XPropertySet > OKeys::createDescriptor()
+{
+ return new OAdoKey(isCaseSensitive(),m_pConnection);
+}
+
+// XAppend
+sdbcx::ObjectType OKeys::appendObject( const OUString&, const Reference< XPropertySet >& descriptor )
+{
+ OAdoKey* pKey = dynamic_cast<OAdoKey*>( descriptor.get() );
+ if ( pKey == nullptr)
+ m_pConnection->throwGenericSQLException( STR_INVALID_KEY_DESCRIPTOR_ERROR,static_cast<XTypeProvider*>(this) );
+
+ // To pass as column parameter to Key's Append method
+ OLEVariant vOptional;
+ vOptional.setNoArg();
+
+ OAdoKey::Map2KeyRule(getINT32(descriptor->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE))));
+
+ WpADOKey aKey = pKey->getImpl();
+ OUString sName = aKey.get_Name();
+ if(!sName.getLength())
+ aKey.put_Name(u"PrimaryKey");
+
+ ADOKeys* pKeys = m_aCollection;
+ if ( FAILED(pKeys->Append(OLEVariant(static_cast<ADOKey*>(aKey)),
+ adKeyPrimary, // must be every time adKeyPrimary
+ vOptional)) )
+ {
+ ADOS::ThrowException(m_pConnection->getConnection(),static_cast<XTypeProvider*>(this));
+ // just make sure that an SQLExceptionis thrown here
+ m_pConnection->throwGenericSQLException( STR_INVALID_KEY_DESCRIPTOR_ERROR,static_cast<XTypeProvider*>(this) );
+ }
+
+ return new OAdoKey(isCaseSensitive(),m_pConnection,pKey->getImpl());
+}
+
+// XDrop
+void OKeys::dropObject(sal_Int32 /*_nPos*/,const OUString& _sElementName)
+{
+ if(!m_aCollection.Delete(OLEVariant(_sElementName).getString()))
+ ADOS::ThrowException(m_pConnection->getConnection(),static_cast<XTypeProvider*>(this));
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/ado/APreparedStatement.cxx b/connectivity/source/drivers/ado/APreparedStatement.cxx
new file mode 100644
index 0000000000..9e17d71b0b
--- /dev/null
+++ b/connectivity/source/drivers/ado/APreparedStatement.cxx
@@ -0,0 +1,455 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <connectivity/sqlparse.hxx>
+#include <ado/APreparedStatement.hxx>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <ado/AResultSetMetaData.hxx>
+#include <ado/AResultSet.hxx>
+#include <ado/ADriver.hxx>
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <cppuhelper/typeprovider.hxx>
+#include <cppuhelper/queryinterface.hxx>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/sequence.hxx>
+#include <comphelper/types.hxx>
+#include <connectivity/dbexception.hxx>
+#include <connectivity/dbtools.hxx>
+#include <rtl/ref.hxx>
+#include <strings.hrc>
+
+#include <limits>
+
+#define CHECK_RETURN(x) \
+ if(!x) \
+ ADOS::ThrowException(m_pConnection->getConnection(),*this);
+
+#ifdef max
+# undef max
+#endif
+
+using namespace connectivity::ado;
+using namespace connectivity;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::sdbc;
+using namespace com::sun::star::util;
+
+IMPLEMENT_SERVICE_INFO(OPreparedStatement,"com.sun.star.sdbcx.APreparedStatement","com.sun.star.sdbc.PreparedStatement");
+
+OPreparedStatement::OPreparedStatement( OConnection* _pConnection, const OUString& sql)
+ : OStatement_Base( _pConnection )
+{
+ osl_atomic_increment( &m_refCount );
+
+ OSQLParser aParser(_pConnection->getDriver()->getContext());
+ OUString sErrorMessage;
+ OUString sNewSql;
+ std::unique_ptr<OSQLParseNode> pNode = aParser.parseTree(sErrorMessage,sql);
+ if(pNode)
+ { // special handling for parameters
+ // we recursive replace all occurrences of ? in the statement and
+ // replace them with name like "parame" */
+ sal_Int32 nParameterCount = 0;
+ replaceParameterNodeName(pNode.get(), "parame", nParameterCount);
+ pNode->parseNodeToStr( sNewSql, _pConnection );
+ }
+ else
+ sNewSql = sql;
+ CHECK_RETURN(m_Command.put_CommandText(sNewSql))
+ CHECK_RETURN(m_Command.put_Prepared(VARIANT_TRUE))
+ m_pParameters = m_Command.get_Parameters();
+ m_pParameters->AddRef();
+ m_pParameters->Refresh();
+
+ osl_atomic_decrement( &m_refCount );
+}
+
+OPreparedStatement::~OPreparedStatement()
+{
+ if (m_pParameters)
+ {
+ OSL_FAIL( "OPreparedStatement::~OPreparedStatement: not disposed!" );
+ m_pParameters->Release();
+ m_pParameters = nullptr;
+ }
+}
+
+Any SAL_CALL OPreparedStatement::queryInterface( const Type & rType )
+{
+ Any aRet = OStatement_Base::queryInterface(rType);
+ return aRet.hasValue() ? aRet : ::cppu::queryInterface( rType,
+ static_cast< XPreparedStatement*>(this),
+ static_cast< XParameters*>(this),
+ static_cast< XResultSetMetaDataSupplier*>(this));
+}
+
+css::uno::Sequence< css::uno::Type > SAL_CALL OPreparedStatement::getTypes( )
+{
+ ::cppu::OTypeCollection aTypes( cppu::UnoType<XPreparedStatement>::get(),
+ cppu::UnoType<XParameters>::get(),
+ cppu::UnoType<XResultSetMetaDataSupplier>::get());
+
+ return ::comphelper::concatSequences(aTypes.getTypes(),OStatement_Base::getTypes());
+}
+
+Reference< XResultSetMetaData > SAL_CALL OPreparedStatement::getMetaData( )
+{
+ if(!m_xMetaData.is() && m_RecordSet.IsValid())
+ m_xMetaData = new OResultSetMetaData(m_RecordSet);
+ return m_xMetaData;
+}
+
+void OPreparedStatement::disposing()
+{
+ m_xMetaData.clear();
+ if (m_pParameters)
+ {
+ m_pParameters->Release();
+ m_pParameters = nullptr;
+ }
+ OStatement_Base::disposing();
+}
+
+void SAL_CALL OPreparedStatement::close( )
+{
+
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OStatement_BASE::rBHelper.bDisposed);
+
+ }
+ dispose();
+
+}
+
+sal_Bool SAL_CALL OPreparedStatement::execute( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OStatement_BASE::rBHelper.bDisposed);
+
+ clearWarnings ();
+
+ // Call SQLExecute
+ try {
+ ADORecordset* pSet=nullptr;
+ CHECK_RETURN(m_Command.Execute(m_RecordsAffected,m_Parameters,adCmdUnknown,&pSet))
+ m_RecordSet.set(pSet);
+ }
+ catch (SQLWarning&)
+ {
+ //TODO: Save pointer to warning and save with ResultSet
+ // object once it is created.
+ }
+ return m_RecordSet.IsValid();
+}
+
+sal_Int32 SAL_CALL OPreparedStatement::executeUpdate( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OStatement_BASE::rBHelper.bDisposed);
+
+
+ ADORecordset* pSet=nullptr;
+ CHECK_RETURN(m_Command.Execute(m_RecordsAffected,m_Parameters,adCmdUnknown,&pSet))
+ if ( VT_ERROR == m_RecordsAffected.getType() )
+ {
+ ADOS::ThrowException(m_pConnection->getConnection(),*this);
+ // to be sure that we get the error really thrown
+ throw SQLException();
+ }
+ m_RecordSet.set(pSet);
+ return m_RecordsAffected.getInt32();
+}
+
+void OPreparedStatement::setParameter(sal_Int32 parameterIndex, const DataTypeEnum& _eType,
+ sal_Int32 _nSize,const OLEVariant& Val)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OStatement_BASE::rBHelper.bDisposed);
+
+
+ sal_Int32 nCount = 0;
+ m_pParameters->get_Count(&nCount);
+ if(nCount < (parameterIndex-1))
+ {
+ OUString sDefaultName = "parame" + OUString::number(parameterIndex);
+ ADOParameter* pParam = m_Command.CreateParameter(sDefaultName,_eType,adParamInput,_nSize,Val);
+ if(pParam)
+ {
+ m_pParameters->Append(pParam);
+ }
+ }
+ else
+ {
+ WpADOParameter aParam;
+ m_pParameters->get_Item(OLEVariant(sal_Int32(parameterIndex-1)),&aParam);
+ if(aParam)
+ {
+ DataTypeEnum eType = aParam.GetADOType();
+ if ( _eType != eType && _eType != adDBTimeStamp )
+ {
+ aParam.put_Type(_eType);
+ eType = _eType;
+ aParam.put_Size(_nSize);
+ }
+
+ if ( adVarBinary == eType && aParam.GetAttributes() == adParamLong )
+ {
+ aParam.AppendChunk(Val);
+ }
+ else
+ CHECK_RETURN(aParam.PutValue(Val));
+ }
+ }
+ ADOS::ThrowException(m_pConnection->getConnection(),*this);
+}
+
+void SAL_CALL OPreparedStatement::setString( sal_Int32 parameterIndex, const OUString& x )
+{
+ setParameter( parameterIndex, adLongVarWChar, std::numeric_limits< sal_Int32 >::max(), x );
+}
+
+Reference< XConnection > SAL_CALL OPreparedStatement::getConnection( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OStatement_BASE::rBHelper.bDisposed);
+
+ return static_cast<Reference< XConnection >>(m_pConnection);
+}
+
+Reference< XResultSet > SAL_CALL OPreparedStatement::executeQuery( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OStatement_BASE::rBHelper.bDisposed);
+
+ // first clear the old things
+ m_xMetaData.clear();
+ disposeResultSet();
+ if(m_RecordSet.IsValid())
+ m_RecordSet.Close();
+ m_RecordSet.clear();
+
+ // then create the new ones
+ m_RecordSet.Create();
+ OLEVariant aCmd;
+ aCmd.setIDispatch(m_Command);
+ OLEVariant aCon;
+ aCon.setNoArg();
+ CHECK_RETURN(m_RecordSet.put_CacheSize(m_nFetchSize))
+ CHECK_RETURN(m_RecordSet.put_MaxRecords(m_nMaxRows))
+ CHECK_RETURN(m_RecordSet.Open(aCmd,aCon,m_eCursorType,m_eLockType,adOpenUnspecified))
+ CHECK_RETURN(m_RecordSet.get_CacheSize(m_nFetchSize))
+ CHECK_RETURN(m_RecordSet.get_MaxRecords(m_nMaxRows))
+ CHECK_RETURN(m_RecordSet.get_CursorType(m_eCursorType))
+ CHECK_RETURN(m_RecordSet.get_LockType(m_eLockType))
+
+ rtl::Reference<OResultSet> pSet = new OResultSet(m_RecordSet,this);
+ pSet->construct();
+ pSet->setMetaData(getMetaData());
+ m_xResultSet = WeakReference<XResultSet>(pSet);
+
+ return pSet;
+}
+
+void SAL_CALL OPreparedStatement::setBoolean( sal_Int32 parameterIndex, sal_Bool x )
+{
+ setParameter(parameterIndex,adBoolean,sizeof(x),bool(x));
+}
+
+void SAL_CALL OPreparedStatement::setByte( sal_Int32 parameterIndex, sal_Int8 x )
+{
+ setParameter(parameterIndex,adTinyInt,sizeof(x),x);
+}
+
+void SAL_CALL OPreparedStatement::setDate( sal_Int32 parameterIndex, const Date& x )
+{
+ setParameter(parameterIndex,adDBDate,sizeof(x),x);
+}
+
+void SAL_CALL OPreparedStatement::setTime( sal_Int32 parameterIndex, const css::util::Time& x )
+{
+ setParameter(parameterIndex,adDBTime,sizeof(x),x);
+}
+
+void SAL_CALL OPreparedStatement::setTimestamp( sal_Int32 parameterIndex, const DateTime& x )
+{
+ setParameter(parameterIndex,adDBTimeStamp,sizeof(x),x);
+}
+
+void SAL_CALL OPreparedStatement::setDouble( sal_Int32 parameterIndex, double x )
+{
+ setParameter(parameterIndex,adDouble,sizeof(x),x);
+}
+
+void SAL_CALL OPreparedStatement::setFloat( sal_Int32 parameterIndex, float x )
+{
+ setParameter(parameterIndex,adSingle,sizeof(x),x);
+}
+
+void SAL_CALL OPreparedStatement::setInt( sal_Int32 parameterIndex, sal_Int32 x )
+{
+ setParameter(parameterIndex,adInteger,sizeof(x),x);
+}
+
+void SAL_CALL OPreparedStatement::setLong( sal_Int32 parameterIndex, sal_Int64 x )
+{
+ setParameter(parameterIndex,adBigInt,sizeof(x),x);
+}
+
+void SAL_CALL OPreparedStatement::setNull( sal_Int32 parameterIndex, sal_Int32 /*sqlType*/ )
+{
+ OLEVariant aVal;
+ aVal.setNull();
+ setParameter(parameterIndex,adEmpty,0,aVal);
+}
+
+void SAL_CALL OPreparedStatement::setClob( sal_Int32 /*parameterIndex*/, const Reference< XClob >& /*x*/ )
+{
+ ::dbtools::throwFeatureNotImplementedSQLException( "XRowUpdate::setClob", *this );
+}
+
+void SAL_CALL OPreparedStatement::setBlob( sal_Int32 /*parameterIndex*/, const Reference< XBlob >& /*x*/ )
+{
+ ::dbtools::throwFeatureNotImplementedSQLException( "XRowUpdate::setBlob", *this );
+}
+
+void SAL_CALL OPreparedStatement::setArray( sal_Int32 /*parameterIndex*/, const Reference< XArray >& /*x*/ )
+{
+ ::dbtools::throwFeatureNotImplementedSQLException( "XRowUpdate::setArray", *this );
+}
+
+void SAL_CALL OPreparedStatement::setRef( sal_Int32 /*parameterIndex*/, const Reference< XRef >& /*x*/ )
+{
+ ::dbtools::throwFeatureNotImplementedSQLException( "XRowUpdate::setRef", *this );
+}
+
+void SAL_CALL OPreparedStatement::setObjectWithInfo( sal_Int32 parameterIndex, const Any& x, sal_Int32 sqlType, sal_Int32 scale )
+{
+ switch(sqlType)
+ {
+ case DataType::DECIMAL:
+ case DataType::NUMERIC:
+ setString(parameterIndex,::comphelper::getString(x));
+ break;
+ default:
+ ::dbtools::setObjectWithInfo(this,parameterIndex,x,sqlType,scale);
+ break;
+ }
+}
+
+void SAL_CALL OPreparedStatement::setObjectNull( sal_Int32 parameterIndex, sal_Int32 sqlType, const OUString& /*typeName*/ )
+{
+ setNull(parameterIndex,sqlType);
+}
+
+void SAL_CALL OPreparedStatement::setObject( sal_Int32 parameterIndex, const Any& x )
+{
+ if(!::dbtools::implSetObject(this,parameterIndex,x))
+ {
+ const OUString sError( m_pConnection->getResources().getResourceStringWithSubstitution(
+ STR_UNKNOWN_PARA_TYPE,
+ "$position$", OUString::number(parameterIndex)
+ ) );
+ ::dbtools::throwGenericSQLException(sError,*this);
+ }
+}
+
+void SAL_CALL OPreparedStatement::setShort( sal_Int32 parameterIndex, sal_Int16 x )
+{
+ setParameter(parameterIndex,adSmallInt,sizeof(x),x);
+}
+
+void SAL_CALL OPreparedStatement::setBytes( sal_Int32 parameterIndex, const Sequence< sal_Int8 >& x )
+{
+ setParameter(parameterIndex,adVarBinary,sizeof(sal_Int8)*x.getLength(),x);
+}
+
+void SAL_CALL OPreparedStatement::setCharacterStream( sal_Int32 /*parameterIndex*/, const Reference< css::io::XInputStream >& /*x*/, sal_Int32 /*length*/ )
+{
+ ::dbtools::throwFeatureNotImplementedSQLException( "XParameters::setCharacterStream", *this );
+}
+
+void SAL_CALL OPreparedStatement::setBinaryStream( sal_Int32 parameterIndex, const Reference< css::io::XInputStream >& x, sal_Int32 length )
+{
+ if(x.is())
+ {
+ Sequence< sal_Int8 > aData;
+ x->readBytes(aData,length);
+ setBytes(parameterIndex,aData);
+ }
+}
+
+void SAL_CALL OPreparedStatement::clearParameters( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OStatement_BASE::rBHelper.bDisposed);
+
+
+ if(m_pParameters)
+ {
+ sal_Int32 nCount = 0;
+ m_pParameters->get_Count(&nCount);
+ OLEVariant aVal;
+ aVal.setEmpty();
+ for(sal_Int32 i=0;i<nCount;++i)
+ {
+ WpADOParameter aParam;
+ m_pParameters->get_Item(OLEVariant(i),&aParam);
+ if(aParam)
+ {
+ CHECK_RETURN(aParam.PutValue(aVal));
+ }
+ }
+ }
+}
+
+void SAL_CALL OPreparedStatement::acquire() noexcept
+{
+ OStatement_Base::acquire();
+}
+
+void SAL_CALL OPreparedStatement::release() noexcept
+{
+ OStatement_Base::release();
+}
+
+void OPreparedStatement::replaceParameterNodeName(OSQLParseNode const * _pNode,
+ const OUString& _sDefaultName,
+ sal_Int32& _rParameterCount)
+{
+ sal_Int32 nCount = _pNode->count();
+ for(sal_Int32 i=0;i < nCount;++i)
+ {
+ OSQLParseNode* pChildNode = _pNode->getChild(i);
+ if(SQL_ISRULE(pChildNode,parameter) && pChildNode->count() == 1)
+ {
+ OSQLParseNode* pNewNode = new OSQLParseNode(OUString(":") ,SQLNodeType::Punctuation,0);
+ pChildNode->replaceAndDelete(pChildNode->getChild(0), pNewNode);
+ OUString sParameterName = _sDefaultName + OUString::number(++_rParameterCount);
+ pChildNode->append(new OSQLParseNode( sParameterName,SQLNodeType::Name,0));
+ }
+ else
+ replaceParameterNodeName(pChildNode,_sDefaultName,_rParameterCount);
+
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/ado/AResultSet.cxx b/connectivity/source/drivers/ado/AResultSet.cxx
new file mode 100644
index 0000000000..85ca2b081a
--- /dev/null
+++ b/connectivity/source/drivers/ado/AResultSet.cxx
@@ -0,0 +1,1158 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <ado/AResultSet.hxx>
+#include <ado/AResultSetMetaData.hxx>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <com/sun/star/sdbc/KeyRule.hpp>
+#include <com/sun/star/sdbc/IndexType.hpp>
+#include <com/sun/star/sdbcx/CompareBookmark.hpp>
+#include <comphelper/property.hxx>
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <com/sun/star/sdbc/ResultSetConcurrency.hpp>
+#include <com/sun/star/sdbc/ResultSetType.hpp>
+#include <com/sun/star/sdbc/FetchDirection.hpp>
+#include <cppuhelper/typeprovider.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <comphelper/sequence.hxx>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <comphelper/seqstream.hxx>
+#include <connectivity/dbexception.hxx>
+#include <connectivity/dbtools.hxx>
+#include <comphelper/types.hxx>
+
+using namespace ::comphelper;
+
+
+#include <oledb.h>
+
+#define CHECK_RETURN(x) \
+ if(!SUCCEEDED(x)) \
+ ADOS::ThrowException(m_pStmt->m_pConnection->getConnection(),*this);
+
+using namespace connectivity::ado;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::sdbc;
+
+
+// IMPLEMENT_SERVICE_INFO(OResultSet,"com.sun.star.sdbcx.AResultSet","com.sun.star.sdbc.ResultSet");
+OUString SAL_CALL OResultSet::getImplementationName( )
+{
+ return "com.sun.star.sdbcx.ado.ResultSet";
+}
+
+css::uno::Sequence< OUString > SAL_CALL OResultSet::getSupportedServiceNames( )
+{
+ return {"com.sun.star.sdbc.ResultSet","com.sun.star.sdbcx.ResultSet"};
+}
+
+sal_Bool SAL_CALL OResultSet::supportsService( const OUString& _rServiceName )
+{
+ return cppu::supportsService(this, _rServiceName);
+}
+
+OResultSet::OResultSet(ADORecordset* _pRecordSet,OStatement_Base* pStmt) : OResultSet_BASE(m_aMutex)
+ ,OPropertySetHelper(OResultSet_BASE::rBHelper)
+ ,m_pRecordSet(_pRecordSet)
+ ,m_pStmt(pStmt)
+ ,m_xStatement(*pStmt)
+ ,m_nRowPos(0)
+ ,m_bEOF(false)
+ ,m_bOnFirstAfterOpen(false)
+{
+}
+
+OResultSet::OResultSet(ADORecordset* _pRecordSet) : OResultSet_BASE(m_aMutex)
+ ,OPropertySetHelper(OResultSet_BASE::rBHelper)
+ ,m_pRecordSet(_pRecordSet)
+ ,m_pStmt(nullptr)
+ ,m_nRowPos(0)
+ ,m_bEOF(false)
+ ,m_bOnFirstAfterOpen(false)
+{
+}
+
+void OResultSet::construct()
+{
+ osl_atomic_increment( &m_refCount );
+ if (!m_pRecordSet)
+ {
+ OSL_FAIL( "OResultSet::construct: no RecordSet!" );
+ Reference< XInterface > xInt( *this );
+ osl_atomic_decrement( &m_refCount );
+ ::dbtools::throwFunctionSequenceException( xInt );
+ }
+ m_pRecordSet->AddRef();
+ VARIANT_BOOL bIsAtBOF;
+ CHECK_RETURN(m_pRecordSet->get_BOF(&bIsAtBOF))
+ m_bOnFirstAfterOpen = bIsAtBOF != VARIANT_TRUE;
+ osl_atomic_decrement( &m_refCount );
+}
+
+OResultSet::~OResultSet()
+{
+ if(m_pRecordSet)
+ m_pRecordSet->Release();
+}
+
+void OResultSet::disposing()
+{
+ OPropertySetHelper::disposing();
+
+ ::osl::MutexGuard aGuard(m_aMutex);
+ if(m_pRecordSet)
+ m_pRecordSet->Close();
+ m_xStatement.clear();
+ m_xMetaData.clear();
+}
+
+Any SAL_CALL OResultSet::queryInterface( const Type & rType )
+{
+ Any aRet = OPropertySetHelper::queryInterface(rType);
+ return aRet.hasValue() ? aRet : OResultSet_BASE::queryInterface(rType);
+}
+
+css::uno::Sequence< css::uno::Type > SAL_CALL OResultSet::getTypes( )
+{
+ ::cppu::OTypeCollection aTypes( cppu::UnoType<css::beans::XMultiPropertySet>::get(),
+ cppu::UnoType<css::beans::XFastPropertySet>::get(),
+ cppu::UnoType<css::beans::XPropertySet>::get());
+
+ return ::comphelper::concatSequences(aTypes.getTypes(),OResultSet_BASE::getTypes());
+}
+
+
+sal_Int32 SAL_CALL OResultSet::findColumn( const OUString& columnName )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+
+ Reference< XResultSetMetaData > xMeta = getMetaData();
+ sal_Int32 nLen = xMeta->getColumnCount();
+ sal_Int32 i = 1;
+ for(;i<=nLen;++i)
+ {
+ if(xMeta->isCaseSensitive(i) ? columnName == xMeta->getColumnName(i) :
+ columnName.equalsIgnoreAsciiCase(xMeta->getColumnName(i)))
+ return i;
+ }
+
+ ::dbtools::throwInvalidColumnException( columnName, *this );
+ assert(false);
+ return 0; // Never reached
+}
+#define BLOCK_SIZE 256
+
+Reference< css::io::XInputStream > SAL_CALL OResultSet::getBinaryStream( sal_Int32 columnIndex )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ WpADOField aField = ADOS::getField(m_pRecordSet,columnIndex);
+
+ if((aField.GetAttributes() & adFldLong) == adFldLong)
+ {
+ //Copy the data only up to the Actual Size of Field.
+ sal_Int32 nSize = aField.GetActualSize();
+ Sequence<sal_Int8> aData(nSize);
+ sal_Int32 index = 0;
+ while(index < nSize)
+ {
+ m_aValue = aField.GetChunk(BLOCK_SIZE);
+ if(m_aValue.isNull())
+ break;
+ UCHAR chData;
+ for(LONG index2 = 0;index2 < BLOCK_SIZE;++index2)
+ {
+ HRESULT hr = ::SafeArrayGetElement(m_aValue.parray,&index2,&chData);
+ if(SUCCEEDED(hr))
+ {
+ //Take BYTE by BYTE and advance Memory Location
+ aData.getArray()[index++] = chData;
+ }
+ else
+ break;
+ }
+ }
+
+ return new ::comphelper::SequenceInputStream(aData);
+ }
+ // else we ask for a bytesequence
+ aField.get_Value(m_aValue);
+
+ return m_aValue.isNull() ? nullptr : new ::comphelper::SequenceInputStream(m_aValue.getByteSequence());
+}
+
+Reference< css::io::XInputStream > SAL_CALL OResultSet::getCharacterStream( sal_Int32 /*columnIndex*/ )
+{
+ ::dbtools::throwFeatureNotImplementedSQLException( "XRow::getCharacterStream", *this );
+ return nullptr;
+}
+
+OLEVariant OResultSet::getValue(sal_Int32 columnIndex )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ WpADOField aField = ADOS::getField(m_pRecordSet,columnIndex);
+ aField.get_Value(m_aValue);
+ return m_aValue;
+}
+
+sal_Bool SAL_CALL OResultSet::getBoolean( sal_Int32 columnIndex )
+{
+ return getValue(columnIndex).getBool();
+}
+
+
+sal_Int8 SAL_CALL OResultSet::getByte( sal_Int32 columnIndex )
+{
+ return getValue(columnIndex).getInt8();
+}
+
+
+Sequence< sal_Int8 > SAL_CALL OResultSet::getBytes( sal_Int32 columnIndex )
+{
+ return getValue(columnIndex).getByteSequence();
+}
+
+
+css::util::Date SAL_CALL OResultSet::getDate( sal_Int32 columnIndex )
+{
+ return getValue(columnIndex).getDate();
+}
+
+
+double SAL_CALL OResultSet::getDouble( sal_Int32 columnIndex )
+{
+ return getValue(columnIndex).getDouble();
+}
+
+
+float SAL_CALL OResultSet::getFloat( sal_Int32 columnIndex )
+{
+ return getValue(columnIndex).getFloat();
+}
+
+
+sal_Int32 SAL_CALL OResultSet::getInt( sal_Int32 columnIndex )
+{
+ return getValue(columnIndex).getInt32();
+}
+
+
+sal_Int32 SAL_CALL OResultSet::getRow( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+
+ PositionEnum_Param aPos;
+ m_pRecordSet->get_AbsolutePosition(&aPos);
+ return (aPos > 0) ? static_cast<sal_Int32>(aPos) : m_nRowPos;
+ // return the rowcount from driver if the driver doesn't support this return our count
+}
+
+
+sal_Int64 SAL_CALL OResultSet::getLong( sal_Int32 /*columnIndex*/ )
+{
+ ::dbtools::throwFeatureNotImplementedSQLException( "XRow::getLong", *this );
+ return sal_Int64(0);
+}
+
+
+Reference< XResultSetMetaData > SAL_CALL OResultSet::getMetaData( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+
+ if(!m_xMetaData.is())
+ m_xMetaData = new OResultSetMetaData(m_pRecordSet);
+ return m_xMetaData;
+}
+
+Reference< XArray > SAL_CALL OResultSet::getArray( sal_Int32 /*columnIndex*/ )
+{
+ ::dbtools::throwFeatureNotImplementedSQLException( "XRow::getArray", *this );
+ return nullptr;
+}
+
+
+Reference< XClob > SAL_CALL OResultSet::getClob( sal_Int32 /*columnIndex*/ )
+{
+ ::dbtools::throwFeatureNotImplementedSQLException( "XRow::getClob", *this );
+ return nullptr;
+}
+
+Reference< XBlob > SAL_CALL OResultSet::getBlob( sal_Int32 /*columnIndex*/ )
+{
+ ::dbtools::throwFeatureNotImplementedSQLException( "XRow::getBlob", *this );
+ return nullptr;
+}
+
+
+Reference< XRef > SAL_CALL OResultSet::getRef( sal_Int32 /*columnIndex*/ )
+{
+ ::dbtools::throwFeatureNotImplementedSQLException( "XRow::getRef", *this );
+ return nullptr;
+}
+
+
+Any SAL_CALL OResultSet::getObject( sal_Int32 columnIndex, const Reference< css::container::XNameAccess >& /*typeMap*/ )
+{
+ return getValue(columnIndex).makeAny();
+}
+
+
+sal_Int16 SAL_CALL OResultSet::getShort( sal_Int32 columnIndex )
+{
+ return getValue(columnIndex).getInt16();
+}
+
+
+OUString SAL_CALL OResultSet::getString( sal_Int32 columnIndex )
+{
+ return getValue(columnIndex).getString();
+}
+
+
+css::util::Time SAL_CALL OResultSet::getTime( sal_Int32 columnIndex )
+{
+ return getValue(columnIndex).getTime();
+}
+
+
+css::util::DateTime SAL_CALL OResultSet::getTimestamp( sal_Int32 columnIndex )
+{
+ return getValue(columnIndex).getDateTime();
+}
+
+
+sal_Bool SAL_CALL OResultSet::isAfterLast( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+
+ VARIANT_BOOL bIsAtEOF;
+ CHECK_RETURN(m_pRecordSet->get_EOF(&bIsAtEOF))
+ return bIsAtEOF == VARIANT_TRUE;
+}
+
+sal_Bool SAL_CALL OResultSet::isFirst( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+
+ return m_nRowPos == 1;
+}
+
+sal_Bool SAL_CALL OResultSet::isLast( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+
+ return true;
+}
+
+void SAL_CALL OResultSet::beforeFirst( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+
+ if(first())
+ m_bOnFirstAfterOpen = !previous();
+}
+
+void SAL_CALL OResultSet::afterLast( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+
+ if(last())
+ next();
+ m_bEOF = true;
+}
+
+
+void SAL_CALL OResultSet::close( )
+{
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ }
+ dispose();
+}
+
+
+sal_Bool SAL_CALL OResultSet::first( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+
+ if(SUCCEEDED(m_pRecordSet->MoveFirst()))
+ {
+ m_nRowPos = 1;
+ m_bOnFirstAfterOpen = false;
+ return true;
+ }
+ return false;
+}
+
+
+sal_Bool SAL_CALL OResultSet::last( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+
+ bool bRet = SUCCEEDED(m_pRecordSet->MoveLast());
+ if(bRet)
+ {
+ m_pRecordSet->get_RecordCount(&m_nRowPos);
+ m_bOnFirstAfterOpen = false;
+ }
+ return bRet;
+}
+
+sal_Bool SAL_CALL OResultSet::absolute( sal_Int32 row )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+
+ if(!row) // absolute with zero not allowed
+ ::dbtools::throwFunctionSequenceException(*this);
+
+ bool bCheck = true;
+ if(row < 0)
+ {
+ bCheck = SUCCEEDED(m_pRecordSet->MoveLast());
+ if ( bCheck )
+ {
+ while(++row < 0 && bCheck)
+ bCheck = SUCCEEDED(m_pRecordSet->MovePrevious());
+ }
+ }
+ else
+ {
+ first();
+ OLEVariant aEmpty;
+ aEmpty.setNoArg();
+ bCheck = SUCCEEDED(m_pRecordSet->Move(row-1,aEmpty)); // move to row -1 because we stand already on the first
+ if(bCheck)
+ m_nRowPos = row;
+ }
+ if(bCheck)
+ m_bOnFirstAfterOpen = false;
+ return bCheck;
+}
+
+sal_Bool SAL_CALL OResultSet::relative( sal_Int32 row )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+
+ OLEVariant aEmpty;
+ aEmpty.setNoArg();
+ sal_Int32 nNewPos = row;
+ if ( m_bOnFirstAfterOpen && nNewPos > 0 )
+ --nNewPos;
+ bool bRet = SUCCEEDED(m_pRecordSet->Move(row,aEmpty));
+ if(bRet)
+ {
+ m_nRowPos += row;
+ m_bOnFirstAfterOpen = false;
+ }
+ return bRet;
+}
+
+sal_Bool SAL_CALL OResultSet::previous( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ bool bRet = SUCCEEDED(m_pRecordSet->MovePrevious());
+ if(bRet)
+ {
+ --m_nRowPos;
+ m_bOnFirstAfterOpen = false;
+ }
+ return bRet;
+}
+
+Reference< XInterface > SAL_CALL OResultSet::getStatement( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+ return m_xStatement;
+}
+
+
+sal_Bool SAL_CALL OResultSet::rowDeleted( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+
+ sal_Int32 eRec;
+ m_pRecordSet->get_Status(&eRec);
+ bool bRet = (RecordStatusEnum(eRec) & adRecDeleted) == adRecDeleted;
+ if(bRet)
+ --m_nRowPos;
+ return bRet;
+}
+
+sal_Bool SAL_CALL OResultSet::rowInserted( )
+{ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+
+ sal_Int32 eRec;
+ m_pRecordSet->get_Status(&eRec);
+ bool bRet = (RecordStatusEnum(eRec) & adRecNew) == adRecNew;
+ if(bRet)
+ ++m_nRowPos;
+ return bRet;
+}
+
+sal_Bool SAL_CALL OResultSet::rowUpdated( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+
+ sal_Int32 eRec;
+ m_pRecordSet->get_Status(&eRec);
+ return (RecordStatusEnum(eRec) & adRecModified) == adRecModified;
+}
+
+
+sal_Bool SAL_CALL OResultSet::isBeforeFirst( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+
+ OSL_ENSURE(!m_nRowPos,"OResultSet::isBeforeFirst: Error in setting m_nRowPos!");
+ VARIANT_BOOL bIsAtBOF = VARIANT_TRUE;
+ if(!m_bOnFirstAfterOpen)
+ {
+ OSL_ENSURE(!m_nRowPos,"OResultSet::isBeforeFirst: Error in setting m_nRowPos!");
+ m_pRecordSet->get_BOF(&bIsAtBOF);
+ }
+ return bIsAtBOF == VARIANT_TRUE;
+}
+
+
+sal_Bool SAL_CALL OResultSet::next( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+
+ bool bRet = true;
+ if(m_bOnFirstAfterOpen)
+ {
+ m_bOnFirstAfterOpen = false;
+ ++m_nRowPos;
+ }
+ else
+ {
+ bRet = SUCCEEDED(m_pRecordSet->MoveNext());
+
+ if(bRet)
+ {
+ VARIANT_BOOL bIsAtEOF;
+ CHECK_RETURN(m_pRecordSet->get_EOF(&bIsAtEOF))
+ bRet = bIsAtEOF != VARIANT_TRUE;
+ ++m_nRowPos;
+ }
+ else
+ ADOS::ThrowException(m_pStmt->m_pConnection->getConnection(),*this);
+ }
+
+ return bRet;
+}
+
+
+sal_Bool SAL_CALL OResultSet::wasNull( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+
+ return m_aValue.isNull();
+}
+
+
+void SAL_CALL OResultSet::cancel( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+
+ m_pRecordSet->Cancel();
+}
+
+void SAL_CALL OResultSet::clearWarnings( )
+{
+}
+
+Any SAL_CALL OResultSet::getWarnings( )
+{
+ return Any();
+}
+
+void SAL_CALL OResultSet::insertRow( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+
+ OLEVariant aEmpty;
+ aEmpty.setNoArg();
+ m_pRecordSet->AddNew(aEmpty,aEmpty);
+}
+
+void SAL_CALL OResultSet::updateRow( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+
+ OLEVariant aEmpty;
+ aEmpty.setNoArg();
+ m_pRecordSet->Update(aEmpty,aEmpty);
+}
+
+void SAL_CALL OResultSet::deleteRow( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+
+ m_pRecordSet->Delete();
+ m_pRecordSet->UpdateBatch(adAffectCurrent);
+}
+
+
+void SAL_CALL OResultSet::cancelRowUpdates( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+
+ m_pRecordSet->CancelUpdate();
+}
+
+
+void SAL_CALL OResultSet::moveToInsertRow( )
+{
+ // ::osl::MutexGuard aGuard( m_aMutex );
+ //checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+ // if ( getResultSetConcurrency() == ResultSetConcurrency::READ_ONLY )
+ // throw SQLException();
+}
+
+
+void SAL_CALL OResultSet::moveToCurrentRow( )
+{
+}
+
+void OResultSet::updateValue(sal_Int32 columnIndex,const OLEVariant& x)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ WpADOField aField = ADOS::getField(m_pRecordSet,columnIndex);
+ aField.PutValue(x);
+}
+
+void SAL_CALL OResultSet::updateNull( sal_Int32 columnIndex )
+{
+ OLEVariant x;
+ x.setNull();
+ updateValue(columnIndex,x);
+}
+
+
+void SAL_CALL OResultSet::updateBoolean( sal_Int32 columnIndex, sal_Bool x )
+{
+ updateValue(columnIndex,bool(x));
+}
+
+void SAL_CALL OResultSet::updateByte( sal_Int32 columnIndex, sal_Int8 x )
+{
+ updateValue(columnIndex,x);
+}
+
+
+void SAL_CALL OResultSet::updateShort( sal_Int32 columnIndex, sal_Int16 x )
+{
+ updateValue(columnIndex,x);
+}
+
+void SAL_CALL OResultSet::updateInt( sal_Int32 columnIndex, sal_Int32 x )
+{
+ updateValue(columnIndex,x);
+}
+
+void SAL_CALL OResultSet::updateLong( sal_Int32 columnIndex, sal_Int64 x )
+{
+ updateValue(columnIndex,x);
+}
+
+void SAL_CALL OResultSet::updateFloat( sal_Int32 columnIndex, float x )
+{
+ updateValue(columnIndex,x);
+}
+
+
+void SAL_CALL OResultSet::updateDouble( sal_Int32 columnIndex, double x )
+{
+ updateValue(columnIndex,x);
+}
+
+void SAL_CALL OResultSet::updateString( sal_Int32 columnIndex, const OUString& x )
+{
+ updateValue(columnIndex,x);
+}
+
+void SAL_CALL OResultSet::updateBytes( sal_Int32 columnIndex, const Sequence< sal_Int8 >& x )
+{
+ updateValue(columnIndex,x);
+}
+
+void SAL_CALL OResultSet::updateDate( sal_Int32 columnIndex, const css::util::Date& x )
+{
+ updateValue(columnIndex,x);
+}
+
+
+void SAL_CALL OResultSet::updateTime( sal_Int32 columnIndex, const css::util::Time& x )
+{
+ updateValue(columnIndex,x);
+}
+
+
+void SAL_CALL OResultSet::updateTimestamp( sal_Int32 columnIndex, const css::util::DateTime& x )
+{
+ updateValue(columnIndex,x);
+}
+
+
+void SAL_CALL OResultSet::updateBinaryStream( sal_Int32 columnIndex, const Reference< css::io::XInputStream >& x, sal_Int32 length )
+{
+ if(!x.is())
+ ::dbtools::throwFunctionSequenceException(*this);
+
+ Sequence<sal_Int8> aSeq;
+ x->readBytes(aSeq,length);
+ updateBytes(columnIndex,aSeq);
+}
+
+void SAL_CALL OResultSet::updateCharacterStream( sal_Int32 columnIndex, const Reference< css::io::XInputStream >& x, sal_Int32 length )
+{
+ if(!x.is())
+ ::dbtools::throwFunctionSequenceException(*this);
+
+ Sequence<sal_Int8> aSeq;
+ x->readBytes(aSeq,length);
+ updateBytes(columnIndex,aSeq);
+}
+
+void SAL_CALL OResultSet::refreshRow( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+
+ m_pRecordSet->Resync(adAffectCurrent);
+}
+
+void SAL_CALL OResultSet::updateObject( sal_Int32 columnIndex, const Any& x )
+{
+ if (!::dbtools::implUpdateObject(this, columnIndex, x))
+ throw SQLException();
+}
+
+
+void SAL_CALL OResultSet::updateNumericObject( sal_Int32 columnIndex, const Any& x, sal_Int32 /*scale*/ )
+{
+ if (!::dbtools::implUpdateObject(this, columnIndex, x))
+ throw SQLException();
+}
+
+// XRowLocate
+Any SAL_CALL OResultSet::getBookmark( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ if(m_nRowPos < static_cast<sal_Int32>(m_aBookmarks.size())) // this bookmark was already fetched
+ return Any(sal_Int32(m_nRowPos-1));
+
+ OLEVariant aVar;
+ m_pRecordSet->get_Bookmark(&aVar);
+ m_aBookmarks.push_back(aVar);
+ return Any(static_cast<sal_Int32>(m_aBookmarks.size()-1));
+
+}
+
+sal_Bool SAL_CALL OResultSet::moveToBookmark( const Any& bookmark )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+
+ sal_Int32 nPos = 0;
+ bookmark >>= nPos;
+ OSL_ENSURE(nPos >= 0 && nPos < static_cast<sal_Int32>(m_aBookmarks.size()),"Invalid Index for vector");
+ if(nPos < 0 || nPos >= static_cast<sal_Int32>(m_aBookmarks.size()))
+ ::dbtools::throwFunctionSequenceException(*this);
+
+ return SUCCEEDED(m_pRecordSet->Move(0,m_aBookmarks[nPos]));
+}
+
+sal_Bool SAL_CALL OResultSet::moveRelativeToBookmark( const Any& bookmark, sal_Int32 rows )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+
+ sal_Int32 nPos = 0;
+ bookmark >>= nPos;
+ nPos += rows;
+ OSL_ENSURE(nPos >= 0 && nPos < static_cast<sal_Int32>(m_aBookmarks.size()),"Invalid Index for vector");
+ if(nPos < 0 || nPos >= static_cast<sal_Int32>(m_aBookmarks.size()))
+ ::dbtools::throwFunctionSequenceException(*this);
+ return SUCCEEDED(m_pRecordSet->Move(rows,m_aBookmarks[nPos]));
+}
+
+sal_Int32 SAL_CALL OResultSet::compareBookmarks( const Any& bookmark1, const Any& bookmark2 )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ sal_Int32 nPos1 = 0;
+ bookmark1 >>= nPos1;
+ sal_Int32 nPos2 = 0;
+ bookmark2 >>= nPos2;
+ if(nPos1 == nPos2) // they should be equal
+ return css::sdbcx::CompareBookmark::EQUAL;
+
+ OSL_ENSURE((nPos1 >= 0 && nPos1 < static_cast<sal_Int32>(m_aBookmarks.size())) || (nPos1 >= 0 && nPos2 < static_cast<sal_Int32>(m_aBookmarks.size())),"Invalid Index for vector");
+
+ CompareEnum eNum;
+ m_pRecordSet->CompareBookmarks(m_aBookmarks[nPos1],m_aBookmarks[nPos2],&eNum);
+ return static_cast<sal_Int32>(eNum) - 1;
+}
+
+sal_Bool SAL_CALL OResultSet::hasOrderedBookmarks( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+
+ WpADOProperties aProps;
+ m_pRecordSet->get_Properties(&aProps);
+ ADOS::ThrowException(static_cast<OConnection*>(m_pStmt->getConnection().get())->getConnection(),*this);
+ OSL_ENSURE(aProps.IsValid(),"There are no properties at the connection");
+
+ WpADOProperty aProp(aProps.GetItem(OUString("Bookmarks Ordered")));
+ OLEVariant aVar;
+ if(aProp.IsValid())
+ aVar = aProp.GetValue();
+ else
+ ADOS::ThrowException(static_cast<OConnection*>(m_pStmt->getConnection().get())->getConnection(),*this);
+
+ bool bValue(false);
+ if(!aVar.isNull() && !aVar.isEmpty())
+ bValue = aVar.getBool();
+ return bValue;
+}
+
+sal_Int32 SAL_CALL OResultSet::hashBookmark( const Any& bookmark )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+
+ sal_Int32 nPos = 0;
+ bookmark >>= nPos;
+ return nPos;
+}
+
+// XDeleteRows
+Sequence< sal_Int32 > SAL_CALL OResultSet::deleteRows( const Sequence< Any >& rows )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+
+ OLEVariant aVar;
+ sal_Int32 nPos = 0;
+
+ // Create SafeArray Bounds and initialize the array
+ SAFEARRAYBOUND rgsabound[1];
+ rgsabound[0].lLbound = 0;
+ rgsabound[0].cElements = rows.getLength();
+ SAFEARRAY *psa = SafeArrayCreate( VT_VARIANT, 1, rgsabound );
+
+ const Any* pBegin = rows.getConstArray();
+ const Any* pEnd = pBegin + rows.getLength();
+ for(sal_Int32 i=0;pBegin != pEnd ;++pBegin,++i)
+ {
+ *pBegin >>= nPos;
+ SafeArrayPutElement(psa,&i,&m_aBookmarks[nPos]);
+ }
+
+ // Initialize and fill the SafeArray
+ OLEVariant vsa;
+ vsa.setArray(psa,VT_VARIANT);
+
+ m_pRecordSet->put_Filter(vsa);
+ m_pRecordSet->Delete(adAffectGroup);
+ m_pRecordSet->UpdateBatch(adAffectGroup);
+
+ Sequence< sal_Int32 > aSeq(rows.getLength());
+ if(first())
+ {
+ sal_Int32* pSeq = aSeq.getArray();
+ sal_Int32 i=0;
+ do
+ {
+ OSL_ENSURE(i<aSeq.getLength(),"Index greater than length of sequence");
+ m_pRecordSet->get_Status(&pSeq[i]);
+ if(pSeq[i++] == adRecDeleted)
+ --m_nRowPos;
+ }
+ while(next());
+ }
+ return aSeq;
+}
+
+sal_Int32 OResultSet::getResultSetConcurrency() const
+{
+ sal_Int32 nValue=ResultSetConcurrency::READ_ONLY;
+ LockTypeEnum eRet;
+ if(!SUCCEEDED(m_pRecordSet->get_LockType(&eRet)))
+ {
+ switch(eRet)
+ {
+ case adLockReadOnly:
+ nValue = ResultSetConcurrency::READ_ONLY;
+ break;
+ default:
+ nValue = ResultSetConcurrency::UPDATABLE;
+ break;
+ }
+ }
+ return nValue;
+}
+
+sal_Int32 OResultSet::getResultSetType() const
+{
+ sal_Int32 nValue=0;
+ CursorTypeEnum eRet;
+ if(!SUCCEEDED(m_pRecordSet->get_CursorType(&eRet)))
+ {
+ switch(eRet)
+ {
+ case adOpenUnspecified:
+ case adOpenForwardOnly:
+ nValue = ResultSetType::FORWARD_ONLY;
+ break;
+ case adOpenStatic:
+ case adOpenKeyset:
+ nValue = ResultSetType::SCROLL_INSENSITIVE;
+ break;
+ case adOpenDynamic:
+ nValue = ResultSetType::SCROLL_SENSITIVE;
+ break;
+ }
+ }
+ return nValue;
+}
+
+sal_Int32 OResultSet::getFetchDirection()
+{
+ return FetchDirection::FORWARD;
+}
+
+sal_Int32 OResultSet::getFetchSize() const
+{
+ sal_Int32 nValue=-1;
+ m_pRecordSet->get_CacheSize(&nValue);
+ return nValue;
+}
+
+OUString OResultSet::getCursorName()
+{
+ return OUString();
+}
+
+
+void OResultSet::setFetchDirection(sal_Int32 /*_par0*/)
+{
+ ::dbtools::throwFeatureNotImplementedSQLException( "ResultSet::FetchDirection", *this );
+}
+
+void OResultSet::setFetchSize(sal_Int32 _par0)
+{
+ m_pRecordSet->put_CacheSize(_par0);
+}
+
+::cppu::IPropertyArrayHelper* OResultSet::createArrayHelper( ) const
+{
+ return new ::cppu::OPropertyArrayHelper
+ {
+ {
+ {
+ ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHDIRECTION),
+ PROPERTY_ID_FETCHDIRECTION, cppu::UnoType<sal_Int32>::get(), 0
+ },
+ {
+ ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHSIZE),
+ PROPERTY_ID_FETCHSIZE, cppu::UnoType<sal_Int32>::get(), 0
+ },
+ {
+ ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISBOOKMARKABLE),
+ PROPERTY_ID_ISBOOKMARKABLE, cppu::UnoType<bool>::get(), PropertyAttribute::READONLY
+ },
+ {
+ ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETCONCURRENCY),
+ PROPERTY_ID_RESULTSETCONCURRENCY, cppu::UnoType<sal_Int32>::get(), PropertyAttribute::READONLY
+ },
+ {
+ ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETTYPE),
+ PROPERTY_ID_RESULTSETTYPE, cppu::UnoType<sal_Int32>::get(), PropertyAttribute::READONLY
+ }
+ }
+ };
+}
+
+::cppu::IPropertyArrayHelper & OResultSet::getInfoHelper()
+{
+ return *getArrayHelper();
+}
+
+sal_Bool OResultSet::convertFastPropertyValue(
+ Any & rConvertedValue,
+ Any & rOldValue,
+ sal_Int32 nHandle,
+ const Any& rValue )
+{
+ switch(nHandle)
+ {
+ case PROPERTY_ID_ISBOOKMARKABLE:
+ case PROPERTY_ID_CURSORNAME:
+ case PROPERTY_ID_RESULTSETCONCURRENCY:
+ case PROPERTY_ID_RESULTSETTYPE:
+ throw css::lang::IllegalArgumentException();
+ break;
+ case PROPERTY_ID_FETCHDIRECTION:
+ return ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, getFetchDirection());
+ case PROPERTY_ID_FETCHSIZE:
+ return ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, getFetchSize());
+ default:
+ ;
+ }
+ return false;
+}
+
+void OResultSet::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,const Any& rValue)
+{
+ switch(nHandle)
+ {
+ case PROPERTY_ID_ISBOOKMARKABLE:
+ case PROPERTY_ID_CURSORNAME:
+ case PROPERTY_ID_RESULTSETCONCURRENCY:
+ case PROPERTY_ID_RESULTSETTYPE:
+ throw Exception("cannot set prop " + OUString::number(nHandle), nullptr);
+ break;
+ case PROPERTY_ID_FETCHDIRECTION:
+ setFetchDirection(getINT32(rValue));
+ break;
+ case PROPERTY_ID_FETCHSIZE:
+ setFetchSize(getINT32(rValue));
+ break;
+ default:
+ ;
+ }
+}
+
+void OResultSet::getFastPropertyValue(Any& rValue,sal_Int32 nHandle) const
+{
+ switch(nHandle)
+ {
+ case PROPERTY_ID_ISBOOKMARKABLE:
+ {
+ VARIANT_BOOL bBool;
+ m_pRecordSet->Supports(adBookmark,&bBool);
+ rValue <<= (bBool == VARIANT_TRUE);
+ }
+ break;
+ case PROPERTY_ID_CURSORNAME:
+ rValue <<= getCursorName();
+ break;
+ case PROPERTY_ID_RESULTSETCONCURRENCY:
+ rValue <<= getResultSetConcurrency();
+ break;
+ case PROPERTY_ID_RESULTSETTYPE:
+ rValue <<= getResultSetType();
+ break;
+ case PROPERTY_ID_FETCHDIRECTION:
+ rValue <<= getFetchDirection();
+ break;
+ case PROPERTY_ID_FETCHSIZE:
+ rValue <<= getFetchSize();
+ break;
+ }
+}
+
+void SAL_CALL OResultSet::acquire() noexcept
+{
+ OResultSet_BASE::acquire();
+}
+
+void SAL_CALL OResultSet::release() noexcept
+{
+ OResultSet_BASE::release();
+}
+
+css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL OResultSet::getPropertySetInfo( )
+{
+ return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper());
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/ado/AResultSetMetaData.cxx b/connectivity/source/drivers/ado/AResultSetMetaData.cxx
new file mode 100644
index 0000000000..d43ee5da92
--- /dev/null
+++ b/connectivity/source/drivers/ado/AResultSetMetaData.cxx
@@ -0,0 +1,247 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <string_view>
+
+#include <ado/AResultSetMetaData.hxx>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <com/sun/star/sdbc/ColumnValue.hpp>
+#include <ado/Awrapado.hxx>
+#include <connectivity/dbexception.hxx>
+
+using namespace connectivity;
+using namespace connectivity::ado;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::sdbc;
+
+OResultSetMetaData::OResultSetMetaData( ADORecordset* _pRecordSet)
+ : m_pRecordSet(_pRecordSet),
+ m_nColCount(-1)
+{
+ if ( m_pRecordSet )
+ m_pRecordSet->AddRef();
+}
+
+OResultSetMetaData::~OResultSetMetaData()
+{
+ if ( m_pRecordSet )
+ m_pRecordSet->Release();
+}
+
+sal_Int32 SAL_CALL OResultSetMetaData::getColumnDisplaySize( sal_Int32 column )
+{
+ WpADOField aField = ADOS::getField(m_pRecordSet,column);
+ if(aField.IsValid() && aField.GetActualSize() != -1)
+ return aField.GetActualSize();
+ return 0;
+}
+
+
+sal_Int32 SAL_CALL OResultSetMetaData::getColumnType( sal_Int32 column )
+{
+ WpADOField aField = ADOS::getField(m_pRecordSet,column);
+ return ADOS::MapADOType2Jdbc(aField.GetADOType());
+}
+
+
+sal_Int32 SAL_CALL OResultSetMetaData::getColumnCount( )
+{
+ if(m_nColCount != -1 )
+ return m_nColCount;
+
+ if ( !m_pRecordSet )
+ return 0;
+
+ WpOLEAppendCollection<ADOFields, WpADOField> pFields;
+ m_pRecordSet->get_Fields(&pFields);
+ m_nColCount = pFields.GetItemCount();
+ return m_nColCount;
+}
+
+
+sal_Bool SAL_CALL OResultSetMetaData::isCaseSensitive( sal_Int32 column )
+{
+ bool bRet = false;
+ WpADOField aField = ADOS::getField(m_pRecordSet,column);
+ if ( aField.IsValid() )
+ {
+ WpADOProperties aProps( aField.get_Properties() );
+ if ( aProps.IsValid() )
+ bRet = OTools::getValue(aProps, std::u16string_view(u"ISCASESENSITIVE")).getBool();
+ }
+ return bRet;
+}
+
+
+OUString SAL_CALL OResultSetMetaData::getSchemaName( sal_Int32 /*column*/ )
+{
+ return OUString();
+}
+
+
+OUString SAL_CALL OResultSetMetaData::getColumnName( sal_Int32 column )
+{
+ WpADOField aField = ADOS::getField(m_pRecordSet,column);
+ if(aField.IsValid())
+ return aField.GetName();
+
+ return OUString();
+}
+
+OUString SAL_CALL OResultSetMetaData::getTableName( sal_Int32 column )
+{
+ OUString sTableName;
+
+ WpADOField aField = ADOS::getField(m_pRecordSet,column);
+ if ( aField.IsValid() )
+ {
+ WpADOProperties aProps( aField.get_Properties() );
+ if ( aProps.IsValid() )
+ sTableName
+ = OTools::getValue(aProps, std::u16string_view(u"BASETABLENAME")).getString();
+ }
+ return sTableName;
+}
+
+OUString SAL_CALL OResultSetMetaData::getCatalogName( sal_Int32 /*column*/ )
+{
+ return OUString();
+}
+
+OUString SAL_CALL OResultSetMetaData::getColumnTypeName( sal_Int32 /*column*/ )
+{
+ return OUString();
+}
+
+OUString SAL_CALL OResultSetMetaData::getColumnLabel( sal_Int32 column )
+{
+ return getColumnName(column);
+}
+
+OUString SAL_CALL OResultSetMetaData::getColumnServiceName( sal_Int32 /*column*/ )
+{
+ return OUString();
+}
+
+
+sal_Bool SAL_CALL OResultSetMetaData::isCurrency( sal_Int32 column )
+{
+ WpADOField aField = ADOS::getField(m_pRecordSet,column);
+ if(aField.IsValid())
+ {
+ return ((aField.GetAttributes() & adFldFixed) == adFldFixed) && (aField.GetADOType() == adCurrency);
+ }
+ return false;
+}
+
+
+sal_Bool SAL_CALL OResultSetMetaData::isAutoIncrement( sal_Int32 column )
+{
+ bool bRet = false;
+ WpADOField aField = ADOS::getField(m_pRecordSet,column);
+ if ( aField.IsValid() )
+ {
+ WpADOProperties aProps( aField.get_Properties() );
+ if ( aProps.IsValid() )
+ {
+ bRet = OTools::getValue(aProps, std::u16string_view(u"ISAUTOINCREMENT")).getBool();
+ }
+ }
+ return bRet;
+}
+
+
+sal_Bool SAL_CALL OResultSetMetaData::isSigned( sal_Int32 column )
+{
+ WpADOField aField = ADOS::getField(m_pRecordSet,column);
+ if(aField.IsValid())
+ {
+ DataTypeEnum eType = aField.GetADOType();
+ return !(eType == adUnsignedBigInt || eType == adUnsignedInt || eType == adUnsignedSmallInt || eType == adUnsignedTinyInt);
+ }
+ return false;
+}
+
+sal_Int32 SAL_CALL OResultSetMetaData::getPrecision( sal_Int32 column )
+{
+ WpADOField aField = ADOS::getField(m_pRecordSet,column);
+ if(aField.IsValid())
+ return aField.GetPrecision();
+ return 0;
+}
+
+sal_Int32 SAL_CALL OResultSetMetaData::getScale( sal_Int32 column )
+{
+ WpADOField aField = ADOS::getField(m_pRecordSet,column);
+ if(aField.IsValid())
+ return aField.GetNumericScale();
+ return 0;
+}
+
+
+sal_Int32 SAL_CALL OResultSetMetaData::isNullable( sal_Int32 column )
+{
+ WpADOField aField = ADOS::getField(m_pRecordSet,column);
+ if(aField.IsValid())
+ {
+ return sal_Int32((aField.GetAttributes() & adFldIsNullable) == adFldIsNullable);
+ }
+ return sal_Int32(false);
+}
+
+
+sal_Bool SAL_CALL OResultSetMetaData::isSearchable( sal_Int32 /*column*/ )
+{
+ return true;
+}
+
+
+sal_Bool SAL_CALL OResultSetMetaData::isReadOnly( sal_Int32 column )
+{
+ WpADOField aField = ADOS::getField(m_pRecordSet,column);
+ if(aField.IsValid())
+ {
+ // return (aField.GetStatus() & adFieldReadOnly) == adFieldReadOnly;
+ }
+ return false;
+}
+
+
+sal_Bool SAL_CALL OResultSetMetaData::isDefinitelyWritable( sal_Int32 column )
+{
+ WpADOField aField = ADOS::getField(m_pRecordSet,column);
+ if(aField.IsValid())
+ {
+ return (aField.GetAttributes() & adFldUpdatable) == adFldUpdatable;
+ }
+ return false;
+;
+}
+
+sal_Bool SAL_CALL OResultSetMetaData::isWritable( sal_Int32 column )
+{
+ return isDefinitelyWritable(column);
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/ado/AStatement.cxx b/connectivity/source/drivers/ado/AStatement.cxx
new file mode 100644
index 0000000000..c2a09385de
--- /dev/null
+++ b/connectivity/source/drivers/ado/AStatement.cxx
@@ -0,0 +1,867 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <ado/AStatement.hxx>
+#include <ado/AConnection.hxx>
+#include <ado/AResultSet.hxx>
+#include <comphelper/property.hxx>
+#include <osl/thread.h>
+#include <cppuhelper/typeprovider.hxx>
+#include <cppuhelper/queryinterface.hxx>
+#include <comphelper/sequence.hxx>
+#include <com/sun/star/sdbc/ResultSetConcurrency.hpp>
+#include <com/sun/star/sdbc/ResultSetType.hpp>
+#include <com/sun/star/sdbc/FetchDirection.hpp>
+#include <connectivity/dbexception.hxx>
+#include <comphelper/types.hxx>
+#include <rtl/ref.hxx>
+
+#undef max
+
+#include <algorithm>
+#include <numeric>
+
+using namespace ::comphelper;
+
+#define CHECK_RETURN(x) \
+ if(!x) \
+ ADOS::ThrowException(m_pConnection->getConnection(),*this);
+
+
+using namespace connectivity::ado;
+
+
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::sdbc;
+
+OStatement_Base::OStatement_Base(OConnection* _pConnection ) : OStatement_BASE(m_aMutex)
+ ,OPropertySetHelper(OStatement_BASE::rBHelper)
+ ,m_pConnection(_pConnection)
+ ,m_nMaxRows(0)
+ ,m_nFetchSize(1)
+ ,m_eLockType(adLockReadOnly)
+ ,m_eCursorType(adOpenForwardOnly)
+{
+ osl_atomic_increment( &m_refCount );
+
+ m_Command.Create();
+ if(m_Command.IsValid())
+ m_Command.putref_ActiveConnection(m_pConnection->getConnection());
+ else
+ ADOS::ThrowException(m_pConnection->getConnection(),*this);
+
+ m_RecordsAffected.setNoArg();
+ m_Parameters.setNoArg();
+
+ m_pConnection->acquire();
+
+ osl_atomic_decrement( &m_refCount );
+}
+
+void OStatement_Base::disposeResultSet()
+{
+ // free the cursor if alive
+ Reference< XComponent > xComp(m_xResultSet.get(), UNO_QUERY);
+ if (xComp.is())
+ xComp->dispose();
+ m_xResultSet.clear();
+}
+
+
+void OStatement_Base::disposing()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+
+
+ disposeResultSet();
+
+ if ( m_Command.IsValid() )
+ m_Command.putref_ActiveConnection({});
+ m_Command.clear();
+
+ if ( m_RecordSet.IsValid() )
+ m_RecordSet.PutRefDataSource( nullptr );
+ m_RecordSet.clear();
+
+ if (m_pConnection)
+ m_pConnection->release();
+
+ OStatement_BASE::disposing();
+}
+
+void SAL_CALL OStatement_Base::release() noexcept
+{
+ OStatement_BASE::release();
+}
+
+Any SAL_CALL OStatement_Base::queryInterface( const Type & rType )
+{
+ Any aRet = OStatement_BASE::queryInterface(rType);
+ return aRet.hasValue() ? aRet : OPropertySetHelper::queryInterface(rType);
+}
+
+css::uno::Sequence< css::uno::Type > SAL_CALL OStatement_Base::getTypes( )
+{
+ ::cppu::OTypeCollection aTypes( cppu::UnoType<css::beans::XMultiPropertySet>::get(),
+ cppu::UnoType<css::beans::XFastPropertySet>::get(),
+ cppu::UnoType<css::beans::XPropertySet>::get());
+
+ return ::comphelper::concatSequences(aTypes.getTypes(),OStatement_BASE::getTypes());
+}
+
+
+void SAL_CALL OStatement_Base::cancel( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OStatement_BASE::rBHelper.bDisposed);
+
+
+ CHECK_RETURN(m_Command.Cancel())
+}
+
+
+void SAL_CALL OStatement_Base::close( )
+{
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OStatement_BASE::rBHelper.bDisposed);
+
+ }
+ dispose();
+}
+
+
+void SAL_CALL OStatement::clearBatch( )
+{
+
+}
+
+
+void OStatement_Base::reset()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OStatement_BASE::rBHelper.bDisposed);
+
+
+ clearWarnings ();
+
+ if (m_xResultSet.get().is())
+ clearMyResultSet();
+}
+
+// clearMyResultSet
+// If a ResultSet was created for this Statement, close it
+
+
+void OStatement_Base::clearMyResultSet ()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OStatement_BASE::rBHelper.bDisposed);
+
+ try
+ {
+ Reference<XCloseable> xCloseable(
+ m_xResultSet.get(), css::uno::UNO_QUERY);
+ if ( xCloseable.is() )
+ xCloseable->close();
+ }
+ catch( const DisposedException& ) { }
+
+ m_xResultSet.clear();
+}
+
+sal_Int32 OStatement_Base::getRowCount ()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OStatement_BASE::rBHelper.bDisposed);
+
+
+ return m_RecordsAffected.getInt32();
+}
+
+// getPrecision
+// Given a SQL type, return the maximum precision for the column.
+// Returns -1 if not known
+
+
+sal_Int32 OStatement_Base::getPrecision ( sal_Int32 sqlType)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OStatement_BASE::rBHelper.bDisposed);
+
+
+ sal_Int32 prec = -1;
+ OTypeInfo aInfo;
+ aInfo.nType = static_cast<sal_Int16>(sqlType);
+ if (!m_aTypeInfo.empty())
+ {
+ std::vector<OTypeInfo>::const_iterator aIter = std::find(m_aTypeInfo.begin(),m_aTypeInfo.end(),aInfo);
+ for(;aIter != m_aTypeInfo.end();++aIter)
+ {
+ prec = std::max(prec,(*aIter).nPrecision);
+ }
+ }
+
+ return prec;
+}
+
+// setWarning
+// Sets the warning
+
+
+void OStatement_Base::setWarning (const SQLWarning &ex)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OStatement_BASE::rBHelper.bDisposed);
+
+
+ m_aLastWarning = ex;
+}
+
+void OStatement_Base::assignRecordSet( ADORecordset* _pRS )
+{
+ WpADORecordset aOldRS( m_RecordSet );
+ m_RecordSet.set( _pRS );
+
+ if ( aOldRS.IsValid() )
+ aOldRS.PutRefDataSource( nullptr );
+
+ if ( m_RecordSet.IsValid() )
+ m_RecordSet.PutRefDataSource( static_cast<IDispatch*>(m_Command) );
+}
+
+sal_Bool SAL_CALL OStatement_Base::execute( const OUString& sql )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OStatement_BASE::rBHelper.bDisposed);
+
+
+ // Reset the statement handle and warning
+
+ reset();
+
+ try
+ {
+ ADORecordset* pSet = nullptr;
+ CHECK_RETURN(m_Command.put_CommandText(sql))
+ CHECK_RETURN(m_Command.Execute(m_RecordsAffected,m_Parameters,adCmdText,&pSet))
+
+ assignRecordSet( pSet );
+ }
+ catch (SQLWarning& ex)
+ {
+
+ // Save pointer to warning and save with ResultSet
+ // object once it is created.
+
+ m_aLastWarning = ex;
+ }
+
+ return m_RecordSet.IsValid();
+}
+
+Reference< XResultSet > SAL_CALL OStatement_Base::executeQuery( const OUString& sql )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OStatement_BASE::rBHelper.bDisposed);
+
+
+ reset();
+
+ m_xResultSet = WeakReference<XResultSet>(nullptr);
+
+ WpADORecordset aSet;
+ aSet.Create();
+ CHECK_RETURN(m_Command.put_CommandText(sql))
+ OLEVariant aCmd;
+ aCmd.setIDispatch(m_Command);
+ OLEVariant aCon;
+ aCon.setNoArg();
+ CHECK_RETURN(aSet.put_CacheSize(m_nFetchSize))
+ CHECK_RETURN(aSet.put_MaxRecords(m_nMaxRows))
+ CHECK_RETURN(aSet.Open(aCmd,aCon,m_eCursorType,m_eLockType,adOpenUnspecified))
+
+
+ CHECK_RETURN(aSet.get_CacheSize(m_nFetchSize))
+ CHECK_RETURN(aSet.get_MaxRecords(m_nMaxRows))
+ CHECK_RETURN(aSet.get_CursorType(m_eCursorType))
+ CHECK_RETURN(aSet.get_LockType(m_eLockType))
+
+ rtl::Reference<OResultSet> pSet = new OResultSet(aSet,this);
+ pSet->construct();
+
+ m_xResultSet = WeakReference<XResultSet>(pSet);
+
+ return pSet;
+}
+
+
+Reference< XConnection > SAL_CALL OStatement_Base::getConnection( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OStatement_BASE::rBHelper.bDisposed);
+
+
+ return static_cast<Reference< XConnection >>(m_pConnection);
+}
+
+
+Any SAL_CALL OStatement::queryInterface( const Type & rType )
+{
+ Any aRet = ::cppu::queryInterface(rType,static_cast< XBatchExecution*> (this));
+ return aRet.hasValue() ? aRet : OStatement_Base::queryInterface(rType);
+}
+
+
+void SAL_CALL OStatement::addBatch( const OUString& sql )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OStatement_BASE::rBHelper.bDisposed);
+
+
+ m_aBatchVector.push_back(sql);
+}
+
+Sequence< sal_Int32 > SAL_CALL OStatement::executeBatch( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OStatement_BASE::rBHelper.bDisposed);
+
+
+ reset();
+
+ OUString aBatchSql = std::accumulate(m_aBatchVector.begin(), m_aBatchVector.end(), OUString(),
+ [](const OUString& rRes, const OUString& rStr) { return rRes + rStr + ";"; });
+ sal_Int32 nLen = m_aBatchVector.size();
+
+
+ if ( m_RecordSet.IsValid() )
+ m_RecordSet.PutRefDataSource( nullptr );
+ m_RecordSet.clear();
+ m_RecordSet.Create();
+
+ CHECK_RETURN(m_Command.put_CommandText(aBatchSql))
+ if ( m_RecordSet.IsValid() )
+ m_RecordSet.PutRefDataSource(static_cast<IDispatch*>(m_Command));
+
+ CHECK_RETURN(m_RecordSet.UpdateBatch(adAffectAll))
+
+ ADORecordset* pSet=nullptr;
+ Sequence< sal_Int32 > aRet(nLen);
+ sal_Int32* pArray = aRet.getArray();
+ for(sal_Int32 j=0;j<nLen;++j)
+ {
+ pSet = nullptr;
+ OLEVariant aRecordsAffected;
+ if(m_RecordSet.NextRecordset(aRecordsAffected,&pSet) && pSet)
+ {
+ assignRecordSet( pSet );
+
+ ADO_LONGPTR nValue;
+ if(m_RecordSet.get_RecordCount(nValue))
+ pArray[j] = nValue;
+ }
+ }
+ return aRet;
+}
+
+
+sal_Int32 SAL_CALL OStatement_Base::executeUpdate( const OUString& sql )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OStatement_BASE::rBHelper.bDisposed);
+
+
+ reset();
+
+ try {
+ ADORecordset* pSet = nullptr;
+ CHECK_RETURN(m_Command.put_CommandText(sql))
+ CHECK_RETURN(m_Command.Execute(m_RecordsAffected,m_Parameters,long(adCmdText)|long(adExecuteNoRecords),&pSet))
+ }
+ catch (SQLWarning& ex) {
+
+ // Save pointer to warning and save with ResultSet
+ // object once it is created.
+
+ m_aLastWarning = ex;
+ }
+ if(!m_RecordsAffected.isEmpty() && !m_RecordsAffected.isNull() && m_RecordsAffected.getType() != VT_ERROR)
+ return m_RecordsAffected.getInt32();
+
+ return 0;
+}
+
+
+Reference< XResultSet > SAL_CALL OStatement_Base::getResultSet( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OStatement_BASE::rBHelper.bDisposed);
+
+
+ return m_xResultSet;
+}
+
+
+sal_Int32 SAL_CALL OStatement_Base::getUpdateCount( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OStatement_BASE::rBHelper.bDisposed);
+
+
+ ADO_LONGPTR nRet;
+ if(m_RecordSet.IsValid() && m_RecordSet.get_RecordCount(nRet))
+ return nRet;
+ return -1;
+}
+
+
+sal_Bool SAL_CALL OStatement_Base::getMoreResults( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OStatement_BASE::rBHelper.bDisposed);
+
+
+ // clear previous warnings
+
+ clearWarnings ();
+
+ // Call SQLMoreResults
+
+ try
+ {
+ ADORecordset* pSet=nullptr;
+ OLEVariant aRecordsAffected;
+ if(m_RecordSet.IsValid() && m_RecordSet.NextRecordset(aRecordsAffected,&pSet) && pSet)
+ assignRecordSet( pSet );
+ }
+ catch (SQLWarning &)
+ {
+
+ //TODO: Save pointer to warning and save with ResultSet
+ // object once it is created.
+ }
+ return m_RecordSet.IsValid();
+}
+
+
+Any SAL_CALL OStatement_Base::getWarnings( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OStatement_BASE::rBHelper.bDisposed);
+
+
+ return Any(m_aLastWarning);
+}
+
+
+void SAL_CALL OStatement_Base::clearWarnings( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OStatement_BASE::rBHelper.bDisposed);
+
+
+ m_aLastWarning = SQLWarning();
+}
+
+
+sal_Int32 OStatement_Base::getQueryTimeOut() const
+{
+ return m_Command.get_CommandTimeout();
+}
+
+sal_Int32 OStatement_Base::getMaxRows() const
+{
+ ADO_LONGPTR nRet=-1;
+ if(!(m_RecordSet.IsValid() && m_RecordSet.get_MaxRecords(nRet)))
+ ::dbtools::throwFunctionSequenceException(nullptr);
+ return nRet;
+}
+
+sal_Int32 OStatement_Base::getResultSetConcurrency() const
+{
+ sal_Int32 nValue;
+
+ switch(m_eLockType)
+ {
+ case adLockReadOnly:
+ nValue = ResultSetConcurrency::READ_ONLY;
+ break;
+ default:
+ nValue = ResultSetConcurrency::UPDATABLE;
+ break;
+ }
+
+ return nValue;
+}
+
+sal_Int32 OStatement_Base::getResultSetType() const
+{
+ sal_Int32 nValue=0;
+ switch(m_eCursorType)
+ {
+ case adOpenUnspecified:
+ case adOpenForwardOnly:
+ nValue = ResultSetType::FORWARD_ONLY;
+ break;
+ case adOpenStatic:
+ case adOpenKeyset:
+ nValue = ResultSetType::SCROLL_INSENSITIVE;
+ break;
+ case adOpenDynamic:
+ nValue = ResultSetType::SCROLL_SENSITIVE;
+ break;
+ }
+ return nValue;
+}
+
+sal_Int32 OStatement_Base::getFetchDirection()
+{
+ return FetchDirection::FORWARD;
+}
+
+sal_Int32 OStatement_Base::getFetchSize() const
+{
+ return m_nFetchSize;
+}
+
+sal_Int32 OStatement_Base::getMaxFieldSize()
+{
+ return 0;
+}
+
+OUString OStatement_Base::getCursorName() const
+{
+ return m_Command.GetName();
+}
+
+void OStatement_Base::setQueryTimeOut(sal_Int32 seconds)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OStatement_BASE::rBHelper.bDisposed);
+
+
+ m_Command.put_CommandTimeout(seconds);
+}
+
+void OStatement_Base::setMaxRows(sal_Int32 _par0)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OStatement_BASE::rBHelper.bDisposed);
+
+ m_nMaxRows = _par0;
+}
+
+void OStatement_Base::setResultSetConcurrency(sal_Int32 _par0)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OStatement_BASE::rBHelper.bDisposed);
+
+ switch(_par0)
+ {
+ case ResultSetConcurrency::READ_ONLY:
+ m_eLockType = adLockReadOnly;
+ break;
+ default:
+ m_eLockType = adLockOptimistic;
+ break;
+ }
+}
+
+void OStatement_Base::setResultSetType(sal_Int32 _par0)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OStatement_BASE::rBHelper.bDisposed);
+
+
+ switch(_par0)
+ {
+ case ResultSetType::FORWARD_ONLY:
+ m_eCursorType = adOpenForwardOnly;
+ break;
+ case ResultSetType::SCROLL_INSENSITIVE:
+ m_eCursorType = adOpenKeyset;
+ break;
+ case ResultSetType::SCROLL_SENSITIVE:
+ m_eCursorType = adOpenDynamic;
+ break;
+ }
+}
+
+void OStatement_Base::setFetchDirection(sal_Int32 /*_par0*/)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OStatement_BASE::rBHelper.bDisposed);
+ ::dbtools::throwFeatureNotImplementedSQLException( "Statement::FetchDirection", *this );
+}
+
+void OStatement_Base::setFetchSize(sal_Int32 _par0)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OStatement_BASE::rBHelper.bDisposed);
+
+
+ m_nFetchSize = _par0;
+}
+
+void OStatement_Base::setMaxFieldSize(sal_Int32 /*_par0*/)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OStatement_BASE::rBHelper.bDisposed);
+ ::dbtools::throwFeatureNotImplementedSQLException( "Statement::MaxFieldSize", *this );
+}
+
+void OStatement_Base::setCursorName(std::u16string_view _par0)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OStatement_BASE::rBHelper.bDisposed);
+
+ m_Command.put_Name(_par0);
+}
+
+
+::cppu::IPropertyArrayHelper* OStatement_Base::createArrayHelper( ) const
+{
+ return new ::cppu::OPropertyArrayHelper
+ {
+ {
+ {
+ ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_CURSORNAME),
+ PROPERTY_ID_CURSORNAME,
+ cppu::UnoType<OUString>::get(),
+ 0
+ },
+ {
+ ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ESCAPEPROCESSING),
+ PROPERTY_ID_ESCAPEPROCESSING,
+ cppu::UnoType<bool>::get(),
+ 0
+ },
+ {
+ ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHDIRECTION),
+ PROPERTY_ID_FETCHDIRECTION,
+ cppu::UnoType<sal_Int32>::get(),
+ 0
+ },
+ {
+ ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHSIZE),
+ PROPERTY_ID_FETCHSIZE,
+ cppu::UnoType<sal_Int32>::get(),
+ 0
+ },
+ {
+ ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_MAXFIELDSIZE),
+ PROPERTY_ID_MAXFIELDSIZE,
+ cppu::UnoType<sal_Int32>::get(),
+ 0
+ },
+ {
+ ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_MAXROWS),
+ PROPERTY_ID_MAXROWS,
+ cppu::UnoType<sal_Int32>::get(),
+ 0
+ },
+ {
+ ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_QUERYTIMEOUT),
+ PROPERTY_ID_QUERYTIMEOUT,
+ cppu::UnoType<sal_Int32>::get(),
+ 0
+ },
+ {
+ ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETCONCURRENCY),
+ PROPERTY_ID_RESULTSETCONCURRENCY,
+ cppu::UnoType<sal_Int32>::get(),
+ 0
+ },
+ {
+ ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETTYPE),
+ PROPERTY_ID_RESULTSETTYPE,
+ cppu::UnoType<sal_Int32>::get(),
+ 0
+ },
+ {
+ ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_USEBOOKMARKS),
+ PROPERTY_ID_USEBOOKMARKS,
+ cppu::UnoType<bool>::get(),
+ 0
+ }
+ }
+ };
+}
+
+
+::cppu::IPropertyArrayHelper & OStatement_Base::getInfoHelper()
+{
+ return *getArrayHelper();
+}
+
+sal_Bool OStatement_Base::convertFastPropertyValue(
+ Any & rConvertedValue,
+ Any & rOldValue,
+ sal_Int32 nHandle,
+ const Any& rValue )
+{
+ bool bModified = false;
+
+ bool bValidAdoRS = m_RecordSet.IsValid();
+ // some of the properties below, when set, are remembered in a member, and applied in the next execute
+ // For these properties, the record set does not need to be valid to allow setting them.
+ // For all others (where the values are forwarded to the ADO RS directly), the recordset must be valid.
+
+ try
+ {
+ switch(nHandle)
+ {
+ case PROPERTY_ID_MAXROWS:
+ bModified = ::comphelper::tryPropertyValue( rConvertedValue, rOldValue, rValue, bValidAdoRS ? getMaxRows() : m_nMaxRows );
+ break;
+
+ case PROPERTY_ID_RESULTSETTYPE:
+ bModified = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, getResultSetType());
+ break;
+ case PROPERTY_ID_FETCHSIZE:
+ bModified = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, getFetchSize());
+ break;
+ case PROPERTY_ID_RESULTSETCONCURRENCY:
+ bModified = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, getResultSetConcurrency());
+ break;
+ case PROPERTY_ID_QUERYTIMEOUT:
+ bModified = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, getQueryTimeOut());
+ break;
+ case PROPERTY_ID_MAXFIELDSIZE:
+ bModified = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, getMaxFieldSize());
+ break;
+ case PROPERTY_ID_CURSORNAME:
+ bModified = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, getCursorName());
+ break;
+ case PROPERTY_ID_FETCHDIRECTION:
+ bModified = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, getFetchDirection());
+ break;
+ }
+ }
+ catch( const Exception& )
+ {
+ bModified = true; // will ensure that the property is set
+ OSL_FAIL( "OStatement_Base::convertFastPropertyValue: caught something strange!" );
+ }
+ return bModified;
+}
+
+void OStatement_Base::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,const Any& rValue)
+{
+ switch(nHandle)
+ {
+ case PROPERTY_ID_QUERYTIMEOUT:
+ setQueryTimeOut(comphelper::getINT32(rValue));
+ break;
+ case PROPERTY_ID_MAXFIELDSIZE:
+ setMaxFieldSize(comphelper::getINT32(rValue));
+ break;
+ case PROPERTY_ID_MAXROWS:
+ setMaxRows(comphelper::getINT32(rValue));
+ break;
+ case PROPERTY_ID_CURSORNAME:
+ setCursorName(comphelper::getString(rValue));
+ break;
+ case PROPERTY_ID_RESULTSETCONCURRENCY:
+ setResultSetConcurrency(comphelper::getINT32(rValue));
+ break;
+ case PROPERTY_ID_RESULTSETTYPE:
+ setResultSetType(comphelper::getINT32(rValue));
+ break;
+ case PROPERTY_ID_FETCHDIRECTION:
+ setFetchDirection(comphelper::getINT32(rValue));
+ break;
+ case PROPERTY_ID_FETCHSIZE:
+ setFetchSize(comphelper::getINT32(rValue));
+ break;
+ case PROPERTY_ID_ESCAPEPROCESSING:
+ // return ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, m_bAsLink);
+ case PROPERTY_ID_USEBOOKMARKS:
+ // return ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, m_bAsLink);
+ default:
+ ;
+ }
+}
+
+void OStatement_Base::getFastPropertyValue(Any& rValue,sal_Int32 nHandle) const
+{
+ switch(nHandle)
+ {
+ case PROPERTY_ID_QUERYTIMEOUT:
+ rValue <<= getQueryTimeOut();
+ break;
+ case PROPERTY_ID_MAXFIELDSIZE:
+ rValue <<= getMaxFieldSize();
+ break;
+ case PROPERTY_ID_MAXROWS:
+ rValue <<= getMaxRows();
+ break;
+ case PROPERTY_ID_CURSORNAME:
+ rValue <<= getCursorName();
+ break;
+ case PROPERTY_ID_RESULTSETCONCURRENCY:
+ rValue <<= getResultSetConcurrency();
+ break;
+ case PROPERTY_ID_RESULTSETTYPE:
+ rValue <<= getResultSetType();
+ break;
+ case PROPERTY_ID_FETCHDIRECTION:
+ rValue <<= getFetchDirection();
+ break;
+ case PROPERTY_ID_FETCHSIZE:
+ rValue <<= getFetchSize();
+ break;
+ case PROPERTY_ID_ESCAPEPROCESSING:
+ rValue <<= true;
+ break;
+ case PROPERTY_ID_USEBOOKMARKS:
+ default:
+ ;
+ }
+}
+
+OStatement::~OStatement()
+{
+}
+IMPLEMENT_SERVICE_INFO(OStatement,"com.sun.star.sdbcx.AStatement","com.sun.star.sdbc.Statement");
+
+void SAL_CALL OStatement_Base::acquire() noexcept
+{
+ OStatement_BASE::acquire();
+}
+
+void SAL_CALL OStatement::acquire() noexcept
+{
+ OStatement_Base::acquire();
+}
+
+void SAL_CALL OStatement::release() noexcept
+{
+ OStatement_Base::release();
+}
+
+css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL OStatement_Base::getPropertySetInfo( )
+{
+ return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper());
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/ado/ATable.cxx b/connectivity/source/drivers/ado/ATable.cxx
new file mode 100644
index 0000000000..47e22e1253
--- /dev/null
+++ b/connectivity/source/drivers/ado/ATable.cxx
@@ -0,0 +1,216 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <string_view>
+
+#include <ado/ATable.hxx>
+#include <ado/AIndexes.hxx>
+#include <ado/AColumns.hxx>
+#include <ado/AColumn.hxx>
+#include <ado/AKeys.hxx>
+#include <ado/AConnection.hxx>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XResultSet.hpp>
+#include <com/sun/star/sdbcx/KeyType.hpp>
+#include <com/sun/star/sdbc/KeyRule.hpp>
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <com/sun/star/sdbc/ColumnValue.hpp>
+#include <ado/Awrapado.hxx>
+#include <TConnection.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <comphelper/types.hxx>
+
+using namespace ::comphelper;
+
+using namespace connectivity;
+using namespace connectivity::ado;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::sdbc;
+using namespace com::sun::star::container;
+
+
+OAdoTable::OAdoTable(sdbcx::OCollection* _pTables,bool _bCase,OCatalog* _pCatalog,_ADOTable* _pTable)
+ : OTable_TYPEDEF(_pTables,_bCase)
+ ,m_pCatalog(_pCatalog)
+{
+ construct();
+ m_aTable.set(_pTable);
+ // m_aTable.putref_ParentCatalog(_pCatalog->getCatalog());
+ fillPropertyValues();
+
+}
+
+OAdoTable::OAdoTable(sdbcx::OCollection* _pTables,bool _bCase,OCatalog* _pCatalog)
+ : OTable_TYPEDEF(_pTables,_bCase)
+ ,m_pCatalog(_pCatalog)
+{
+ construct();
+ m_aTable.Create();
+ m_aTable.putref_ParentCatalog(_pCatalog->getCatalog());
+
+}
+
+void SAL_CALL OAdoTable::disposing()
+{
+ OTable_TYPEDEF::disposing();
+ m_aTable.clear();
+}
+
+void OAdoTable::refreshColumns()
+{
+ ::std::vector< OUString> aVector;
+
+ WpADOColumns aColumns;
+ if ( m_aTable.IsValid() )
+ {
+ aColumns = m_aTable.get_Columns();
+ aColumns.fillElementNames(aVector);
+ }
+
+ if(m_xColumns)
+ m_xColumns->reFill(aVector);
+ else
+ m_xColumns.reset(new OColumns(*this,m_aMutex,aVector,aColumns,isCaseSensitive(),m_pCatalog->getConnection()));
+}
+
+void OAdoTable::refreshKeys()
+{
+ ::std::vector< OUString> aVector;
+
+ WpADOKeys aKeys;
+ if(m_aTable.IsValid())
+ {
+ aKeys = m_aTable.get_Keys();
+ aKeys.fillElementNames(aVector);
+ }
+
+ if(m_xKeys)
+ m_xKeys->reFill(aVector);
+ else
+ m_xKeys.reset(new OKeys(*this,m_aMutex,aVector,aKeys,isCaseSensitive(),m_pCatalog->getConnection()));
+}
+
+void OAdoTable::refreshIndexes()
+{
+ ::std::vector< OUString> aVector;
+
+ WpADOIndexes aIndexes;
+ if(m_aTable.IsValid())
+ {
+ aIndexes = m_aTable.get_Indexes();
+ aIndexes.fillElementNames(aVector);
+ }
+
+ if(m_xIndexes)
+ m_xIndexes->reFill(aVector);
+ else
+ m_xIndexes.reset(new OIndexes(*this,m_aMutex,aVector,aIndexes,isCaseSensitive(),m_pCatalog->getConnection()));
+}
+
+// XRename
+void SAL_CALL OAdoTable::rename( const OUString& newName )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(OTableDescriptor_BASE_TYPEDEF::rBHelper.bDisposed);
+
+ m_aTable.put_Name(newName);
+ ADOS::ThrowException(m_pCatalog->getConnection()->getConnection(),*this);
+
+ OTable_TYPEDEF::rename(newName);
+}
+
+Reference< XDatabaseMetaData> OAdoTable::getMetaData() const
+{
+ return m_pCatalog->getConnection()->getMetaData();
+}
+
+// XAlterTable
+void SAL_CALL OAdoTable::alterColumnByName( const OUString& colName, const Reference< XPropertySet >& descriptor )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(OTableDescriptor_BASE_TYPEDEF::rBHelper.bDisposed);
+
+ bool bError = true;
+ OAdoColumn* pColumn = dynamic_cast<OAdoColumn*>(descriptor.get());
+ if(pColumn != nullptr)
+ {
+ WpADOColumns aColumns = m_aTable.get_Columns();
+ bError = !aColumns.Delete(colName);
+ bError = bError || !aColumns.Append(pColumn->getColumnImpl());
+ }
+ if(bError)
+ ADOS::ThrowException(m_pCatalog->getConnection()->getConnection(),*this);
+
+ m_xColumns->refresh();
+ refreshColumns();
+}
+
+void SAL_CALL OAdoTable::alterColumnByIndex( sal_Int32 index, const Reference< XPropertySet >& descriptor )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(OTableDescriptor_BASE_TYPEDEF::rBHelper.bDisposed);
+
+ Reference< XPropertySet > xOld;
+ m_xColumns->getByIndex(index) >>= xOld;
+ if(xOld.is())
+ alterColumnByName(getString(xOld->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME))),descriptor);
+}
+
+void OAdoTable::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,const Any& rValue)
+{
+ if(m_aTable.IsValid())
+ {
+ switch(nHandle)
+ {
+ case PROPERTY_ID_NAME:
+ m_aTable.put_Name(getString(rValue));
+ break;
+
+ case PROPERTY_ID_TYPE:
+ OTools::putValue( m_aTable.get_Properties(),
+ OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE),
+ getString(rValue));
+ break;
+
+ case PROPERTY_ID_DESCRIPTION:
+ OTools::putValue( m_aTable.get_Properties(),
+ std::u16string_view(u"Description"),
+ getString(rValue));
+ break;
+
+ case PROPERTY_ID_SCHEMANAME:
+ break;
+
+ default:
+ throw Exception("unknown prop " + OUString::number(nHandle), nullptr);
+ }
+ }
+ OTable_TYPEDEF::setFastPropertyValue_NoBroadcast(nHandle,rValue);
+}
+
+OUString SAL_CALL OAdoTable::getName()
+{
+ return m_aTable.get_Name();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/ado/ATables.cxx b/connectivity/source/drivers/ado/ATables.cxx
new file mode 100644
index 0000000000..07910462fb
--- /dev/null
+++ b/connectivity/source/drivers/ado/ATables.cxx
@@ -0,0 +1,103 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <ado/ATables.hxx>
+#include <ado/ATable.hxx>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XResultSet.hpp>
+#include <com/sun/star/sdbc/ColumnValue.hpp>
+#include <com/sun/star/sdbc/KeyRule.hpp>
+#include <com/sun/star/sdbcx/KeyType.hpp>
+#include <ado/ACatalog.hxx>
+#include <ado/AConnection.hxx>
+#include <ado/Awrapado.hxx>
+#include <TConnection.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <comphelper/types.hxx>
+#include <cppuhelper/interfacecontainer.h>
+#include <connectivity/dbexception.hxx>
+#include <strings.hrc>
+
+using namespace ::cppu;
+using namespace connectivity;
+using namespace comphelper;
+using namespace connectivity::ado;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::sdbc;
+using namespace com::sun::star::container;
+
+sdbcx::ObjectType OTables::createObject(const OUString& _rName)
+{
+ OSL_ENSURE(m_aCollection.IsValid(),"Collection isn't valid");
+ return new OAdoTable(this,isCaseSensitive(),m_pCatalog,m_aCollection.GetItem(_rName));
+}
+
+void OTables::impl_refresh( )
+{
+ OSL_ENSURE(m_aCollection.IsValid(),"Collection isn't valid");
+ m_aCollection.Refresh();
+ m_pCatalog->refreshTables();
+}
+
+Reference< XPropertySet > OTables::createDescriptor()
+{
+ return new OAdoTable(this,isCaseSensitive(),m_pCatalog);
+}
+
+// XAppend
+sdbcx::ObjectType OTables::appendObject( const OUString&, const Reference< XPropertySet >& descriptor )
+{
+ OAdoTable* pTable = dynamic_cast<OAdoTable*>( descriptor.get() );
+ if ( pTable == nullptr )
+ m_pCatalog->getConnection()->throwGenericSQLException( STR_INVALID_TABLE_DESCRIPTOR_ERROR,static_cast<XTypeProvider*>(this) );
+
+ OSL_ENSURE(m_aCollection.IsValid(),"Collection isn't valid");
+ if(!m_aCollection.Append(pTable->getImpl()))
+ ADOS::ThrowException(m_pCatalog->getConnection()->getConnection(),static_cast<XTypeProvider*>(this));
+ m_aCollection.Refresh();
+
+ return new OAdoTable(this,isCaseSensitive(),m_pCatalog,pTable->getImpl());
+}
+
+// XDrop
+void OTables::dropObject(sal_Int32 /*_nPos*/,const OUString& _sElementName)
+{
+ OSL_ENSURE(m_aCollection.IsValid(),"Collection isn't valid");
+ if ( !m_aCollection.Delete(_sElementName) )
+ ADOS::ThrowException(m_pCatalog->getConnection()->getConnection(),static_cast<XTypeProvider*>(this));
+}
+
+void OTables::appendNew(const OUString& _rsNewTable)
+{
+ OSL_ENSURE(m_aCollection.IsValid(),"Collection isn't valid");
+ m_aCollection.Refresh();
+
+ insertElement(_rsNewTable,nullptr);
+
+ // notify our container listeners
+ ContainerEvent aEvent(static_cast<XContainer*>(this), Any(_rsNewTable), Any(), Any());
+ OInterfaceIteratorHelper3 aListenerLoop(m_aContainerListeners);
+ while (aListenerLoop.hasMoreElements())
+ aListenerLoop.next()->elementInserted(aEvent);
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/ado/AUser.cxx b/connectivity/source/drivers/ado/AUser.cxx
new file mode 100644
index 0000000000..eb7a5803f6
--- /dev/null
+++ b/connectivity/source/drivers/ado/AUser.cxx
@@ -0,0 +1,175 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <ado/AUser.hxx>
+#include <ado/ACatalog.hxx>
+#include <ado/AGroups.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XResultSet.hpp>
+#include <ado/AConnection.hxx>
+#include <ado/Awrapado.hxx>
+
+using namespace connectivity::ado;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::sdbc;
+
+
+OAdoUser::OAdoUser(OCatalog* _pParent,bool _bCase, ADOUser* _pUser)
+ : OUser_TYPEDEF(_bCase)
+ ,m_pCatalog(_pParent)
+{
+ construct();
+
+ if(_pUser)
+ m_aUser.set(_pUser);
+ else
+ m_aUser.Create();
+}
+
+OAdoUser::OAdoUser(OCatalog* _pParent,bool _bCase, const OUString& Name)
+ : OUser_TYPEDEF(Name,_bCase)
+ , m_pCatalog(_pParent)
+{
+ construct();
+ m_aUser.Create();
+ m_aUser.put_Name(Name);
+}
+
+void OAdoUser::refreshGroups()
+{
+ ::std::vector< OUString> aVector;
+ WpADOGroups aGroups(m_aUser.get_Groups());
+ aGroups.fillElementNames(aVector);
+ if(m_pGroups)
+ m_pGroups->reFill(aVector);
+ else
+ m_pGroups.reset(new OGroups(m_pCatalog, m_aMutex, aVector, aGroups, isCaseSensitive()));
+}
+
+void OAdoUser::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,const Any& rValue)
+{
+ if(m_aUser.IsValid())
+ {
+
+ switch(nHandle)
+ {
+ case PROPERTY_ID_NAME:
+ {
+ OUString aVal;
+ rValue >>= aVal;
+ m_aUser.put_Name(aVal);
+ }
+ break;
+ }
+ }
+}
+
+void OAdoUser::getFastPropertyValue(Any& rValue,sal_Int32 nHandle) const
+{
+ if(m_aUser.IsValid())
+ {
+ switch(nHandle)
+ {
+ case PROPERTY_ID_NAME:
+ rValue <<= m_aUser.get_Name();
+ break;
+ }
+ }
+}
+
+OUserExtend::OUserExtend(OCatalog* _pParent,bool _bCase, ADOUser* _pUser)
+ : OAdoUser(_pParent,_bCase,_pUser)
+{
+}
+
+OUserExtend::OUserExtend(OCatalog* _pParent,bool _bCase, const OUString& Name)
+ : OAdoUser(_pParent,_bCase,Name)
+{
+}
+
+
+void OUserExtend::construct()
+{
+ OUser_TYPEDEF::construct();
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PASSWORD), PROPERTY_ID_PASSWORD,0,&m_Password,::cppu::UnoType<OUString>::get());
+}
+
+cppu::IPropertyArrayHelper* OUserExtend::createArrayHelper() const
+{
+ Sequence< css::beans::Property > aProps;
+ describeProperties(aProps);
+ return new cppu::OPropertyArrayHelper(aProps);
+}
+
+cppu::IPropertyArrayHelper & OUserExtend::getInfoHelper()
+{
+ return *OUserExtend_PROP::getArrayHelper();
+}
+
+sal_Int32 SAL_CALL OAdoUser::getPrivileges( const OUString& objName, sal_Int32 objType )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(OUser_BASE_TYPEDEF::rBHelper.bDisposed);
+
+ return ADOS::mapAdoRights2Sdbc(m_aUser.GetPermissions(objName, ADOS::mapObjectType2Ado(objType)));
+}
+
+sal_Int32 SAL_CALL OAdoUser::getGrantablePrivileges( const OUString& objName, sal_Int32 objType )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(OUser_BASE_TYPEDEF::rBHelper.bDisposed);
+
+ sal_Int32 nRights = 0;
+ RightsEnum eRights = m_aUser.GetPermissions(objName, ADOS::mapObjectType2Ado(objType));
+ if((eRights & adRightWithGrant) == adRightWithGrant)
+ nRights = ADOS::mapAdoRights2Sdbc(eRights);
+ ADOS::ThrowException(m_pCatalog->getConnection()->getConnection(),*this);
+ return nRights;
+}
+
+void SAL_CALL OAdoUser::grantPrivileges( const OUString& objName, sal_Int32 objType, sal_Int32 objPrivileges )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(OUser_BASE_TYPEDEF::rBHelper.bDisposed);
+ m_aUser.SetPermissions(objName,ADOS::mapObjectType2Ado(objType),adAccessGrant,RightsEnum(ADOS::mapRights2Ado(objPrivileges)));
+ ADOS::ThrowException(m_pCatalog->getConnection()->getConnection(),*this);
+}
+
+void SAL_CALL OAdoUser::revokePrivileges( const OUString& objName, sal_Int32 objType, sal_Int32 objPrivileges )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(OUser_BASE_TYPEDEF::rBHelper.bDisposed);
+ m_aUser.SetPermissions(objName,ADOS::mapObjectType2Ado(objType),adAccessRevoke,RightsEnum(ADOS::mapRights2Ado(objPrivileges)));
+ ADOS::ThrowException(m_pCatalog->getConnection()->getConnection(),*this);
+}
+
+// XUser
+void SAL_CALL OAdoUser::changePassword( const OUString& objPassword, const OUString& newPassword )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(OUser_BASE_TYPEDEF::rBHelper.bDisposed);
+ m_aUser.ChangePassword(objPassword,newPassword);
+ ADOS::ThrowException(m_pCatalog->getConnection()->getConnection(),*this);
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/ado/AUsers.cxx b/connectivity/source/drivers/ado/AUsers.cxx
new file mode 100644
index 0000000000..4b050d2392
--- /dev/null
+++ b/connectivity/source/drivers/ado/AUsers.cxx
@@ -0,0 +1,77 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <ado/AUsers.hxx>
+#include <ado/AUser.hxx>
+#include <ado/ATable.hxx>
+#include <ado/AConnection.hxx>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XResultSet.hpp>
+#include <connectivity/sdbcx/IRefreshable.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <comphelper/types.hxx>
+#include <connectivity/dbexception.hxx>
+#include <systools/win32/oleauto.hxx>
+#include <strings.hrc>
+
+using namespace comphelper;
+using namespace connectivity;
+using namespace connectivity::ado;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::sdbc;
+using namespace com::sun::star::container;
+
+sdbcx::ObjectType OUsers::createObject(const OUString& _rName)
+{
+ return new OAdoUser(m_pCatalog,isCaseSensitive(),_rName);
+}
+
+void OUsers::impl_refresh()
+{
+ m_aCollection.Refresh();
+}
+
+Reference< XPropertySet > OUsers::createDescriptor()
+{
+ return new OUserExtend(m_pCatalog,isCaseSensitive());
+}
+
+// XAppend
+sdbcx::ObjectType OUsers::appendObject( const OUString& _rForName, const Reference< XPropertySet >& descriptor )
+{
+ OUserExtend* pUser = dynamic_cast<OUserExtend*>( descriptor.get() );
+ if ( pUser == nullptr )
+ m_pCatalog->getConnection()->throwGenericSQLException( STR_INVALID_USER_DESCRIPTOR_ERROR,static_cast<XTypeProvider*>(this) );
+
+ ADOUsers* pUsers = m_aCollection;
+ pUsers->Append(OLEVariant(pUser->getImpl()), sal::systools::BStr(pUser->getPassword()));
+
+ return createObject( _rForName );
+}
+
+// XDrop
+void OUsers::dropObject(sal_Int32 /*_nPos*/,const OUString& _sElementName)
+{
+ m_aCollection.Delete(_sElementName);
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/ado/AView.cxx b/connectivity/source/drivers/ado/AView.cxx
new file mode 100644
index 0000000000..10a5524db9
--- /dev/null
+++ b/connectivity/source/drivers/ado/AView.cxx
@@ -0,0 +1,78 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <ado/AView.hxx>
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <ado/adoimp.hxx>
+#include <ado/Awrapado.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <comphelper/types.hxx>
+#include <systools/win32/oleauto.hxx>
+
+#include <TConnection.hxx>
+
+
+using namespace comphelper;
+using namespace connectivity::ado;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::sdbc;
+
+// IMPLEMENT_SERVICE_INFO(OAdoView,"com.sun.star.sdbcx.AView","com.sun.star.sdbcx.View");
+
+OAdoView::OAdoView(bool _bCase,ADOView* _pView) : OView_ADO(_bCase,nullptr)
+,m_aView(_pView)
+{
+}
+
+void OAdoView::getFastPropertyValue(Any& rValue,sal_Int32 nHandle) const
+{
+ if(m_aView.IsValid())
+ {
+ switch(nHandle)
+ {
+ case PROPERTY_ID_NAME:
+ rValue <<= m_aView.get_Name();
+ break;
+ case PROPERTY_ID_CATALOGNAME:
+ break;
+ case PROPERTY_ID_SCHEMANAME:
+ // rValue <<= m_aView.get_Type();
+ break;
+ case PROPERTY_ID_COMMAND:
+ {
+ OLEVariant aVar;
+ m_aView.get_Command(aVar);
+ if(!aVar.isNull() && !aVar.isEmpty())
+ {
+ ADOCommand* pCom = static_cast<ADOCommand*>(aVar.getIDispatch());
+ sal::systools::BStr aBSTR;
+ pCom->get_CommandText(&aBSTR);
+ rValue <<= OUString(aBSTR);
+ }
+ }
+ break;
+ }
+ }
+ else
+ OView_ADO::getFastPropertyValue(rValue,nHandle);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/ado/AViews.cxx b/connectivity/source/drivers/ado/AViews.cxx
new file mode 100644
index 0000000000..9434222896
--- /dev/null
+++ b/connectivity/source/drivers/ado/AViews.cxx
@@ -0,0 +1,97 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <ado/AViews.hxx>
+#include <ado/AView.hxx>
+#include <ado/ATables.hxx>
+#include <ado/ACatalog.hxx>
+#include <ado/AConnection.hxx>
+#include <ado/Awrapado.hxx>
+#include <TConnection.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <comphelper/types.hxx>
+#include <connectivity/dbexception.hxx>
+#include <rtl/ref.hxx>
+#include <systools/win32/oleauto.hxx>
+
+#include <strings.hrc>
+
+using namespace ::comphelper;
+
+using namespace connectivity;
+using namespace connectivity::ado;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::sdbc;
+using namespace com::sun::star::container;
+
+sdbcx::ObjectType OViews::createObject(const OUString& _rName)
+{
+ rtl::Reference<OAdoView> pView = new OAdoView(isCaseSensitive(),m_aCollection.GetItem(_rName));
+ pView->setNew(false);
+ return pView;
+}
+
+void OViews::impl_refresh( )
+{
+ m_aCollection.Refresh();
+}
+
+Reference< XPropertySet > OViews::createDescriptor()
+{
+ return new OAdoView(isCaseSensitive());
+}
+
+
+// XAppend
+sdbcx::ObjectType OViews::appendObject( const OUString& _rForName, const Reference< XPropertySet >& descriptor )
+{
+ OAdoView* pView = dynamic_cast<OAdoView*>( descriptor.get() );
+ if ( pView == nullptr )
+ m_pCatalog->getConnection()->throwGenericSQLException( STR_INVALID_VIEW_DESCRIPTOR_ERROR,static_cast<XTypeProvider*>(this) );
+
+ WpADOCommand aCommand;
+ aCommand.Create();
+ if ( !aCommand.IsValid() )
+ m_pCatalog->getConnection()->throwGenericSQLException( STR_VIEW_NO_COMMAND_ERROR,static_cast<XTypeProvider*>(this) );
+
+ OUString sName( _rForName );
+ aCommand.put_Name(sName);
+ aCommand.put_CommandText(getString(descriptor->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_COMMAND))));
+ ADOViews* pViews = m_aCollection;
+ if (FAILED(pViews->Append(sal::systools::BStr(sName), aCommand)))
+ ADOS::ThrowException(m_pCatalog->getConnection()->getConnection(),static_cast<XTypeProvider*>(this));
+
+ OTables* pTables = static_cast<OTables*>(static_cast<OCatalog&>(m_rParent).getPrivateTables());
+ if ( pTables )
+ pTables->appendNew(sName);
+
+ return createObject( _rForName );
+}
+
+// XDrop
+void OViews::dropObject(sal_Int32 /*_nPos*/,const OUString& _sElementName)
+{
+ if(!m_aCollection.Delete(_sElementName))
+ ADOS::ThrowException(m_pCatalog->getConnection()->getConnection(),static_cast<XTypeProvider*>(this));
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/ado/Aolevariant.cxx b/connectivity/source/drivers/ado/Aolevariant.cxx
new file mode 100644
index 0000000000..c082c1987f
--- /dev/null
+++ b/connectivity/source/drivers/ado/Aolevariant.cxx
@@ -0,0 +1,687 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <ado/Aolevariant.hxx>
+#include <connectivity/dbconversion.hxx>
+#include <osl/diagnose.h>
+#include <o3tl/char16_t2wchar_t.hxx>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <com/sun/star/util/Time.hpp>
+#include <com/sun/star/util/Date.hpp>
+#include <com/sun/star/util/DateTime.hpp>
+#include <resource/sharedresources.hxx>
+#include <strings.hrc>
+#include <com/sun/star/bridge/oleautomation/Date.hpp>
+#include <com/sun/star/bridge/oleautomation/Currency.hpp>
+#include <com/sun/star/bridge/oleautomation/SCode.hpp>
+#include <com/sun/star/bridge/oleautomation/Decimal.hpp>
+
+using namespace com::sun::star::beans;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::bridge::oleautomation;
+using namespace connectivity::ado;
+
+OLEVariant::OLEVariant()
+{
+ VariantInit(this);
+}
+OLEVariant::OLEVariant(const VARIANT& varSrc)
+{
+ ::VariantInit(this);
+ HRESULT eRet = ::VariantCopy(this, &varSrc);
+ OSL_ENSURE(eRet == S_OK,"Error while copying an ado variant!");
+}
+OLEVariant::OLEVariant(const OLEVariant& varSrc)
+{
+ ::VariantInit(this);
+ HRESULT eRet = ::VariantCopy(this, static_cast<const VARIANT*>(&varSrc));
+ OSL_ENSURE(eRet == S_OK,"Error while copying an ado variant!");
+}
+
+OLEVariant::OLEVariant(bool x) { VariantInit(this); vt = VT_BOOL; boolVal = (x ? VARIANT_TRUE : VARIANT_FALSE);}
+OLEVariant::OLEVariant(sal_Int8 n) { VariantInit(this); vt = VT_I1; bVal = n;}
+OLEVariant::OLEVariant(sal_Int16 n) { VariantInit(this); vt = VT_I2; intVal = n;}
+OLEVariant::OLEVariant(sal_Int32 n) { VariantInit(this); vt = VT_I4; lVal = n;}
+OLEVariant::OLEVariant(sal_Int64 x) { VariantInit(this); vt = VT_I4; lVal = static_cast<LONG>(x);}
+
+OLEVariant::OLEVariant(std::u16string_view us)
+{
+ ::VariantInit(this);
+ vt = VT_BSTR;
+ bstrVal = SysAllocStringLen(o3tl::toW(us.data()), us.length());
+}
+OLEVariant::~OLEVariant()
+{
+ HRESULT eRet = ::VariantClear(this);
+ OSL_ENSURE(eRet == S_OK,"Error while clearing an ado variant!");
+} // clears all the memory that was allocated before
+
+OLEVariant::OLEVariant(const css::util::Date& x )
+{
+ VariantInit(this);
+ vt = VT_DATE;
+ dblVal = ::dbtools::DBTypeConversion::toDouble(x,css::util::Date(30,12,1899));
+}
+OLEVariant::OLEVariant(const css::util::Time& x )
+{
+ VariantInit(this);
+ vt = VT_DATE;
+ dblVal = ::dbtools::DBTypeConversion::toDouble(x);
+}
+OLEVariant::OLEVariant(const css::util::DateTime& x )
+{
+ VariantInit(this);
+ vt = VT_DATE;
+ dblVal = ::dbtools::DBTypeConversion::toDouble(x,css::util::Date(30,12,1899));
+}
+OLEVariant::OLEVariant(float x)
+{
+ VariantInit(this);
+ vt = VT_R4;
+ fltVal = x;
+}
+OLEVariant::OLEVariant(const double &x)
+{
+ VariantInit(this);
+ vt = VT_R8;
+ dblVal = x;
+}
+
+
+OLEVariant::OLEVariant(IDispatch* pDispInterface)
+{
+ VariantInit(this);
+ setIDispatch( pDispInterface );
+}
+
+OLEVariant::OLEVariant(const css::uno::Sequence< sal_Int8 >& x)
+{
+ VariantInit(this);
+
+ vt = VT_ARRAY|VT_UI1;
+
+ parray = SafeArrayCreateVector(VT_UI1, 0, x.getLength());
+ const sal_Int8* pBegin = x.getConstArray();
+ const sal_Int8* pEnd = pBegin + x.getLength();
+
+ for(sal_Int32 i=0;pBegin != pEnd;++i,++pBegin)
+ {
+ sal_Int32 nData = *pBegin;
+ HRESULT rs = SafeArrayPutElement(parray,&i,&nData);
+ OSL_ENSURE(S_OK == rs,"Error while copy byte data");
+ }
+}
+
+OLEVariant& OLEVariant::operator=(const OLEVariant& varSrc)
+{
+ HRESULT eRet = ::VariantCopy(this, static_cast<const VARIANT*>(&varSrc));
+ OSL_ENSURE(eRet == S_OK,"Error while copying an ado variant!");
+ return *this;
+}
+// Assign a const VARIANT& (::VariantCopy handles everything)
+
+OLEVariant& OLEVariant::operator=(const tagVARIANT& varSrc)
+{
+ HRESULT eRet = ::VariantCopy(this, &varSrc);
+ OSL_ENSURE(eRet == S_OK,"Error while copying an ado variant!");
+
+ return *this;
+}
+
+// Assign a const VARIANT* (::VariantCopy handles everything)
+
+OLEVariant& OLEVariant::operator=(const VARIANT* pSrc)
+{
+ HRESULT eRet = ::VariantCopy(this, pSrc);
+ OSL_ENSURE(eRet == S_OK,"Error while copying an ado variant!");
+
+ return *this;
+}
+
+void OLEVariant::setByte(sal_uInt8 n)
+{
+ HRESULT eRet = VariantClear(this);
+ OSL_ENSURE(eRet == S_OK,"Error while clearing an ado variant!");
+ vt = VT_UI1;
+ bVal = n;
+}
+void OLEVariant::setInt16(sal_Int16 n)
+{
+ HRESULT eRet = VariantClear(this);
+ OSL_ENSURE(eRet == S_OK,"Error while clearing an ado variant!");
+ vt = VT_I2;
+ iVal = n;
+}
+void OLEVariant::setInt32(sal_Int32 n)
+{
+ HRESULT eRet = VariantClear(this);
+ OSL_ENSURE(eRet == S_OK,"Error while clearing an ado variant!");
+ vt = VT_I4;
+ lVal = n;
+}
+void OLEVariant::setFloat(float f)
+{ HRESULT eRet = VariantClear(this);
+ OSL_ENSURE(eRet == S_OK,"Error while clearing an ado variant!");
+ vt = VT_R4;
+ fltVal = f;
+}
+void OLEVariant::setDouble(double d)
+{
+ HRESULT eRet = VariantClear(this);
+ OSL_ENSURE(eRet == S_OK,"Error while clearing an ado variant!");
+ vt = VT_R8;
+ dblVal = d;
+}
+void OLEVariant::setDate(DATE d)
+{ HRESULT eRet = VariantClear(this);
+ OSL_ENSURE(eRet == S_OK,"Error while clearing an ado variant!");
+ vt = VT_DATE;
+ date = d;
+}
+void OLEVariant::setChar(unsigned char a)
+{
+ HRESULT eRet = VariantClear(this);
+ OSL_ENSURE(eRet == S_OK,"Error while clearing an ado variant!");
+ vt = VT_UI1;
+ bVal = a;
+}
+void OLEVariant::setCurrency(double aCur)
+{
+ HRESULT eRet = VariantClear(this);
+ OSL_ENSURE(eRet == S_OK,"Error while clearing an ado variant!");
+ vt = VT_CY;
+ set(aCur*10000);
+}
+void OLEVariant::setBool(bool b)
+{
+ HRESULT eRet = VariantClear(this);
+ OSL_ENSURE(eRet == S_OK,"Error while clearing an ado variant!");
+ vt = VT_BOOL;
+ boolVal = b ? VARIANT_TRUE : VARIANT_FALSE;
+}
+void OLEVariant::setString(std::u16string_view us)
+{
+ HRESULT eRet = VariantClear(this);
+ OSL_ENSURE(eRet == S_OK,"Error while clearing an ado variant!");
+ vt = VT_BSTR;
+ bstrVal = SysAllocStringLen(o3tl::toW(us.data()), us.length());
+}
+void OLEVariant::setNoArg()
+{
+ HRESULT eRet = VariantClear(this);
+ OSL_ENSURE(eRet == S_OK,"Error while clearing an ado variant!");
+ vt = VT_ERROR;
+ scode = DISP_E_PARAMNOTFOUND;
+}
+
+void OLEVariant::setNull()
+{
+ HRESULT eRet = VariantClear(this);
+ OSL_ENSURE(eRet == S_OK,"Error while clearing an ado variant!");
+ vt = VT_NULL;
+}
+void OLEVariant::setEmpty()
+{
+ HRESULT eRet = VariantClear(this);
+ OSL_ENSURE(eRet == S_OK,"Error while clearing an ado variant!");
+ vt = VT_EMPTY;
+}
+
+void OLEVariant::setUI1SAFEARRAYPtr(SAFEARRAY* pSafeAr)
+{
+ HRESULT eRet = VariantClear(this);
+ OSL_ENSURE(eRet == S_OK,"Error while clearing an ado variant!");
+ vt = VT_ARRAY|VT_UI1; parray = pSafeAr;
+}
+
+void OLEVariant::setArray(SAFEARRAY* pSafeArray, VARTYPE vtType)
+{
+ HRESULT eRet = VariantClear(this);
+ OSL_ENSURE(eRet == S_OK,"Error while clearing an ado variant!");
+ vt = static_cast<VARTYPE>(VT_ARRAY|vtType);
+ parray = pSafeArray;
+}
+
+void OLEVariant::setIDispatch(IDispatch* pDispInterface)
+{
+ HRESULT eRet = VariantClear(this);
+ OSL_ENSURE(eRet == S_OK,"Error while clearing an ado variant!");
+
+ vt = VT_DISPATCH;
+ pdispVal = pDispInterface;
+
+ if ( pDispInterface )
+ pDispInterface->AddRef();
+}
+
+
+bool OLEVariant::isNull() const { return (vt == VT_NULL); }
+bool OLEVariant::isEmpty() const { return (vt == VT_EMPTY); }
+
+VARTYPE OLEVariant::getType() const { return vt; }
+
+css::util::Date OLEVariant::getDate() const
+{
+ return isNull() ? css::util::Date(30,12,1899) : ::dbtools::DBTypeConversion::toDate(getDateAsDouble(),css::util::Date(30,12,1899));
+}
+css::util::Time OLEVariant::getTime() const
+{
+ return isNull() ? css::util::Time() : ::dbtools::DBTypeConversion::toTime(getDateAsDouble());
+}
+css::util::DateTime OLEVariant::getDateTime() const
+{
+ return isNull() ? css::util::DateTime() : ::dbtools::DBTypeConversion::toDateTime(getDateAsDouble(),css::util::Date(30,12,1899));
+}
+
+VARIANT_BOOL OLEVariant::VariantBool(bool bEinBoolean)
+{
+ return (bEinBoolean ? VARIANT_TRUE : VARIANT_FALSE);
+}
+
+void OLEVariant::CHS()
+{
+ cyVal.Lo ^= sal_uInt32(-1);
+ cyVal.Hi ^= -1;
+ cyVal.Lo++;
+ if( !cyVal.Lo )
+ cyVal.Hi++;
+}
+
+void OLEVariant::set(double n)
+{
+ if( n >= 0 )
+ {
+ cyVal.Hi = static_cast<sal_Int32>(n / 4294967296.0);
+ cyVal.Lo = static_cast<sal_uInt32>(n - (static_cast<double>(cyVal.Hi) * 4294967296.0));
+ }
+ else {
+ cyVal.Hi = static_cast<sal_Int32>(-n / 4294967296.0);
+ cyVal.Lo = static_cast<sal_uInt32>(-n - (static_cast<double>(cyVal.Hi) * 4294967296.0));
+ CHS();
+ }
+}
+
+OUString OLEVariant::getString() const
+{
+ if (V_VT(this) == VT_BSTR)
+ return OUString(o3tl::toU(V_BSTR(this)));
+
+ if(isNull())
+ return OUString();
+
+ OLEVariant varDest;
+
+ varDest.ChangeType(VT_BSTR, this);
+
+ return OUString(o3tl::toU(V_BSTR(&varDest)));
+}
+
+
+void OLEVariant::ChangeType(VARTYPE vartype, const OLEVariant* pSrc)
+{
+
+ // If pDest is NULL, convert type in place
+
+ if (pSrc == nullptr)
+ pSrc = this;
+
+ if ( ( this != pSrc )
+ || ( vartype != V_VT( this ) )
+ )
+ {
+ if ( FAILED( ::VariantChangeType( static_cast< VARIANT* >( this ),
+ static_cast< const VARIANT* >( pSrc ),
+ 0,
+ vartype ) ) )
+ {
+ ::connectivity::SharedResources aResources;
+ const OUString sError( aResources.getResourceString(STR_TYPE_NOT_CONVERT));
+ throw css::sdbc::SQLException(
+ sError,
+ nullptr,
+ "S1000",
+ 1000,
+ css::uno::Any()
+ );
+ }
+ }
+}
+
+
+css::uno::Sequence< sal_Int8 > OLEVariant::getByteSequence() const
+{
+ css::uno::Sequence< sal_Int8 > aRet;
+ if(V_VT(this) == VT_BSTR)
+ {
+ aRet = css::uno::Sequence<sal_Int8>(reinterpret_cast<sal_Int8*>(V_BSTR(this)),
+ ::SysStringByteLen(V_BSTR(this)));
+ }
+ else if(!isNull())
+ {
+ SAFEARRAY* pArray = getUI1SAFEARRAYPtr();
+
+ if(pArray)
+ {
+ HRESULT hresult1,hresult2;
+ LONG lBound,uBound;
+ // Verify that the SafeArray is the proper shape.
+ hresult1 = ::SafeArrayGetLBound(pArray, 1, &lBound);
+ hresult2 = ::SafeArrayGetUBound(pArray, 1, &uBound);
+ if ( SUCCEEDED(hresult1) && SUCCEEDED(hresult2) )
+ {
+ LONG nCount = uBound-lBound+1;
+ aRet.realloc(nCount);
+ sal_Int8* pData = aRet.getArray();
+ for(; SUCCEEDED(hresult1) && lBound <= uBound ;++lBound)
+ {
+ sal_Int32 nData = 0;
+ hresult1 = ::SafeArrayGetElement(pArray,&lBound,&nData);
+ if ( SUCCEEDED(hresult1) )
+ {
+ *pData = static_cast<sal_Int8>(nData);
+ ++pData;
+ }
+ }
+ }
+ }
+ }
+
+ return aRet;
+}
+
+bool OLEVariant::getBool() const
+{
+ if (V_VT(this) == VT_BOOL)
+ return V_BOOL(this) == VARIANT_TRUE;
+ if(isNull())
+ return false;
+
+ OLEVariant varDest;
+
+ varDest.ChangeType(VT_BOOL, this);
+
+ return V_BOOL(&varDest) == VARIANT_TRUE;
+}
+
+IUnknown* OLEVariant::getIUnknown() const
+{
+ if (V_VT(this) == VT_UNKNOWN)
+ {
+ return V_UNKNOWN(this);
+ }
+ if(isNull())
+ return nullptr;
+
+ OLEVariant varDest;
+
+ varDest.ChangeType(VT_UNKNOWN, this);
+
+ V_UNKNOWN(&varDest)->AddRef();
+ return V_UNKNOWN(&varDest);
+}
+
+IDispatch* OLEVariant::getIDispatch() const
+{
+ if (V_VT(this) == VT_DISPATCH)
+ {
+ return V_DISPATCH(this);
+ }
+
+ if(isNull())
+ return nullptr;
+
+ OLEVariant varDest;
+
+ varDest.ChangeType(VT_DISPATCH, this);
+
+ V_DISPATCH(&varDest)->AddRef();
+ return V_DISPATCH(&varDest);
+}
+
+sal_uInt8 OLEVariant::getByte() const
+{
+ if (V_VT(this) == VT_UI1)
+ return V_UI1(this);
+
+ if(isNull())
+ return sal_Int8(0);
+ OLEVariant varDest;
+
+ varDest.ChangeType(VT_UI1, this);
+
+ return V_UI1(&varDest);
+}
+
+sal_Int16 OLEVariant::getInt16() const
+{
+ if (V_VT(this) == VT_I2)
+ return V_I2(this);
+
+ if(isNull())
+ return sal_Int16(0);
+ OLEVariant varDest;
+
+ varDest.ChangeType(VT_I2, this);
+
+ return V_I2(&varDest);
+}
+
+sal_Int8 OLEVariant::getInt8() const
+{
+ if (V_VT(this) == VT_I1)
+ return V_I1(this);
+
+ if(isNull())
+ return sal_Int8(0);
+
+ OLEVariant varDest;
+
+ varDest.ChangeType(VT_I1, this);
+
+ return V_I1(&varDest);
+}
+
+sal_Int32 OLEVariant::getInt32() const
+{
+ if (V_VT(this) == VT_I4)
+ return V_I4(this);
+
+ if(isNull())
+ return sal_Int32(0);
+
+ OLEVariant varDest;
+
+ varDest.ChangeType(VT_I4, this);
+
+ return V_I4(&varDest);
+}
+
+sal_uInt32 OLEVariant::getUInt32() const
+{
+ if (V_VT(this) == VT_UI4)
+ return V_UI4(this);
+
+ if(isNull())
+ return sal_uInt32(0);
+
+ OLEVariant varDest;
+
+ varDest.ChangeType(VT_UI4, this);
+
+ return V_UI4(&varDest);
+}
+
+float OLEVariant::getFloat() const
+{
+ if (V_VT(this) == VT_R4)
+ return V_R4(this);
+
+ if(isNull())
+ return float(0);
+ OLEVariant varDest;
+
+ varDest.ChangeType(VT_R4, this);
+
+ return V_R4(&varDest);
+}
+
+double OLEVariant::getDouble() const
+{
+ if (V_VT(this) == VT_R8)
+ return V_R8(this);
+
+ if(isNull())
+ return double(0);
+ OLEVariant varDest;
+
+ varDest.ChangeType(VT_R8, this);
+
+ return V_R8(&varDest);
+}
+
+double OLEVariant::getDateAsDouble() const
+{
+ if (V_VT(this) == VT_DATE)
+ return V_DATE(this);
+
+ if(isNull())
+ return double(0);
+ OLEVariant varDest;
+
+ varDest.ChangeType(VT_DATE, this);
+
+ return V_DATE(&varDest);
+}
+
+CY OLEVariant::getCurrency() const
+{
+ if (V_VT(this) == VT_CY)
+ return V_CY(this);
+
+ if(isNull())
+ {
+ CY aVar;
+ aVar.int64 = sal_Int64(0);
+ return aVar;
+ }
+ OLEVariant varDest;
+
+ varDest.ChangeType(VT_CY, this);
+
+ return V_CY(&varDest);
+}
+
+SAFEARRAY* OLEVariant::getUI1SAFEARRAYPtr() const
+{
+ if (V_VT(this) == (VT_ARRAY|VT_UI1))
+ return V_ARRAY(this);
+
+ if(isNull())
+ return nullptr;
+ OLEVariant varDest;
+
+ varDest.ChangeType((VT_ARRAY|VT_UI1), this);
+
+ return V_ARRAY(&varDest);
+}
+
+css::uno::Any OLEVariant::makeAny() const
+{
+ css::uno::Any aValue;
+ switch (V_VT(this))
+ {
+ case VT_EMPTY:
+ case VT_NULL:
+ aValue.setValue(nullptr, Type());
+ break;
+ case VT_I2:
+ aValue.setValue( & iVal, cppu::UnoType<sal_Int16>::get());
+ break;
+ case VT_I4:
+ aValue.setValue( & lVal, cppu::UnoType<sal_Int32>::get());
+ break;
+ case VT_R4:
+ aValue.setValue( & fltVal, cppu::UnoType<float>::get());
+ break;
+ case VT_R8:
+ aValue.setValue(& dblVal, cppu::UnoType<double>::get());
+ break;
+ case VT_CY:
+ {
+ Currency cy(cyVal.int64);
+ aValue <<= cy;
+ break;
+ }
+ case VT_DATE:
+ {
+ aValue <<= getDate();
+ break;
+ }
+ case VT_BSTR:
+ {
+ OUString b(o3tl::toU(bstrVal));
+ aValue.setValue( &b, cppu::UnoType<decltype(b)>::get());
+ break;
+ }
+ case VT_BOOL:
+ {
+ aValue <<= (boolVal == VARIANT_TRUE);
+ break;
+ }
+ case VT_I1:
+ aValue.setValue( & cVal, cppu::UnoType<sal_Int8>::get());
+ break;
+ case VT_UI1: // there is no unsigned char in UNO
+ aValue <<= sal_Int8(bVal);
+ break;
+ case VT_UI2:
+ aValue.setValue( & uiVal, cppu::UnoType<cppu::UnoUnsignedShortType>::get());
+ break;
+ case VT_UI4:
+ aValue.setValue( & ulVal, cppu::UnoType<sal_uInt32>::get());
+ break;
+ case VT_INT:
+ aValue.setValue( & intVal, cppu::UnoType<sal_Int32>::get());
+ break;
+ case VT_UINT:
+ aValue.setValue( & uintVal, cppu::UnoType<sal_uInt32>::get());
+ break;
+ case VT_VOID:
+ aValue.setValue( nullptr, Type());
+ break;
+ case VT_DECIMAL:
+ {
+ Decimal dec;
+ dec.Scale = decVal.scale;
+ dec.Sign = decVal.sign;
+ dec.LowValue = decVal.Lo32;
+ dec.MiddleValue = decVal.Mid32;
+ dec.HighValue = decVal.Hi32;
+ aValue <<= dec;
+ break;
+ }
+
+ default:
+ break;
+ }
+ return aValue;
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/ado/Awrapado.cxx b/connectivity/source/drivers/ado/Awrapado.cxx
new file mode 100644
index 0000000000..eebdc5d8c5
--- /dev/null
+++ b/connectivity/source/drivers/ado/Awrapado.cxx
@@ -0,0 +1,2009 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/macros.h>
+#include <ado/Awrapado.hxx>
+#include <ado/Awrapadox.hxx>
+#include <comphelper/types.hxx>
+#include <o3tl/string_view.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <sal/log.hxx>
+#include <systools/win32/oleauto.hxx>
+
+using namespace connectivity::ado;
+
+void WpADOCatalog::Create()
+{
+ pInterface.CoCreateInstance(ADOS::CLSID_ADOCATALOG_25, nullptr, CLSCTX_INPROC_SERVER);
+}
+
+
+WpADOProperties WpADOConnection::get_Properties() const
+{
+ WpADOProperties pProps;
+ pInterface->get_Properties(&pProps);
+ return pProps;
+}
+
+OUString WpADOConnection::GetConnectionString() const
+{
+ assert(pInterface);
+ sal::systools::BStr aBSTR;
+ pInterface->get_ConnectionString(&aBSTR);
+ return OUString(aBSTR);
+}
+
+bool WpADOConnection::PutConnectionString(std::u16string_view aCon) const
+{
+ assert(pInterface);
+ sal::systools::BStr bstr(aCon);
+ bool bErg = SUCCEEDED(pInterface->put_ConnectionString(bstr));
+
+ return bErg;
+}
+
+sal_Int32 WpADOConnection::GetCommandTimeout() const
+{
+ assert(pInterface);
+ sal_Int32 nRet=0;
+ pInterface->get_CommandTimeout(&nRet);
+ return nRet;
+}
+
+void WpADOConnection::PutCommandTimeout(sal_Int32 nRet)
+{
+ assert(pInterface);
+ pInterface->put_CommandTimeout(nRet);
+}
+
+sal_Int32 WpADOConnection::GetConnectionTimeout() const
+{
+ assert(pInterface);
+ sal_Int32 nRet=0;
+ pInterface->get_ConnectionTimeout(&nRet);
+ return nRet;
+}
+
+void WpADOConnection::PutConnectionTimeout(sal_Int32 nRet)
+{
+ assert(pInterface);
+ pInterface->put_ConnectionTimeout(nRet);
+}
+
+bool WpADOConnection::Close()
+{
+ assert(pInterface);
+ return (SUCCEEDED(pInterface->Close()));
+}
+
+bool WpADOConnection::Execute(std::u16string_view CommandText,OLEVariant& RecordsAffected,long Options, WpADORecordset** ppiRset)
+{
+ assert(pInterface);
+ sal::systools::BStr sStr1(CommandText);
+ bool bErg = SUCCEEDED(pInterface->Execute(sStr1,&RecordsAffected,Options,reinterpret_cast<ADORecordset**>(ppiRset)));
+ return bErg;
+}
+
+bool WpADOConnection::BeginTrans()
+{
+ assert(pInterface);
+ sal_Int32 nIso=0;
+ return SUCCEEDED(pInterface->BeginTrans(&nIso));
+}
+
+bool WpADOConnection::CommitTrans( )
+{
+ assert(pInterface);
+ return SUCCEEDED(pInterface->CommitTrans());
+}
+
+bool WpADOConnection::RollbackTrans( )
+{
+ assert(pInterface);
+ return SUCCEEDED(pInterface->RollbackTrans());
+}
+
+bool WpADOConnection::Open(std::u16string_view ConnectionString, std::u16string_view UserID,std::u16string_view Password,long Options)
+{
+ assert(pInterface);
+ sal::systools::BStr sStr1(ConnectionString);
+ sal::systools::BStr sStr2(UserID);
+ sal::systools::BStr sStr3(Password);
+ bool bErg = SUCCEEDED(pInterface->Open(sStr1, sStr2, sStr3, Options));
+ return bErg;
+}
+
+bool WpADOConnection::GetErrors(ADOErrors** pErrors)
+{
+ assert(pInterface);
+ return SUCCEEDED(pInterface->get_Errors(pErrors));
+}
+
+OUString WpADOConnection::GetDefaultDatabase() const
+{
+ assert(pInterface);
+ sal::systools::BStr aBSTR; pInterface->get_DefaultDatabase(&aBSTR);
+ return OUString(aBSTR);
+}
+
+bool WpADOConnection::PutDefaultDatabase(std::u16string_view _bstr)
+{
+ assert(pInterface);
+ sal::systools::BStr bstr(_bstr);
+ bool bErg = SUCCEEDED(pInterface->put_DefaultDatabase(bstr));
+
+ return bErg;
+}
+
+IsolationLevelEnum WpADOConnection::get_IsolationLevel() const
+{
+ assert(pInterface);
+ IsolationLevelEnum eNum=adXactUnspecified;
+ pInterface->get_IsolationLevel(&eNum);
+ return eNum;
+}
+
+bool WpADOConnection::put_IsolationLevel(const IsolationLevelEnum& eNum)
+{
+ assert(pInterface);
+ return SUCCEEDED(pInterface->put_IsolationLevel(eNum));
+}
+
+sal_Int32 WpADOConnection::get_Attributes() const
+{
+ assert(pInterface);
+ sal_Int32 nRet=0;
+ pInterface->get_Attributes(&nRet);
+ return nRet;
+}
+
+bool WpADOConnection::put_Attributes(sal_Int32 nRet)
+{
+ assert(pInterface);
+ return SUCCEEDED(pInterface->put_Attributes(nRet));
+}
+
+CursorLocationEnum WpADOConnection::get_CursorLocation() const
+{
+ assert(pInterface);
+ CursorLocationEnum eNum=adUseNone;
+ pInterface->get_CursorLocation(&eNum);
+ return eNum;
+}
+
+bool WpADOConnection::put_CursorLocation(const CursorLocationEnum &eNum)
+{
+ assert(pInterface);
+ return SUCCEEDED(pInterface->put_CursorLocation(eNum));
+}
+
+ConnectModeEnum WpADOConnection::get_Mode() const
+{
+ assert(pInterface);
+ ConnectModeEnum eNum=adModeUnknown;
+ pInterface->get_Mode(&eNum);
+ return eNum;
+}
+
+bool WpADOConnection::put_Mode(const ConnectModeEnum &eNum)
+{
+ assert(pInterface);
+ return SUCCEEDED(pInterface->put_Mode(eNum));
+}
+
+OUString WpADOConnection::get_Provider() const
+{
+ assert(pInterface);
+ sal::systools::BStr aBSTR; pInterface->get_Provider(&aBSTR);
+ return OUString(aBSTR);
+}
+
+bool WpADOConnection::put_Provider(std::u16string_view _bstr)
+{
+ assert(pInterface);
+ sal::systools::BStr bstr(_bstr);
+ return SUCCEEDED(pInterface->put_Provider(bstr));
+}
+
+sal_Int32 WpADOConnection::get_State() const
+{
+ assert(pInterface);
+ sal_Int32 nRet=0;
+ pInterface->get_State(&nRet);
+ return nRet;
+}
+
+bool WpADOConnection::OpenSchema(SchemaEnum eNum,OLEVariant const & Restrictions,OLEVariant const & SchemaID,ADORecordset**pprset)
+{
+ assert(pInterface);
+ return SUCCEEDED(pInterface->OpenSchema(eNum,Restrictions,SchemaID,pprset));
+}
+
+OUString WpADOConnection::get_Version() const
+{
+ assert(pInterface);
+ sal::systools::BStr aBSTR;
+ pInterface->get_Version(&aBSTR);
+ return OUString(aBSTR);
+}
+
+bool WpADOCommand::putref_ActiveConnection(const WpADOConnection& rCon)
+{
+ assert(pInterface);
+ return SUCCEEDED(pInterface->putref_ActiveConnection(rCon));
+}
+
+void WpADOCommand::put_ActiveConnection(/* [in] */ const OLEVariant& vConn)
+{
+ assert(pInterface);
+ pInterface->put_ActiveConnection(vConn);
+}
+
+void WpADOCommand::Create()
+{
+ sal::systools::COMReference<IClassFactory2> pInterface2;
+ if (!FAILED(pInterface2.CoGetClassObject(ADOS::CLSID_ADOCOMMAND_21, CLSCTX_INPROC_SERVER)))
+ {
+ sal::systools::COMReference<ADOCommand> pCommand;
+
+ HRESULT hr = pInterface2->CreateInstanceLic(nullptr,
+ nullptr,
+ ADOS::IID_ADOCOMMAND_21,
+ ADOS::GetKeyStr(),
+ reinterpret_cast<void**>(&pCommand));
+
+ if( !FAILED( hr ) )
+ pInterface = std::move(pCommand);
+ }
+}
+
+sal_Int32 WpADOCommand::get_State() const
+{
+ assert(pInterface);
+ sal_Int32 nRet=0;
+ pInterface->get_State(&nRet);
+ return nRet;
+}
+
+OUString WpADOCommand::get_CommandText() const
+{
+ assert(pInterface);
+ sal::systools::BStr aBSTR;
+ pInterface->get_CommandText(&aBSTR);
+ return OUString(aBSTR);
+}
+
+bool WpADOCommand::put_CommandText(std::u16string_view aCon)
+{
+ assert(pInterface);
+ sal::systools::BStr bstr(aCon);
+ bool bErg = SUCCEEDED(pInterface->put_CommandText(bstr));
+
+ return bErg;
+}
+
+sal_Int32 WpADOCommand::get_CommandTimeout() const
+{
+ assert(pInterface);
+ sal_Int32 nRet=0;
+ pInterface->get_CommandTimeout(&nRet);
+ return nRet;
+}
+
+void WpADOCommand::put_CommandTimeout(sal_Int32 nRet)
+{
+ assert(pInterface);
+ pInterface->put_CommandTimeout(nRet);
+}
+
+bool WpADOCommand::get_Prepared() const
+{
+ assert(pInterface);
+ VARIANT_BOOL bPrepared = VARIANT_FALSE;
+ pInterface->get_Prepared(&bPrepared);
+ return bPrepared == VARIANT_TRUE;
+}
+
+bool WpADOCommand::put_Prepared(VARIANT_BOOL bPrepared) const
+{
+ assert(pInterface);
+ return SUCCEEDED(pInterface->put_Prepared(bPrepared));
+}
+
+bool WpADOCommand::Execute(OLEVariant& RecordsAffected,OLEVariant& Params,long Options, ADORecordset** ppiRset)
+{
+ assert(pInterface);
+ return SUCCEEDED(pInterface->Execute(&RecordsAffected,&Params,Options,ppiRset));
+}
+
+ADOParameter* WpADOCommand::CreateParameter(std::u16string_view _bstr,DataTypeEnum Type,ParameterDirectionEnum Direction,long nSize,const OLEVariant &Value)
+{
+ assert(pInterface);
+ ADOParameter* pPara = nullptr;
+ sal::systools::BStr bstr(_bstr);
+ bool bErg = SUCCEEDED(pInterface->CreateParameter(bstr, Type, Direction, nSize, Value, &pPara));
+
+ return bErg ? pPara : nullptr;
+}
+
+ADOParameters* WpADOCommand::get_Parameters() const
+{
+ assert(pInterface);
+ ADOParameters* pPara=nullptr;
+ pInterface->get_Parameters(&pPara);
+ return pPara;
+}
+
+bool WpADOCommand::put_CommandType( /* [in] */ CommandTypeEnum lCmdType)
+{
+ assert(pInterface);
+ return SUCCEEDED(pInterface->put_CommandType(lCmdType));
+}
+
+CommandTypeEnum WpADOCommand::get_CommandType() const
+{
+ assert(pInterface);
+ CommandTypeEnum eNum=adCmdUnspecified;
+ pInterface->get_CommandType(&eNum);
+ return eNum;
+}
+
+// returns the name of the field
+OUString WpADOCommand::GetName() const
+{
+ assert(pInterface);
+ sal::systools::BStr aBSTR;
+ pInterface->get_Name(&aBSTR);
+ return OUString(aBSTR);
+}
+
+bool WpADOCommand::put_Name(std::u16string_view Name)
+{
+ assert(pInterface);
+ sal::systools::BStr bstr(Name);
+ bool bErg = SUCCEEDED(pInterface->put_Name(bstr));
+
+ return bErg;
+}
+bool WpADOCommand::Cancel()
+{
+ assert(pInterface);
+ return SUCCEEDED(pInterface->Cancel());
+}
+
+OUString WpADOError::GetDescription() const
+{
+ assert(pInterface);
+ sal::systools::BStr aBSTR;
+ pInterface->get_Description(&aBSTR);
+ return OUString(aBSTR);
+}
+
+OUString WpADOError::GetSource() const
+{
+ assert(pInterface);
+ sal::systools::BStr aBSTR;
+ pInterface->get_Source(&aBSTR);
+ return OUString(aBSTR);
+}
+
+sal_Int32 WpADOError::GetNumber() const
+{
+ assert(pInterface);
+ sal_Int32 nErrNr=0;
+ pInterface->get_Number(&nErrNr);
+ return nErrNr;
+}
+
+OUString WpADOError::GetSQLState() const
+{
+ assert(pInterface);
+ sal::systools::BStr aBSTR;
+ pInterface->get_SQLState(&aBSTR);
+ return OUString(aBSTR);
+}
+
+sal_Int32 WpADOError::GetNativeError() const
+{
+ assert(pInterface);
+ sal_Int32 nErrNr=0;
+ pInterface->get_NativeError(&nErrNr);
+ return nErrNr;
+}
+
+WpADOProperties WpADOField::get_Properties()
+{
+ assert(pInterface);
+ WpADOProperties pProps;
+ pInterface->get_Properties(&pProps);
+ return pProps;
+}
+
+sal_Int32 WpADOField::GetActualSize() const
+{
+ assert(pInterface);
+ ADO_LONGPTR nActualSize=0;
+ pInterface->get_ActualSize(&nActualSize);
+ return nActualSize;
+}
+
+sal_Int32 WpADOField::GetAttributes() const
+{
+ assert(pInterface);
+ sal_Int32 eADOSFieldAttributes=0;
+ pInterface->get_Attributes(&eADOSFieldAttributes);
+ return eADOSFieldAttributes;
+}
+
+sal_Int32 WpADOField::GetStatus() const
+{
+ assert(pInterface);
+ // pInterface->get_Status(&eADOSFieldAttributes);
+ return 0;
+}
+
+sal_Int32 WpADOField::GetDefinedSize() const
+{
+ assert(pInterface);
+ ADO_LONGPTR nDefinedSize=0;
+ pInterface->get_DefinedSize(&nDefinedSize);
+ return nDefinedSize;
+}
+
+// returns the name of the field
+OUString WpADOField::GetName() const
+{
+ assert(pInterface);
+ sal::systools::BStr aBSTR;
+ pInterface->get_Name(&aBSTR);
+ return OUString(aBSTR);
+}
+
+DataTypeEnum WpADOField::GetADOType() const
+{
+ assert(pInterface);
+ DataTypeEnum eType=adEmpty;
+ pInterface->get_Type(&eType);
+ return eType;
+}
+
+void WpADOField::get_Value(OLEVariant& aValVar) const
+{
+ assert(pInterface);
+ aValVar.setEmpty();
+ pInterface->get_Value(&aValVar);
+}
+
+OLEVariant WpADOField::get_Value() const
+{
+ assert(pInterface);
+ OLEVariant aValVar;
+ pInterface->get_Value(&aValVar);
+ return aValVar;
+}
+
+bool WpADOField::PutValue(const OLEVariant& aVariant)
+{
+ assert(pInterface);
+ return (SUCCEEDED(pInterface->put_Value(aVariant)));
+}
+
+sal_Int32 WpADOField::GetPrecision() const
+{
+ assert(pInterface);
+ sal_uInt8 eType=0;
+ pInterface->get_Precision(&eType);
+ return eType;
+}
+
+sal_Int32 WpADOField::GetNumericScale() const
+{
+ assert(pInterface);
+ sal_uInt8 eType=0;
+ pInterface->get_NumericScale(&eType);
+ return eType;
+}
+
+bool WpADOField::AppendChunk(const OLEVariant& Variant)
+{
+ assert(pInterface);
+ return (SUCCEEDED(pInterface->AppendChunk(Variant)));
+}
+
+OLEVariant WpADOField::GetChunk(long Length) const
+{
+ assert(pInterface);
+ OLEVariant aValVar;
+ pInterface->GetChunk(Length,&aValVar);
+ return aValVar;
+}
+
+void WpADOField::GetChunk(long Length,OLEVariant &aValVar) const
+{
+ assert(pInterface);
+ pInterface->GetChunk(Length,&aValVar);
+}
+
+OLEVariant WpADOField::GetOriginalValue() const
+{
+ assert(pInterface);
+ OLEVariant aValVar;
+ pInterface->get_OriginalValue(&aValVar);
+ return aValVar;
+}
+
+void WpADOField::GetOriginalValue(OLEVariant &aValVar) const
+{
+ assert(pInterface);
+ pInterface->get_OriginalValue(&aValVar);
+}
+
+OLEVariant WpADOField::GetUnderlyingValue() const
+{
+ assert(pInterface);
+ OLEVariant aValVar;
+ pInterface->get_UnderlyingValue(&aValVar);
+ return aValVar;
+}
+
+void WpADOField::GetUnderlyingValue(OLEVariant &aValVar) const
+{
+ assert(pInterface);
+ pInterface->get_UnderlyingValue(&aValVar);
+}
+
+bool WpADOField::PutPrecision(sal_Int8 _prec)
+{
+ assert(pInterface);
+ return (SUCCEEDED(pInterface->put_Precision(_prec)));
+}
+
+bool WpADOField::PutNumericScale(sal_Int8 _prec)
+{
+ assert(pInterface);
+ return (SUCCEEDED(pInterface->put_NumericScale(_prec)));
+}
+
+void WpADOField::PutADOType(DataTypeEnum eType)
+{
+ assert(pInterface);
+ pInterface->put_Type(eType);
+}
+
+bool WpADOField::PutDefinedSize(sal_Int32 _nDefSize)
+{
+ assert(pInterface);
+ return (SUCCEEDED(pInterface->put_DefinedSize(_nDefSize)));
+}
+
+bool WpADOField::PutAttributes(sal_Int32 _nDefSize)
+{
+ assert(pInterface);
+ return (SUCCEEDED(pInterface->put_Attributes(_nDefSize)));
+}
+
+OLEVariant WpADOProperty::GetValue() const
+{
+ OLEVariant aValVar;
+ if(pInterface)
+ pInterface->get_Value(&aValVar);
+ return aValVar;
+}
+
+void WpADOProperty::GetValue(OLEVariant &aValVar) const
+{
+ assert(pInterface);
+ if(pInterface)
+ pInterface->get_Value(&aValVar);
+}
+
+bool WpADOProperty::PutValue(const OLEVariant &aValVar)
+{
+ assert(pInterface);
+ return (SUCCEEDED(pInterface->put_Value(aValVar)));
+}
+
+OUString WpADOProperty::GetName() const
+{
+ assert(pInterface);
+ sal::systools::BStr aBSTR;
+ pInterface->get_Name(&aBSTR);
+ return OUString(aBSTR);
+}
+
+DataTypeEnum WpADOProperty::GetADOType() const
+{
+ assert(pInterface);
+ DataTypeEnum eType=adEmpty;
+ pInterface->get_Type(&eType);
+ return eType;
+}
+
+sal_Int32 WpADOProperty::GetAttributes() const
+{
+ assert(pInterface);
+ sal_Int32 eADOSFieldAttributes=0;
+ pInterface->get_Attributes(&eADOSFieldAttributes);
+ return eADOSFieldAttributes;
+}
+
+bool WpADOProperty::PutAttributes(sal_Int32 _nDefSize)
+{
+ assert(pInterface);
+ return (SUCCEEDED(pInterface->put_Attributes(_nDefSize)));
+}
+ void WpADORecordset::Create()
+{
+ sal::systools::COMReference<IClassFactory2> pInterface2;
+ if (!FAILED(pInterface2.CoGetClassObject(ADOS::CLSID_ADORECORDSET_21, CLSCTX_INPROC_SERVER)))
+ {
+ sal::systools::COMReference<ADORecordset> pRec;
+ HRESULT hr = pInterface2->CreateInstanceLic(nullptr,
+ nullptr,
+ ADOS::IID_ADORECORDSET_21,
+ ADOS::GetKeyStr(),
+ reinterpret_cast<void**>(&pRec));
+
+ if( !FAILED( hr ) )
+ pInterface = std::move(pRec);
+ }
+}
+
+bool WpADORecordset::Open(
+ /* [optional][in] */ VARIANT Source,
+ /* [optional][in] */ VARIANT ActiveConnection,
+ /* [defaultvalue][in] */ CursorTypeEnum CursorType,
+ /* [defaultvalue][in] */ LockTypeEnum LockType,
+ /* [defaultvalue][in] */ sal_Int32 Options)
+{
+ assert(pInterface);
+ return (SUCCEEDED(pInterface->Open(Source,ActiveConnection,CursorType,LockType,Options)));
+}
+
+
+LockTypeEnum WpADORecordset::GetLockType()
+{
+ assert(pInterface);
+ LockTypeEnum eType=adLockUnspecified;
+ pInterface->get_LockType(&eType);
+ return eType;
+}
+
+void WpADORecordset::Close()
+{
+ assert(pInterface);
+ pInterface->Close();
+}
+
+bool WpADORecordset::Cancel() const
+{
+ assert(pInterface);
+ return (SUCCEEDED(pInterface->Cancel()));
+}
+
+sal_Int32 WpADORecordset::get_State()
+{
+ assert(pInterface);
+ sal_Int32 nState = 0;
+ pInterface->get_State(&nState);
+ return nState;
+}
+
+bool WpADORecordset::Supports( /* [in] */ CursorOptionEnum CursorOptions)
+{
+ assert(pInterface);
+ VARIANT_BOOL bSupports=VARIANT_FALSE;
+ pInterface->Supports(CursorOptions,&bSupports);
+ return bSupports == VARIANT_TRUE;
+}
+
+PositionEnum_Param WpADORecordset::get_AbsolutePosition()
+{
+ assert(pInterface);
+ PositionEnum_Param aTemp=adPosUnknown;
+ pInterface->get_AbsolutePosition(&aTemp);
+ return aTemp;
+}
+
+void WpADORecordset::GetDataSource(IUnknown** _pInterface) const
+{
+ assert(pInterface);
+ pInterface->get_DataSource(_pInterface);
+}
+
+void WpADORecordset::PutRefDataSource(IUnknown* _pInterface)
+{
+ assert(pInterface);
+ pInterface->putref_DataSource(_pInterface);
+}
+
+void WpADORecordset::GetBookmark(VARIANT& var)
+{
+ assert(pInterface);
+ pInterface->get_Bookmark(&var);
+}
+
+OLEVariant WpADORecordset::GetBookmark()
+{
+ assert(pInterface);
+ OLEVariant var;
+ pInterface->get_Bookmark(&var);
+ return var;
+}
+
+CompareEnum WpADORecordset::CompareBookmarks(const OLEVariant& left,const OLEVariant& right)
+{
+ assert(pInterface);
+ CompareEnum eNum=adCompareNotComparable;
+ pInterface->CompareBookmarks(left,right,&eNum);
+ return eNum;
+}
+
+bool WpADORecordset::SetBookmark(const OLEVariant &pSafeAr)
+{
+ assert(pInterface);
+ return SUCCEEDED(pInterface->put_Bookmark(pSafeAr));
+}
+
+
+WpADOFields WpADORecordset::GetFields() const
+{
+ assert(pInterface);
+ WpADOFields pFields;
+ pInterface->get_Fields(&pFields);
+ return pFields;
+}
+
+
+bool WpADORecordset::Move(sal_Int32 nRows, VARIANT aBmk) {return pInterface && SUCCEEDED(pInterface->Move(nRows, aBmk));}
+bool WpADORecordset::MoveNext() {return pInterface && SUCCEEDED(pInterface->MoveNext());}
+bool WpADORecordset::MovePrevious() {return pInterface && SUCCEEDED(pInterface->MovePrevious());}
+bool WpADORecordset::MoveFirst() {return pInterface && SUCCEEDED(pInterface->MoveFirst());}
+bool WpADORecordset::MoveLast() {return pInterface && SUCCEEDED(pInterface->MoveLast());}
+
+bool WpADORecordset::IsAtBOF() const
+{
+ assert(pInterface);
+ VARIANT_BOOL bIsAtBOF=VARIANT_FALSE;
+ pInterface->get_BOF(&bIsAtBOF);
+ return bIsAtBOF == VARIANT_TRUE;
+}
+
+bool WpADORecordset::IsAtEOF() const
+{
+ assert(pInterface);
+ VARIANT_BOOL bIsAtEOF=VARIANT_FALSE;
+ pInterface->get_EOF(&bIsAtEOF);
+ return bIsAtEOF == VARIANT_TRUE;
+}
+
+bool WpADORecordset::Delete(AffectEnum eNum)
+{
+ assert(pInterface);
+ return SUCCEEDED(pInterface->Delete(eNum));
+}
+
+bool WpADORecordset::AddNew(const OLEVariant &FieldList,const OLEVariant &Values)
+{
+ assert(pInterface);
+ return SUCCEEDED(pInterface->AddNew(FieldList,Values));
+}
+
+bool WpADORecordset::Update(const OLEVariant &FieldList,const OLEVariant &Values)
+{
+ assert(pInterface);
+ return SUCCEEDED(pInterface->Update(FieldList,Values));
+}
+
+bool WpADORecordset::CancelUpdate()
+{
+ assert(pInterface);
+ return SUCCEEDED(pInterface->CancelUpdate());
+}
+
+WpADOProperties WpADORecordset::get_Properties() const
+{
+ assert(pInterface);
+ WpADOProperties pProps;
+ pInterface->get_Properties(&pProps);
+ return pProps;
+}
+
+bool WpADORecordset::NextRecordset(OLEVariant& RecordsAffected,ADORecordset** ppiRset)
+{
+ assert(pInterface);
+ return SUCCEEDED(pInterface->NextRecordset(&RecordsAffected,ppiRset));
+}
+
+bool WpADORecordset::get_RecordCount(ADO_LONGPTR &_nRet) const
+{
+ assert(pInterface);
+ return SUCCEEDED(pInterface->get_RecordCount(&_nRet));
+}
+
+bool WpADORecordset::get_MaxRecords(ADO_LONGPTR &_nRet) const
+{
+ assert(pInterface);
+ return SUCCEEDED(pInterface->get_MaxRecords(&_nRet));
+}
+
+bool WpADORecordset::put_MaxRecords(ADO_LONGPTR _nRet)
+{
+ assert(pInterface);
+ return SUCCEEDED(pInterface->put_MaxRecords(_nRet));
+}
+
+bool WpADORecordset::get_CursorType(CursorTypeEnum &_nRet) const
+{
+ assert(pInterface);
+ return SUCCEEDED(pInterface->get_CursorType(&_nRet));
+}
+
+bool WpADORecordset::put_CursorType(CursorTypeEnum _nRet)
+{
+ assert(pInterface);
+ return SUCCEEDED(pInterface->put_CursorType(_nRet));
+}
+
+bool WpADORecordset::get_LockType(LockTypeEnum &_nRet) const
+{
+ assert(pInterface);
+ return SUCCEEDED(pInterface->get_LockType(&_nRet));
+}
+
+bool WpADORecordset::put_LockType(LockTypeEnum _nRet)
+{
+ assert(pInterface);
+ return SUCCEEDED(pInterface->put_LockType(_nRet));
+}
+
+bool WpADORecordset::get_CacheSize(sal_Int32 &_nRet) const
+{
+ assert(pInterface);
+ return SUCCEEDED(pInterface->get_CacheSize(&_nRet));
+}
+
+bool WpADORecordset::put_CacheSize(sal_Int32 _nRet)
+{
+ assert(pInterface);
+ return SUCCEEDED(pInterface->put_CacheSize(_nRet));
+}
+
+bool WpADORecordset::UpdateBatch(AffectEnum AffectRecords)
+{
+ assert(pInterface);
+ return SUCCEEDED(pInterface->UpdateBatch(AffectRecords));
+}
+
+OUString WpADOParameter::GetName() const
+{
+ assert(pInterface);
+ sal::systools::BStr aBSTR;
+ pInterface->get_Name(&aBSTR);
+ return OUString(aBSTR);
+}
+
+DataTypeEnum WpADOParameter::GetADOType() const
+{
+ assert(pInterface);
+ DataTypeEnum eType=adEmpty;
+ pInterface->get_Type(&eType);
+ return eType;
+}
+
+void WpADOParameter::put_Type(const DataTypeEnum& _eType)
+{
+ assert(pInterface);
+ pInterface->put_Type(_eType);
+}
+
+sal_Int32 WpADOParameter::GetAttributes() const
+{
+ assert(pInterface);
+ sal_Int32 eADOSFieldAttributes=0;
+ pInterface->get_Attributes(&eADOSFieldAttributes);
+ return eADOSFieldAttributes;
+}
+
+sal_Int32 WpADOParameter::GetPrecision() const
+{
+ assert(pInterface);
+ sal_uInt8 eType=0;
+ pInterface->get_Precision(&eType);
+ return eType;
+}
+
+sal_Int32 WpADOParameter::GetNumericScale() const
+{
+ assert(pInterface);
+ sal_uInt8 eType=0;
+ pInterface->get_NumericScale(&eType);
+ return eType;
+}
+
+ParameterDirectionEnum WpADOParameter::get_Direction() const
+{
+ assert(pInterface);
+ ParameterDirectionEnum alParmDirection=adParamUnknown;
+ pInterface->get_Direction(&alParmDirection);
+ return alParmDirection;
+}
+
+void WpADOParameter::GetValue(OLEVariant& aValVar) const
+{
+ assert(pInterface);
+ pInterface->get_Value(&aValVar);
+}
+
+OLEVariant WpADOParameter::GetValue() const
+{
+ assert(pInterface);
+ OLEVariant aValVar;
+ pInterface->get_Value(&aValVar);
+ return aValVar;
+}
+
+bool WpADOParameter::PutValue(const OLEVariant& aVariant)
+{
+ assert(pInterface);
+ return (SUCCEEDED(pInterface->put_Value(aVariant)));
+}
+bool WpADOParameter::AppendChunk(const OLEVariant& aVariant)
+{
+ assert(pInterface);
+ return (SUCCEEDED(pInterface->AppendChunk(aVariant)));
+}
+bool WpADOParameter::put_Size(sal_Int32 _nSize)
+{
+ assert(pInterface);
+ return (SUCCEEDED(pInterface->put_Size(_nSize)));
+}
+
+OUString WpADOColumn::get_Name() const
+{
+ assert(pInterface);
+ sal::systools::BStr aBSTR;
+ pInterface->get_Name(&aBSTR);
+ return OUString(aBSTR);
+}
+
+OUString WpADOColumn::get_RelatedColumn() const
+{
+ assert(pInterface);
+ sal::systools::BStr aBSTR;
+ pInterface->get_RelatedColumn(&aBSTR);
+ return OUString(aBSTR);
+}
+
+void WpADOColumn::put_Name(std::u16string_view _rName)
+{
+ assert(pInterface);
+ sal::systools::BStr bstr(_rName);
+ pInterface->put_Name(bstr);
+}
+void WpADOColumn::put_RelatedColumn(std::u16string_view _rName)
+{
+ assert(pInterface);
+ sal::systools::BStr bstr(_rName);
+ pInterface->put_RelatedColumn(bstr);
+}
+
+DataTypeEnum WpADOColumn::get_Type() const
+{
+ assert(pInterface);
+ DataTypeEnum eNum = adVarChar;
+ pInterface->get_Type(&eNum);
+ return eNum;
+}
+
+void WpADOColumn::put_Type(const DataTypeEnum& _eNum)
+{
+ assert(pInterface);
+ pInterface->put_Type(_eNum);
+}
+
+sal_Int32 WpADOColumn::get_Precision() const
+{
+ assert(pInterface);
+ sal_Int32 nPrec=0;
+ pInterface->get_Precision(&nPrec);
+ return nPrec;
+}
+
+void WpADOColumn::put_Precision(sal_Int32 _nPre)
+{
+ assert(pInterface);
+ pInterface->put_Precision(_nPre);
+}
+
+sal_Int32 WpADOColumn::get_DefinedSize() const
+{
+ assert(pInterface);
+ sal_Int32 nPrec=0;
+ pInterface->get_DefinedSize(&nPrec);
+ return nPrec;
+}
+sal_uInt8 WpADOColumn::get_NumericScale() const
+{
+ assert(pInterface);
+ sal_uInt8 nPrec=0;
+ pInterface->get_NumericScale(&nPrec);
+ return nPrec;
+}
+
+void WpADOColumn::put_NumericScale(sal_Int8 _nScale)
+{
+ assert(pInterface);
+ pInterface->put_NumericScale(_nScale);
+}
+
+SortOrderEnum WpADOColumn::get_SortOrder() const
+{
+ assert(pInterface);
+ SortOrderEnum nPrec=adSortAscending;
+ pInterface->get_SortOrder(&nPrec);
+ return nPrec;
+}
+
+void WpADOColumn::put_SortOrder(SortOrderEnum _nScale)
+{
+ assert(pInterface);
+ pInterface->put_SortOrder(_nScale);
+}
+
+ColumnAttributesEnum WpADOColumn::get_Attributes() const
+{
+ assert(pInterface);
+ ColumnAttributesEnum eNum=adColNullable;
+ pInterface->get_Attributes(&eNum);
+ return eNum;
+}
+
+bool WpADOColumn::put_Attributes(const ColumnAttributesEnum& _eNum)
+{
+ assert(pInterface);
+ return SUCCEEDED(pInterface->put_Attributes(_eNum));
+}
+
+WpADOProperties WpADOColumn::get_Properties() const
+{
+ assert(pInterface);
+ WpADOProperties pProps;
+ pInterface->get_Properties(&pProps);
+ return pProps;
+}
+
+OUString WpADOKey::get_Name() const
+{
+ assert(pInterface);
+ sal::systools::BStr aBSTR;
+ pInterface->get_Name(&aBSTR);
+ return OUString(aBSTR);
+}
+
+void WpADOKey::put_Name(std::u16string_view _rName)
+{
+ assert(pInterface);
+ sal::systools::BStr bstr(_rName);
+ pInterface->put_Name(bstr);
+}
+
+KeyTypeEnum WpADOKey::get_Type() const
+{
+ assert(pInterface);
+ KeyTypeEnum eNum=adKeyPrimary;
+ pInterface->get_Type(&eNum);
+ return eNum;
+}
+
+void WpADOKey::put_Type(const KeyTypeEnum& _eNum)
+{
+ assert(pInterface);
+ pInterface->put_Type(_eNum);
+}
+
+OUString WpADOKey::get_RelatedTable() const
+{
+ assert(pInterface);
+ sal::systools::BStr aBSTR;
+ pInterface->get_RelatedTable(&aBSTR);
+ return OUString(aBSTR);
+}
+
+void WpADOKey::put_RelatedTable(std::u16string_view _rName)
+{
+ assert(pInterface);
+ sal::systools::BStr bstr(_rName);
+ pInterface->put_RelatedTable(bstr);
+}
+
+RuleEnum WpADOKey::get_DeleteRule() const
+{
+ assert(pInterface);
+ RuleEnum eNum = adRINone;
+ pInterface->get_DeleteRule(&eNum);
+ return eNum;
+}
+
+void WpADOKey::put_DeleteRule(const RuleEnum& _eNum)
+{
+ assert(pInterface);
+ pInterface->put_DeleteRule(_eNum);
+}
+
+RuleEnum WpADOKey::get_UpdateRule() const
+{
+ assert(pInterface);
+ RuleEnum eNum = adRINone;
+ pInterface->get_UpdateRule(&eNum);
+ return eNum;
+}
+
+void WpADOKey::put_UpdateRule(const RuleEnum& _eNum)
+{
+ assert(pInterface);
+ pInterface->put_UpdateRule(_eNum);
+}
+
+WpADOColumns WpADOKey::get_Columns() const
+{
+ assert(pInterface);
+ WpADOColumns pCols;
+ pInterface->get_Columns(&pCols);
+ return pCols;
+}
+
+OUString WpADOIndex::get_Name() const
+{
+ assert(pInterface);
+ sal::systools::BStr aBSTR;
+ pInterface->get_Name(&aBSTR);
+ return OUString(aBSTR);
+}
+
+void WpADOIndex::put_Name(std::u16string_view _rName)
+{
+ assert(pInterface);
+ sal::systools::BStr bstr(_rName);
+ pInterface->put_Name(bstr);
+}
+
+bool WpADOIndex::get_Clustered() const
+{
+ assert(pInterface);
+ VARIANT_BOOL eNum = VARIANT_FALSE;
+ pInterface->get_Clustered(&eNum);
+ return eNum == VARIANT_TRUE;
+}
+
+void WpADOIndex::put_Clustered(bool _b)
+{
+ assert(pInterface);
+ pInterface->put_Clustered(_b ? VARIANT_TRUE : VARIANT_FALSE);
+}
+
+bool WpADOIndex::get_Unique() const
+{
+ assert(pInterface);
+ VARIANT_BOOL eNum = VARIANT_FALSE;
+ pInterface->get_Unique(&eNum);
+ return eNum == VARIANT_TRUE;
+}
+
+void WpADOIndex::put_Unique(bool _b)
+{
+ assert(pInterface);
+ pInterface->put_Unique(_b ? VARIANT_TRUE : VARIANT_FALSE);
+}
+
+bool WpADOIndex::get_PrimaryKey() const
+{
+ assert(pInterface);
+ VARIANT_BOOL eNum = VARIANT_FALSE;
+ pInterface->get_PrimaryKey(&eNum);
+ return eNum == VARIANT_TRUE;
+}
+
+void WpADOIndex::put_PrimaryKey(bool _b)
+{
+ assert(pInterface);
+ pInterface->put_PrimaryKey(_b ? VARIANT_TRUE : VARIANT_FALSE);
+}
+
+WpADOColumns WpADOIndex::get_Columns() const
+{
+ assert(pInterface);
+ WpADOColumns pCols;
+ pInterface->get_Columns(&pCols);
+ return pCols;
+}
+
+void WpADOCatalog::putref_ActiveConnection(IDispatch* pCon)
+{
+ assert(pInterface);
+ pInterface->putref_ActiveConnection(pCon);
+}
+
+WpADOTables WpADOCatalog::get_Tables()
+{
+ assert(pInterface);
+ WpADOTables pRet;
+ pInterface->get_Tables(&pRet);
+ return pRet;
+}
+
+WpADOViews WpADOCatalog::get_Views()
+{
+ assert(pInterface);
+ WpADOViews pRet;
+ pInterface->get_Views(&pRet);
+ return pRet;
+}
+
+WpADOGroups WpADOCatalog::get_Groups()
+{
+ assert(pInterface);
+ WpADOGroups pRet;
+ pInterface->get_Groups(&pRet);
+ return pRet;
+}
+
+WpADOUsers WpADOCatalog::get_Users()
+{
+ assert(pInterface);
+ WpADOUsers pRet;
+ pInterface->get_Users(&pRet);
+ return pRet;
+}
+
+ADOProcedures* WpADOCatalog::get_Procedures()
+{
+ assert(pInterface);
+ ADOProcedures* pRet = nullptr;
+ pInterface->get_Procedures(&pRet);
+ return pRet;
+}
+
+OUString WpADOTable::get_Name() const
+{
+ assert(pInterface);
+ sal::systools::BStr aBSTR;
+ pInterface->get_Name(&aBSTR);
+ return OUString(aBSTR);
+}
+
+void WpADOTable::put_Name(std::u16string_view _rName)
+{
+ assert(pInterface);
+ sal::systools::BStr bstr(_rName);
+ pInterface->put_Name(bstr);
+}
+
+OUString WpADOTable::get_Type() const
+{
+ assert(pInterface);
+ sal::systools::BStr aBSTR;
+ pInterface->get_Type(&aBSTR);
+ return OUString(aBSTR);
+}
+
+WpADOColumns WpADOTable::get_Columns() const
+{
+ assert(pInterface);
+ WpADOColumns pCols;
+ pInterface->get_Columns(&pCols);
+ return pCols;
+}
+
+WpADOIndexes WpADOTable::get_Indexes() const
+{
+ assert(pInterface);
+ WpADOIndexes pRet;
+ pInterface->get_Indexes(&pRet);
+ return pRet;
+}
+
+WpADOKeys WpADOTable::get_Keys() const
+{
+ assert(pInterface);
+ WpADOKeys pRet;
+ pInterface->get_Keys(&pRet);
+ return pRet;
+}
+
+WpADOCatalog WpADOTable::get_ParentCatalog() const
+{
+ assert(pInterface);
+ WpADOCatalog pCat;
+ pInterface->get_ParentCatalog(&pCat);
+ return pCat;
+}
+
+WpADOProperties WpADOTable::get_Properties() const
+{
+ assert(pInterface);
+ WpADOProperties pProps;
+ pInterface->get_Properties(&pProps);
+ return pProps;
+}
+
+OUString WpADOView::get_Name() const
+{
+ assert(pInterface);
+ sal::systools::BStr aBSTR;
+ pInterface->get_Name(&aBSTR);
+ return OUString(aBSTR);
+}
+
+void WpADOView::get_Command(OLEVariant& _rVar) const
+{
+ assert(pInterface);
+ pInterface->get_Command(&_rVar);
+}
+
+void WpADOView::put_Command(OLEVariant const & _rVar)
+{
+ assert(pInterface);
+ pInterface->put_Command(_rVar);
+}
+
+OUString WpADOGroup::get_Name() const
+{
+ sal::systools::BStr aBSTR;
+ pInterface->get_Name(&aBSTR);
+ return OUString(aBSTR);
+}
+
+void WpADOGroup::put_Name(std::u16string_view _rName)
+{
+ sal::systools::BStr bstr(_rName);
+ pInterface->put_Name(bstr);
+}
+
+RightsEnum WpADOGroup::GetPermissions(
+ /* [in] */ const OLEVariant& Name,
+ /* [in] */ ObjectTypeEnum ObjectType)
+{
+ RightsEnum Rights=adRightNone;
+ OLEVariant ObjectTypeId;
+ ObjectTypeId.setNoArg();
+ pInterface->GetPermissions(Name,ObjectType,ObjectTypeId,&Rights);
+ return Rights;
+}
+
+bool WpADOGroup::SetPermissions(
+ /* [in] */ const OLEVariant& Name,
+ /* [in] */ ObjectTypeEnum ObjectType,
+ /* [in] */ ActionEnum Action,
+ /* [in] */ RightsEnum Rights)
+{
+ OLEVariant ObjectTypeId;
+ ObjectTypeId.setNoArg();
+ return SUCCEEDED(pInterface->SetPermissions(Name,ObjectType,Action,Rights,adInheritNone,ObjectTypeId));
+}
+
+WpADOUsers WpADOGroup::get_Users( )
+{
+ WpADOUsers pRet;
+ pInterface->get_Users( &pRet);
+ return pRet;
+}
+
+OUString WpADOUser::get_Name() const
+{
+ sal::systools::BStr aBSTR;
+ pInterface->get_Name(&aBSTR);
+ return OUString(aBSTR);
+}
+
+void WpADOUser::put_Name(std::u16string_view _rName)
+{
+ sal::systools::BStr bstr(_rName);
+ pInterface->put_Name(bstr);
+}
+
+bool WpADOUser::ChangePassword(std::u16string_view _rPwd,std::u16string_view _rNewPwd)
+{
+ sal::systools::BStr sStr1(_rPwd);
+ sal::systools::BStr sStr2(_rNewPwd);
+ bool bErg = SUCCEEDED(pInterface->ChangePassword(sStr1, sStr2));
+ return bErg;
+}
+
+WpADOGroups WpADOUser::get_Groups()
+{
+ WpADOGroups pRet;
+ pInterface->get_Groups(&pRet);
+ return pRet;
+}
+
+RightsEnum WpADOUser::GetPermissions(
+ /* [in] */ const OLEVariant& Name,
+ /* [in] */ ObjectTypeEnum ObjectType)
+{
+ RightsEnum Rights=adRightNone;
+ OLEVariant ObjectTypeId;
+ ObjectTypeId.setNoArg();
+ pInterface->GetPermissions(Name,ObjectType,ObjectTypeId,&Rights);
+ return Rights;
+}
+
+bool WpADOUser::SetPermissions(
+ /* [in] */ const OLEVariant& Name,
+ /* [in] */ ObjectTypeEnum ObjectType,
+ /* [in] */ ActionEnum Action,
+ /* [in] */ RightsEnum Rights)
+{
+ OLEVariant ObjectTypeId;
+ ObjectTypeId.setNoArg();
+ return SUCCEEDED(pInterface->SetPermissions(Name,ObjectType,Action,Rights,adInheritNone,ObjectTypeId));
+}
+
+ADORecordset* WpADOConnection::getExportedKeys( const css::uno::Any& catalog, const OUString& schema, std::u16string_view table )
+{
+ // Create elements used in the array
+ SAFEARRAYBOUND rgsabound[1];
+ SAFEARRAY *psa = nullptr;
+ OLEVariant varCriteria[6];
+
+ // Create SafeArray Bounds and initialize the array
+ rgsabound[0].lLbound = 0;
+ rgsabound[0].cElements = std::size(varCriteria);
+ psa = SafeArrayCreate( VT_VARIANT, 1, rgsabound );
+
+ sal_Int32 nPos=0;
+ if(catalog.hasValue())
+ varCriteria[nPos].setString(::comphelper::getString(catalog));
+
+ SafeArrayPutElement(psa,&nPos,&varCriteria[nPos]);nPos++;// TABLE_CATALOG
+ if(schema.getLength() && schema.toChar() != '%')
+ varCriteria[nPos].setString(schema);
+ SafeArrayPutElement(psa,&nPos,&varCriteria[nPos]);nPos++;// TABLE_SCHEMA
+
+ varCriteria[nPos].setString(table);
+ SafeArrayPutElement(psa,&nPos,&varCriteria[nPos]);nPos++;// TABLE_NAME
+
+ SafeArrayPutElement(psa,&nPos,&varCriteria[nPos]);nPos++;// TABLE_CATALOG
+ SafeArrayPutElement(psa,&nPos,&varCriteria[nPos]);nPos++;// TABLE_SCHEMA
+ SafeArrayPutElement(psa,&nPos,&varCriteria[nPos]);nPos++;// TABLE_NAME
+
+ OLEVariant vtEmpty;
+ vtEmpty.setNoArg();
+
+ // Initialize and fill the SafeArray
+ OLEVariant vsa;
+ vsa.setArray(psa,VT_VARIANT);
+
+ ADORecordset *pRecordset = nullptr;
+ OpenSchema(adSchemaForeignKeys,vsa,vtEmpty,&pRecordset);
+ return pRecordset;
+}
+
+ADORecordset* WpADOConnection::getImportedKeys( const css::uno::Any& catalog, const OUString& schema, std::u16string_view table )
+{
+ // Create elements used in the array
+ SAFEARRAYBOUND rgsabound[1];
+ SAFEARRAY *psa = nullptr;
+ OLEVariant varCriteria[6];
+
+ // Create SafeArray Bounds and initialize the array
+ rgsabound[0].lLbound = 0;
+ rgsabound[0].cElements = std::size(varCriteria);
+ psa = SafeArrayCreate( VT_VARIANT, 1, rgsabound );
+
+ sal_Int32 nPos=0;
+ SafeArrayPutElement(psa,&nPos,&varCriteria[nPos]);nPos++;// TABLE_CATALOG
+ SafeArrayPutElement(psa,&nPos,&varCriteria[nPos]);nPos++;// TABLE_SCHEMA
+ SafeArrayPutElement(psa,&nPos,&varCriteria[nPos]);nPos++;// TABLE_NAME
+
+ if(catalog.hasValue())
+ varCriteria[nPos].setString(::comphelper::getString(catalog));
+
+ SafeArrayPutElement(psa,&nPos,&varCriteria[nPos]);nPos++;// TABLE_CATALOG
+ if(schema.getLength() && schema.toChar() != '%')
+ varCriteria[nPos].setString(schema);
+ SafeArrayPutElement(psa,&nPos,&varCriteria[nPos]);nPos++;// TABLE_SCHEMA
+
+ varCriteria[nPos].setString(table);
+ SafeArrayPutElement(psa,&nPos,&varCriteria[nPos]);nPos++;// TABLE_NAME
+
+ OLEVariant vtEmpty;
+ vtEmpty.setNoArg();
+
+ // Initialize and fill the SafeArray
+ OLEVariant vsa;
+ vsa.setArray(psa,VT_VARIANT);
+
+ ADORecordset *pRecordset = nullptr;
+ OpenSchema(adSchemaForeignKeys,vsa,vtEmpty,&pRecordset);
+
+ return pRecordset;
+
+}
+
+ADORecordset* WpADOConnection::getPrimaryKeys( const css::uno::Any& catalog, const OUString& schema, std::u16string_view table )
+{
+ // Create elements used in the array
+ SAFEARRAYBOUND rgsabound[1];
+ SAFEARRAY *psa = nullptr;
+ OLEVariant varCriteria[3];
+
+ // Create SafeArray Bounds and initialize the array
+ rgsabound[0].lLbound = 0;
+ rgsabound[0].cElements = std::size(varCriteria);
+ psa = SafeArrayCreate( VT_VARIANT, 1, rgsabound );
+
+ sal_Int32 nPos=0;
+ if(catalog.hasValue())
+ varCriteria[nPos].setString(::comphelper::getString(catalog));
+
+ SafeArrayPutElement(psa,&nPos,&varCriteria[nPos]);nPos++;// TABLE_CATALOG
+ if(schema.getLength() && schema.toChar() != '%')
+ varCriteria[nPos].setString(schema);
+ SafeArrayPutElement(psa,&nPos,&varCriteria[nPos]);nPos++;// TABLE_SCHEMA
+
+ varCriteria[nPos].setString(table);
+ SafeArrayPutElement(psa,&nPos,&varCriteria[nPos]);nPos++;// TABLE_NAME
+
+
+ OLEVariant vtEmpty;
+ vtEmpty.setNoArg();
+
+ // Initialize and fill the SafeArray
+ OLEVariant vsa;
+ vsa.setArray(psa,VT_VARIANT);
+
+ ADORecordset *pRecordset = nullptr;
+ OpenSchema(adSchemaPrimaryKeys,vsa,vtEmpty,&pRecordset);
+
+ return pRecordset;
+}
+
+ADORecordset* WpADOConnection::getIndexInfo(
+ const css::uno::Any& catalog, const OUString& schema, std::u16string_view table,
+ bool /*unique*/, bool /*approximate*/ )
+{
+ // Create elements used in the array
+ SAFEARRAYBOUND rgsabound[1];
+ SAFEARRAY *psa = nullptr;
+ OLEVariant varCriteria[5];
+
+ // Create SafeArray Bounds and initialize the array
+ rgsabound[0].lLbound = 0;
+ rgsabound[0].cElements = std::size(varCriteria);
+ psa = SafeArrayCreate( VT_VARIANT, 1, rgsabound );
+
+ sal_Int32 nPos=0;
+ if(catalog.hasValue())
+ varCriteria[nPos].setString(::comphelper::getString(catalog));
+
+ SafeArrayPutElement(psa,&nPos,&varCriteria[nPos]);nPos++;// TABLE_CATALOG
+ if(schema.getLength() && schema.toChar() != '%')
+ varCriteria[nPos].setString(schema);
+ SafeArrayPutElement(psa,&nPos,&varCriteria[nPos]);nPos++;// TABLE_SCHEMA
+
+ SafeArrayPutElement(psa,&nPos,&varCriteria[nPos]);nPos++;// INDEX_NAME
+
+ SafeArrayPutElement(psa,&nPos,&varCriteria[nPos]);nPos++;// TYPE
+
+ varCriteria[nPos].setString(table);
+ SafeArrayPutElement(psa,&nPos,&varCriteria[nPos]);nPos++;// TABLE_NAME
+
+ OLEVariant vtEmpty;
+ vtEmpty.setNoArg();
+
+ // Initialize and fill the SafeArray
+ OLEVariant vsa;
+ vsa.setArray(psa,VT_VARIANT);
+
+ ADORecordset *pRecordset = nullptr;
+ OpenSchema(adSchemaIndexes,vsa,vtEmpty,&pRecordset);
+
+ return pRecordset;
+}
+
+ADORecordset* WpADOConnection::getTablePrivileges( const css::uno::Any& catalog,
+ const OUString& schemaPattern,
+ std::u16string_view tableNamePattern )
+{
+ SAFEARRAYBOUND rgsabound[1];
+ SAFEARRAY *psa = nullptr;
+ OLEVariant varCriteria[5];
+
+ // Create SafeArray Bounds and initialize the array
+ rgsabound[0].lLbound = 0;
+ rgsabound[0].cElements = std::size(varCriteria);
+ psa = SafeArrayCreate( VT_VARIANT, 1, rgsabound );
+
+ sal_Int32 nPos=0;
+ if(catalog.hasValue())
+ varCriteria[nPos].setString(::comphelper::getString(catalog));
+
+ SafeArrayPutElement(psa,&nPos,&varCriteria[nPos]);nPos++;// TABLE_CATALOG
+ if(schemaPattern.getLength() && schemaPattern.toChar() != '%')
+ varCriteria[nPos].setString(schemaPattern);
+ SafeArrayPutElement(psa,&nPos,&varCriteria[nPos]);nPos++;// TABLE_SCHEMA
+
+ if(!o3tl::starts_with(tableNamePattern, u"%"))
+ varCriteria[nPos].setString(tableNamePattern);
+ SafeArrayPutElement(psa,&nPos,&varCriteria[nPos]);nPos++;// TABLE_NAME
+
+ SafeArrayPutElement(psa,&nPos,&varCriteria[nPos]);nPos++;// GRANTOR
+ SafeArrayPutElement(psa,&nPos,&varCriteria[nPos]);nPos++;// GRANTEE
+
+ OLEVariant vtEmpty;
+ vtEmpty.setNoArg();
+
+ // Initialize and fill the SafeArray
+ OLEVariant vsa;
+ vsa.setArray(psa,VT_VARIANT);
+
+ ADORecordset *pRecordset = nullptr;
+ OpenSchema(adSchemaTablePrivileges,vsa,vtEmpty,&pRecordset);
+
+ return pRecordset;
+}
+
+ADORecordset* WpADOConnection::getCrossReference( const css::uno::Any& primaryCatalog,
+ const OUString& primarySchema,
+ std::u16string_view primaryTable,
+ const css::uno::Any& foreignCatalog,
+ const OUString& foreignSchema,
+ std::u16string_view foreignTable)
+{
+ // Create elements used in the array
+ SAFEARRAYBOUND rgsabound[1];
+ SAFEARRAY *psa = nullptr;
+ OLEVariant varCriteria[6];
+
+ // Create SafeArray Bounds and initialize the array
+ rgsabound[0].lLbound = 0;
+ rgsabound[0].cElements = std::size(varCriteria);
+ psa = SafeArrayCreate( VT_VARIANT, 1, rgsabound );
+
+ sal_Int32 nPos=0;
+ if(primaryCatalog.hasValue())
+ varCriteria[nPos].setString(::comphelper::getString(primaryCatalog));
+
+ SafeArrayPutElement(psa,&nPos,&varCriteria[nPos]);nPos++;// TABLE_CATALOG
+ if(primarySchema.getLength() && primarySchema.toChar() != '%')
+ varCriteria[nPos].setString(primarySchema);
+ SafeArrayPutElement(psa,&nPos,&varCriteria[nPos]);nPos++;// TABLE_SCHEMA
+
+ varCriteria[nPos].setString(primaryTable);
+ SafeArrayPutElement(psa,&nPos,&varCriteria[nPos]);nPos++;// TABLE_NAME
+
+ if(foreignCatalog.hasValue())
+ varCriteria[nPos].setString(::comphelper::getString(foreignCatalog));
+
+ SafeArrayPutElement(psa,&nPos,&varCriteria[nPos]);nPos++;// TABLE_CATALOG
+ if(foreignSchema.getLength() && foreignSchema.toChar() != '%')
+ varCriteria[nPos].setString(foreignSchema);
+ SafeArrayPutElement(psa,&nPos,&varCriteria[nPos]);nPos++;// TABLE_SCHEMA
+
+ varCriteria[nPos].setString(foreignTable);
+ SafeArrayPutElement(psa,&nPos,&varCriteria[nPos]);nPos++;// TABLE_NAME
+
+ OLEVariant vtEmpty;
+ vtEmpty.setNoArg();
+
+ // Initialize and fill the SafeArray
+ OLEVariant vsa;
+ vsa.setArray(psa,VT_VARIANT);
+
+ ADORecordset *pRecordset = nullptr;
+ OpenSchema(adSchemaForeignKeys,vsa,vtEmpty,&pRecordset);
+
+ return pRecordset;
+}
+
+ADORecordset* WpADOConnection::getProcedures( const css::uno::Any& catalog,
+ const OUString& schemaPattern,
+ std::u16string_view procedureNamePattern )
+{
+ SAFEARRAYBOUND rgsabound[1];
+ SAFEARRAY *psa = nullptr;
+ OLEVariant varCriteria[3];
+
+ // Create SafeArray Bounds and initialize the array
+ rgsabound[0].lLbound = 0;
+ rgsabound[0].cElements = std::size(varCriteria);
+ psa = SafeArrayCreate( VT_VARIANT, 1, rgsabound );
+
+ sal_Int32 nPos=0;
+ if(catalog.hasValue())
+ varCriteria[nPos].setString(::comphelper::getString(catalog));
+
+ SafeArrayPutElement(psa,&nPos,&varCriteria[nPos]);nPos++;// TABLE_CATALOG
+ if(schemaPattern.getLength() && schemaPattern.toChar() != '%')
+ varCriteria[nPos].setString(schemaPattern);
+ SafeArrayPutElement(psa,&nPos,&varCriteria[nPos]);nPos++;// TABLE_SCHEMA
+
+ if(!o3tl::starts_with(procedureNamePattern, u"%"))
+ varCriteria[nPos].setString(procedureNamePattern);
+ SafeArrayPutElement(psa,&nPos,&varCriteria[nPos]);nPos++;// TABLE_NAME
+
+ OLEVariant vtEmpty;
+ vtEmpty.setNoArg();
+
+ // Initialize and fill the SafeArray
+ OLEVariant vsa;
+ vsa.setArray(psa,VT_VARIANT);
+
+ ADORecordset *pRecordset = nullptr;
+ OpenSchema(adSchemaProcedures,vsa,vtEmpty,&pRecordset);
+
+ return pRecordset;
+}
+
+ADORecordset* WpADOConnection::getProcedureColumns( const css::uno::Any& catalog,
+ const OUString& schemaPattern,
+ std::u16string_view procedureNamePattern,
+ std::u16string_view columnNamePattern )
+{
+ // Create elements used in the array
+ SAFEARRAYBOUND rgsabound[1];
+ SAFEARRAY *psa = nullptr;
+ OLEVariant varCriteria[4];
+
+ // Create SafeArray Bounds and initialize the array
+ rgsabound[0].lLbound = 0;
+ rgsabound[0].cElements = std::size(varCriteria);
+ psa = SafeArrayCreate( VT_VARIANT, 1, rgsabound );
+
+ sal_Int32 nPos=0;
+ if(catalog.hasValue())
+ varCriteria[nPos].setString(::comphelper::getString(catalog));
+
+ SafeArrayPutElement(psa,&nPos,&varCriteria[nPos]);nPos++;// TABLE_CATALOG
+ if(schemaPattern.getLength() && schemaPattern.toChar() != '%')
+ varCriteria[nPos].setString(schemaPattern);
+ SafeArrayPutElement(psa,&nPos,&varCriteria[nPos]);nPos++;// TABLE_SCHEMA
+
+ if(!o3tl::starts_with(procedureNamePattern, u"%"))
+ varCriteria[nPos].setString(procedureNamePattern);
+ SafeArrayPutElement(psa,&nPos,&varCriteria[nPos]);nPos++;// TABLE_NAME
+
+ if(!o3tl::starts_with(columnNamePattern, u"%"))
+ varCriteria[nPos].setString(columnNamePattern);
+ SafeArrayPutElement(psa,&nPos,&varCriteria[nPos]);nPos++;// COLUMN_NAME
+
+ OLEVariant vtEmpty;
+ vtEmpty.setNoArg();
+
+ // Initialize and fill the SafeArray
+ OLEVariant vsa;
+ vsa.setArray(psa,VT_VARIANT);
+
+ ADORecordset *pRecordset = nullptr;
+ OpenSchema(adSchemaProcedureParameters,vsa,vtEmpty,&pRecordset);
+
+ return pRecordset;
+}
+
+ADORecordset* WpADOConnection::getTables( const css::uno::Any& catalog,
+ const OUString& schemaPattern,
+ std::u16string_view tableNamePattern,
+ const css::uno::Sequence< OUString >& types )
+{
+ // Create elements used in the array
+ HRESULT hr = S_OK;
+ OLEVariant varCriteria[4];
+
+ sal_Int32 nPos=0;
+ OUString sCatalog;
+ if ( catalog.hasValue() && (catalog >>= sCatalog) )
+ varCriteria[nPos].setString(sCatalog);
+
+ ++nPos;
+ if(schemaPattern.getLength() && schemaPattern.toChar() != '%')
+ varCriteria[nPos].setString(schemaPattern);
+
+ ++nPos;
+ if(!o3tl::starts_with(tableNamePattern, u"%"))
+ varCriteria[nPos].setString(tableNamePattern);
+
+ ++nPos;
+ OUStringBuffer aTypes;
+ const OUString* pIter = types.getConstArray();
+ const OUString* pEnd = pIter + types.getLength();
+ for( ; pIter != pEnd ; ++pIter)
+ {
+ if ( aTypes.getLength() )
+ aTypes.append(",");
+ aTypes.append(*pIter);
+ }
+
+ OUString sTypeNames = aTypes.makeStringAndClear();
+ if ( sTypeNames.getLength() )
+ varCriteria[nPos].setString(sTypeNames);
+
+ // Create SafeArray Bounds and initialize the array
+ const sal_Int32 nCrit = std::size(varCriteria);
+ SAFEARRAYBOUND rgsabound[1];
+ rgsabound[0].lLbound = 0;
+ rgsabound[0].cElements = nCrit;
+ SAFEARRAY *psa = SafeArrayCreate( VT_VARIANT, 1, rgsabound );
+
+ // Set the values for each element of the array
+ for( LONG i = 0 ; i < nCrit && SUCCEEDED( hr );i++)
+ {
+ hr = SafeArrayPutElement(psa, &i,&varCriteria[i]);
+ }
+
+ OLEVariant vtEmpty;
+ vtEmpty.setNoArg();
+
+ // Initialize and fill the SafeArray
+ OLEVariant vsa;
+ vsa.setArray(psa,VT_VARIANT);
+
+ ADORecordset *pRecordset = nullptr;
+ OpenSchema(adSchemaTables,vsa,vtEmpty,&pRecordset);
+
+ return pRecordset;
+}
+
+ADORecordset* WpADOConnection::getColumns( const css::uno::Any& catalog,
+ const OUString& schemaPattern,
+ std::u16string_view tableNamePattern,
+ std::u16string_view columnNamePattern )
+{
+ // Create elements used in the array
+ SAFEARRAYBOUND rgsabound[1];
+ SAFEARRAY *psa = nullptr;
+ OLEVariant varCriteria[4];
+
+ // Create SafeArray Bounds and initialize the array
+ rgsabound[0].lLbound = 0;
+ rgsabound[0].cElements = std::size(varCriteria);
+ psa = SafeArrayCreate( VT_VARIANT, 1, rgsabound );
+
+ sal_Int32 nPos=0;
+ if(catalog.hasValue())
+ varCriteria[nPos].setString(::comphelper::getString(catalog));
+
+ SafeArrayPutElement(psa,&nPos,&varCriteria[nPos]);nPos++;// TABLE_CATALOG
+ if(schemaPattern.getLength() && schemaPattern.toChar() != '%')
+ varCriteria[nPos].setString(schemaPattern);
+ SafeArrayPutElement(psa,&nPos,&varCriteria[nPos]);nPos++;// TABLE_SCHEMA
+
+ if(!o3tl::starts_with(tableNamePattern, u"%"))
+ varCriteria[nPos].setString(tableNamePattern);
+ SafeArrayPutElement(psa,&nPos,&varCriteria[nPos]);nPos++;// TABLE_NAME
+
+ varCriteria[nPos].setString(columnNamePattern);
+ SafeArrayPutElement(psa,&nPos,&varCriteria[nPos]);nPos++;// COLUMN_NAME
+
+ OLEVariant vtEmpty;
+ vtEmpty.setNoArg();
+
+ // Initialize and fill the SafeArray
+ OLEVariant vsa;
+ vsa.setArray(psa,VT_VARIANT);
+
+ ADORecordset *pRecordset = nullptr;
+ OpenSchema(adSchemaColumns,vsa,vtEmpty,&pRecordset);
+
+ return pRecordset;
+}
+
+ADORecordset* WpADOConnection::getColumnPrivileges( const css::uno::Any& catalog,
+ const OUString& schema,
+ std::u16string_view table,
+ std::u16string_view columnNamePattern )
+{
+ // Create elements used in the array
+ SAFEARRAYBOUND rgsabound[1];
+ SAFEARRAY *psa = nullptr;
+ OLEVariant varCriteria[4];
+
+ // Create SafeArray Bounds and initialize the array
+ rgsabound[0].lLbound = 0;
+ rgsabound[0].cElements = std::size(varCriteria);
+ psa = SafeArrayCreate( VT_VARIANT, 1, rgsabound );
+
+ sal_Int32 nPos=0;
+ if(catalog.hasValue())
+ varCriteria[nPos].setString(::comphelper::getString(catalog));
+
+ SafeArrayPutElement(psa,&nPos,&varCriteria[nPos]);nPos++;// TABLE_CATALOG
+ if(schema.getLength() && schema.toChar() != '%')
+ varCriteria[nPos].setString(schema);
+ SafeArrayPutElement(psa,&nPos,&varCriteria[nPos]);nPos++;// TABLE_SCHEMA
+
+ varCriteria[nPos].setString(table);
+ SafeArrayPutElement(psa,&nPos,&varCriteria[nPos]);nPos++;// TABLE_NAME
+
+ varCriteria[nPos].setString(columnNamePattern);
+ SafeArrayPutElement(psa,&nPos,&varCriteria[nPos]);nPos++;// COLUMN_NAME
+
+ OLEVariant vtEmpty;
+ vtEmpty.setNoArg();
+
+ // Initialize and fill the SafeArray
+ OLEVariant vsa;
+ vsa.setArray(psa,VT_VARIANT);
+
+ ADORecordset *pRecordset = nullptr;
+ OpenSchema(adSchemaColumnPrivileges,vsa,vtEmpty,&pRecordset);
+
+ return pRecordset;
+}
+
+ADORecordset* WpADOConnection::getTypeInfo(DataTypeEnum /*_eType*/)
+{
+ // Create elements used in the array
+ OLEVariant varCriteria[2];
+ const int nCrit = std::size(varCriteria);
+ // Create SafeArray Bounds and initialize the array
+ SAFEARRAYBOUND rgsabound[1];
+ rgsabound[0].lLbound = 0;
+ rgsabound[0].cElements = nCrit;
+ SAFEARRAY *psa = SafeArrayCreate( VT_VARIANT, 1, rgsabound );
+
+ sal_Int32 nPos = 0;
+ SafeArrayPutElement(psa,&nPos,&varCriteria[nPos]);nPos++;
+ SafeArrayPutElement(psa,&nPos,&varCriteria[nPos]);nPos++;
+
+ // Initialize and fill the SafeArray
+ OLEVariant vsa;
+ vsa.setArray(psa,VT_VARIANT);
+
+ OLEVariant aEmpty;
+ aEmpty.setNoArg();
+
+ ADORecordset *pRec=nullptr;
+ OpenSchema(adSchemaProviderTypes,vsa,aEmpty,&pRec);
+
+ return pRec;
+}
+
+void WpADOColumn::put_ParentCatalog(/* [in] */ _ADOCatalog __RPC_FAR *ppvObject)
+{
+ assert(pInterface);
+ bool bRet = SUCCEEDED(pInterface->put_ParentCatalog(ppvObject));
+ SAL_WARN_IF(!bRet, "connectivity.ado", "Could not set ParentCatalog!");
+}
+
+void WpADOTable::putref_ParentCatalog(/* [in] */ _ADOCatalog __RPC_FAR *ppvObject)
+{
+ assert(pInterface);
+ bool bRet = SUCCEEDED(pInterface->putref_ParentCatalog(ppvObject));
+ SAL_WARN_IF(!bRet, "connectivity.ado", "Could not set ParentCatalog!");
+}
+
+void OTools::putValue(const WpADOProperties& _rProps,const OLEVariant &_aPosition,const OLEVariant &_aValVar)
+{
+ SAL_WARN_IF(!_rProps.IsValid(), "connectivity.ado", "Properties are not valid!");
+ WpADOProperty aProp(_rProps.GetItem(_aPosition));
+ if ( aProp.IsValid() )
+ {
+ bool bRet = aProp.PutValue(_aValVar);
+ SAL_WARN_IF(!bRet, "connectivity.ado", "Could not put value!");
+ }
+}
+
+OLEVariant OTools::getValue(const WpADOProperties& _rProps,const OLEVariant &_aPosition)
+{
+ WpADOProperty aProp(_rProps.GetItem(_aPosition));
+ return aProp.GetValue();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/ado/ado.component b/connectivity/source/drivers/ado/ado.component
new file mode 100644
index 0000000000..7c97fb2d85
--- /dev/null
+++ b/connectivity/source/drivers/ado/ado.component
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ -->
+
+<component loader="com.sun.star.loader.SharedLibrary" environment="@CPPU_ENV@:affine"
+ xmlns="http://openoffice.org/2010/uno-components">
+ <implementation name="com.sun.star.comp.sdbc.ado.ODriver"
+ constructor="connectivity_ado_ODriver_get_implementation">
+ <service name="com.sun.star.sdbc.Driver"/>
+ <service name="com.sun.star.sdbcx.Driver"/>
+ </implementation>
+</component>
diff --git a/connectivity/source/drivers/ado/adoimp.cxx b/connectivity/source/drivers/ado/adoimp.cxx
new file mode 100644
index 0000000000..0f0d022681
--- /dev/null
+++ b/connectivity/source/drivers/ado/adoimp.cxx
@@ -0,0 +1,325 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/sdbcx/Privilege.hpp>
+#include <com/sun/star/sdbcx/PrivilegeObject.hpp>
+#include <connectivity/dbexception.hxx>
+#include <ado/Awrapado.hxx>
+#include <ado/adoimp.hxx>
+#include <osl/diagnose.h>
+#include <systools/win32/oleauto.hxx>
+#include <com/sun/star/sdbc/DataType.hpp>
+
+
+using namespace connectivity::ado;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::sdbc;
+using namespace com::sun::star::sdbcx;
+
+
+#define MYADOID(l) {l, 0,0x10,{0x80,0,0,0xAA,0,0x6D,0x2E,0xA4}};
+
+const CLSID ADOS::CLSID_ADOCONNECTION_21 = MYADOID(0x00000514);
+const IID ADOS::IID_ADOCONNECTION_21 = MYADOID(0x00000550);
+
+const CLSID ADOS::CLSID_ADOCOMMAND_21 = MYADOID(0x00000507);
+const IID ADOS::IID_ADOCOMMAND_21 = MYADOID(0x0000054E);
+
+const CLSID ADOS::CLSID_ADORECORDSET_21 = MYADOID(0x00000535);
+const IID ADOS::IID_ADORECORDSET_21 = MYADOID(0x0000054F);
+
+const CLSID ADOS::CLSID_ADOCATALOG_25 = MYADOID(0x00000602);
+const IID ADOS::IID_ADOCATALOG_25 = MYADOID(0x00000603);
+
+const CLSID ADOS::CLSID_ADOINDEX_25 = MYADOID(0x0000061E);
+const IID ADOS::IID_ADOINDEX_25 = MYADOID(0x0000061F);
+
+const CLSID ADOS::CLSID_ADOTABLE_25 = MYADOID(0x00000609);
+const IID ADOS::IID_ADOTABLE_25 = MYADOID(0x00000610);
+
+const CLSID ADOS::CLSID_ADOKEY_25 = MYADOID(0x00000621);
+const IID ADOS::IID_ADOKEY_25 = MYADOID(0x00000622);
+
+const CLSID ADOS::CLSID_ADOCOLUMN_25 = MYADOID(0x0000061B);
+const IID ADOS::IID_ADOCOLUMN_25 = MYADOID(0x0000061C);
+
+const CLSID ADOS::CLSID_ADOGROUP_25 = MYADOID(0x00000615);
+const IID ADOS::IID_ADOGROUP_25 = MYADOID(0x00000616);
+
+const CLSID ADOS::CLSID_ADOUSER_25 = MYADOID(0x00000618);
+const IID ADOS::IID_ADOUSER_25 = MYADOID(0x00000619);
+
+const CLSID ADOS::CLSID_ADOVIEW_25 = MYADOID(0x00000612);
+const IID ADOS::IID_ADOVIEW_25 = MYADOID(0x00000613);
+
+sal::systools::BStr& ADOS::GetKeyStr()
+{
+ static sal::systools::BStr sKeyStr(u"gxwaezucfyqpwjgqbcmtsncuhwsnyhiohwxz");
+ return sKeyStr;
+}
+
+
+sal_Int32 ADOS::MapADOType2Jdbc(DataTypeEnum eType)
+{
+ sal_Int32 nType = DataType::VARCHAR;
+ switch (eType)
+ {
+ case adUnsignedSmallInt:
+ case adSmallInt: nType = DataType::SMALLINT; break;
+ case adUnsignedInt:
+ case adInteger: nType = DataType::INTEGER; break;
+ case adUnsignedBigInt:
+ case adBigInt: nType = DataType::BIGINT; break;
+ case adSingle: nType = DataType::FLOAT; break;
+ case adDouble: nType = DataType::DOUBLE; break;
+ case adCurrency: nType = DataType::DOUBLE; break;
+ case adVarNumeric:
+ case adNumeric: nType = DataType::NUMERIC; break;
+ case adDecimal: nType = DataType::DECIMAL; break;
+ case adDBDate: nType = DataType::DATE; break;
+ case adDBTime: nType = DataType::TIME; break;
+ case adDate:
+ case adDBTimeStamp: nType = DataType::TIMESTAMP; break;
+ case adBoolean: nType = DataType::BOOLEAN; break;
+// case adArray: nType = DataType::ARRAY; break;
+ case adBinary: nType = DataType::BINARY; break;
+ case adGUID: nType = DataType::OBJECT; break;
+ case adBSTR:
+ case adVarWChar:
+ case adWChar:
+ case adVarChar: nType = DataType::VARCHAR; break;
+ case adLongVarWChar:
+ case adLongVarChar: nType = DataType::LONGVARCHAR; break;
+ case adVarBinary: nType = DataType::VARBINARY; break;
+ case adLongVarBinary: nType = DataType::LONGVARBINARY;break;
+ case adChar: nType = DataType::CHAR; break;
+ case adUnsignedTinyInt:
+ case adTinyInt: nType = DataType::TINYINT; break;
+ case adEmpty: nType = DataType::SQLNULL; break;
+ case adUserDefined:
+ case adPropVariant:
+ case adFileTime:
+ case adChapter:
+ case adIDispatch:
+ case adIUnknown:
+ case adError:
+ case adVariant:
+ nType = DataType::OTHER; break;
+ default:
+ OSL_FAIL("MapADOType2Jdbc: Unknown Type!");
+ ;
+ }
+ return nType;
+}
+
+DataTypeEnum ADOS::MapJdbc2ADOType(sal_Int32 _nType,sal_Int32 _nJetEngine)
+{
+ switch (_nType)
+ {
+ case DataType::SMALLINT: return adSmallInt; break;
+ case DataType::INTEGER: return adInteger; break;
+ case DataType::BIGINT: return adBigInt; break;
+ case DataType::FLOAT: return adSingle; break;
+ case DataType::DOUBLE: return adDouble; break;
+ case DataType::NUMERIC: return adNumeric; break;
+ case DataType::DECIMAL: return adDecimal; break;
+ case DataType::DATE: return isJetEngine(_nJetEngine) ? adDate : adDBDate; break;
+ case DataType::TIME: return adDBTime; break;
+ case DataType::TIMESTAMP: return isJetEngine(_nJetEngine) ? adDate : adDBTimeStamp; break;
+ case DataType::BOOLEAN:
+ case DataType::BIT: return adBoolean; break;
+ case DataType::BINARY: return adBinary; break;
+ case DataType::VARCHAR: return adVarWChar; break;
+ case DataType::CLOB:
+ case DataType::LONGVARCHAR: return adLongVarWChar; break;
+ case DataType::VARBINARY: return adVarBinary; break;
+ case DataType::BLOB:
+ case DataType::LONGVARBINARY: return adLongVarBinary; break;
+ case DataType::CHAR: return adWChar; break;
+ case DataType::TINYINT: return isJetEngine(_nJetEngine) ? adUnsignedTinyInt : adTinyInt;break;
+ case DataType::OBJECT: return adGUID; break;
+ default:
+ OSL_FAIL("MapJdbc2ADOType: Unknown Type!");
+ ;
+ }
+ return adEmpty;
+}
+
+const int JET_ENGINETYPE_UNKNOWN = 0;
+const int JET_ENGINETYPE_JET10 = 1;
+const int JET_ENGINETYPE_JET11 = 2;
+const int JET_ENGINETYPE_JET20 = 3;
+const int JET_ENGINETYPE_JET3X = 4;
+const int JET_ENGINETYPE_JET4X = 5;
+const int JET_ENGINETYPE_DBASE3 = 10;
+const int JET_ENGINETYPE_DBASE4 = 11;
+const int JET_ENGINETYPE_DBASE5 = 12;
+const int JET_ENGINETYPE_EXCEL30 = 20;
+const int JET_ENGINETYPE_EXCEL40 = 21;
+const int JET_ENGINETYPE_EXCEL50 = 22;
+const int JET_ENGINETYPE_EXCEL80 = 23;
+const int JET_ENGINETYPE_EXCEL90 = 24;
+const int JET_ENGINETYPE_EXCHANGE4 = 30;
+const int JET_ENGINETYPE_LOTUSWK1 = 40;
+const int JET_ENGINETYPE_LOTUSWK3 = 41;
+const int JET_ENGINETYPE_LOTUSWK4 = 42;
+const int JET_ENGINETYPE_PARADOX3X = 50;
+const int JET_ENGINETYPE_PARADOX4X = 51;
+const int JET_ENGINETYPE_PARADOX5X = 52;
+const int JET_ENGINETYPE_PARADOX7X = 53;
+const int JET_ENGINETYPE_TEXT1X = 60;
+const int JET_ENGINETYPE_HTML1X = 70;
+
+bool ADOS::isJetEngine(sal_Int32 _nEngineType)
+{
+ bool bRet = false;
+ switch(_nEngineType)
+ {
+ case JET_ENGINETYPE_UNKNOWN:
+ case JET_ENGINETYPE_JET10:
+ case JET_ENGINETYPE_JET11:
+ case JET_ENGINETYPE_JET20:
+ case JET_ENGINETYPE_JET3X:
+ case JET_ENGINETYPE_JET4X:
+ case JET_ENGINETYPE_DBASE3:
+ case JET_ENGINETYPE_DBASE4:
+ case JET_ENGINETYPE_DBASE5:
+ case JET_ENGINETYPE_EXCEL30:
+ case JET_ENGINETYPE_EXCEL40:
+ case JET_ENGINETYPE_EXCEL50:
+ case JET_ENGINETYPE_EXCEL80:
+ case JET_ENGINETYPE_EXCEL90:
+ case JET_ENGINETYPE_EXCHANGE4:
+ case JET_ENGINETYPE_LOTUSWK1:
+ case JET_ENGINETYPE_LOTUSWK3:
+ case JET_ENGINETYPE_LOTUSWK4:
+ case JET_ENGINETYPE_PARADOX3X:
+ case JET_ENGINETYPE_PARADOX4X:
+ case JET_ENGINETYPE_PARADOX5X:
+ case JET_ENGINETYPE_PARADOX7X:
+ case JET_ENGINETYPE_TEXT1X:
+ case JET_ENGINETYPE_HTML1X:
+ bRet = true;
+ break;
+ }
+ return bRet;
+}
+
+ObjectTypeEnum ADOS::mapObjectType2Ado(sal_Int32 objType)
+{
+ ObjectTypeEnum eType = adPermObjTable;
+ switch(objType)
+ {
+ case PrivilegeObject::TABLE:
+ eType = adPermObjTable;
+ break;
+ case PrivilegeObject::VIEW:
+ eType = adPermObjView;
+ break;
+ case PrivilegeObject::COLUMN:
+ eType = adPermObjColumn;
+ break;
+ }
+ return eType;
+}
+
+sal_Int32 ADOS::mapAdoType2Object(ObjectTypeEnum objType)
+{
+ sal_Int32 nType = PrivilegeObject::TABLE;
+ switch(objType)
+ {
+ case adPermObjTable:
+ nType = PrivilegeObject::TABLE;
+ break;
+ case adPermObjView:
+ nType = PrivilegeObject::VIEW;
+ break;
+ case adPermObjColumn:
+ nType = PrivilegeObject::COLUMN;
+ break;
+ default:
+ OSL_FAIL( "ADOS::mapAdoType2Object: privilege type cannot be translated!" );
+ break;
+ }
+ return nType;
+}
+#ifdef DELETE
+#undef DELETE
+#endif
+
+sal_Int32 ADOS::mapAdoRights2Sdbc(RightsEnum eRights)
+{
+ sal_Int32 nRights = 0;
+ if((eRights & adRightInsert) == adRightInsert)
+ nRights |= Privilege::INSERT;
+ if((eRights & adRightDelete) == adRightDelete)
+ nRights |= css::sdbcx::Privilege::DELETE;
+ if((eRights & adRightUpdate) == adRightUpdate)
+ nRights |= Privilege::UPDATE;
+ if((eRights & adRightWriteDesign) == adRightWriteDesign)
+ nRights |= Privilege::ALTER;
+ if((eRights & adRightRead) == adRightRead)
+ nRights |= Privilege::SELECT;
+ if((eRights & adRightReference) == adRightReference)
+ nRights |= Privilege::REFERENCE;
+ if((eRights & adRightDrop) == adRightDrop)
+ nRights |= Privilege::DROP;
+
+ return nRights;
+}
+
+sal_Int32 ADOS::mapRights2Ado(sal_Int32 nRights)
+{
+ sal_Int32 eRights = adRightNone;
+
+ if((nRights & Privilege::INSERT) == Privilege::INSERT)
+ eRights |= adRightInsert;
+ if((nRights & Privilege::DELETE) == Privilege::DELETE)
+ eRights |= adRightDelete;
+ if((nRights & Privilege::UPDATE) == Privilege::UPDATE)
+ eRights |= adRightUpdate;
+ if((nRights & Privilege::ALTER) == Privilege::ALTER)
+ eRights |= adRightWriteDesign;
+ if((nRights & Privilege::SELECT) == Privilege::SELECT)
+ eRights |= adRightRead;
+ if((nRights & Privilege::REFERENCE) == Privilege::REFERENCE)
+ eRights |= adRightReference;
+ if((nRights & Privilege::DROP) == Privilege::DROP)
+ eRights |= adRightDrop;
+
+ return eRights;
+}
+
+WpADOField ADOS::getField(ADORecordset* _pRecordSet,sal_Int32 _nColumnIndex)
+{
+ if ( !_pRecordSet )
+ return WpADOField();
+
+ WpOLEAppendCollection<ADOFields, WpADOField> aFields;
+ _pRecordSet->get_Fields(&aFields);
+ if(_nColumnIndex <= 0 || _nColumnIndex > aFields.GetItemCount())
+ ::dbtools::throwInvalidIndexException(nullptr);
+ WpADOField aField(aFields.GetItem(_nColumnIndex-1));
+ if(!aField.IsValid())
+ ::dbtools::throwInvalidIndexException(nullptr);
+ return aField;
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/calc/CCatalog.cxx b/connectivity/source/drivers/calc/CCatalog.cxx
new file mode 100644
index 0000000000..03c4358b9b
--- /dev/null
+++ b/connectivity/source/drivers/calc/CCatalog.cxx
@@ -0,0 +1,62 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <calc/CCatalog.hxx>
+#include <calc/CConnection.hxx>
+#include <calc/CTables.hxx>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XResultSet.hpp>
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::container;
+
+using namespace connectivity::calc;
+
+OCalcCatalog::OCalcCatalog(OCalcConnection* _pCon)
+ : file::OFileCatalog(_pCon)
+{
+}
+
+void OCalcCatalog::refreshTables()
+{
+ ::std::vector<OUString> aVector;
+ Sequence<OUString> aTypes;
+ OCalcConnection::ODocHolder aDocHolder(static_cast<OCalcConnection*>(m_pConnection));
+ Reference<XResultSet> xResult = m_xMetaData->getTables(Any(), "%", "%", aTypes);
+
+ if (xResult.is())
+ {
+ Reference<XRow> xRow(xResult, UNO_QUERY);
+ while (xResult->next())
+ aVector.push_back(xRow->getString(3));
+ }
+ if (m_pTables)
+ m_pTables->reFill(aVector);
+ else
+ m_pTables.reset(new OCalcTables(m_xMetaData, *this, m_aMutex, aVector));
+
+ // this avoids that the document will be loaded a 2nd time when one table will be accessed.
+ //if ( m_pTables && m_pTables->hasElements() )
+ // m_pTables->getByIndex(0);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/calc/CConnection.cxx b/connectivity/source/drivers/calc/CConnection.cxx
new file mode 100644
index 0000000000..f4f1b409e2
--- /dev/null
+++ b/connectivity/source/drivers/calc/CConnection.cxx
@@ -0,0 +1,264 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <calc/CConnection.hxx>
+#include <calc/CDatabaseMetaData.hxx>
+#include <calc/CCatalog.hxx>
+#include <calc/CDriver.hxx>
+#include <resource/sharedresources.hxx>
+#include <com/sun/star/frame/Desktop.hpp>
+#include <com/sun/star/sheet/XSpreadsheetDocument.hpp>
+#include <tools/urlobj.hxx>
+#include <component/CPreparedStatement.hxx>
+#include <component/CStatement.hxx>
+#include <unotools/pathoptions.hxx>
+#include <connectivity/dbexception.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+#include <strings.hrc>
+
+using namespace connectivity::calc;
+using namespace connectivity::file;
+
+typedef connectivity::file::OConnection OConnection_BASE;
+
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::frame;
+using namespace ::com::sun::star::sheet;
+
+
+OCalcConnection::OCalcConnection(ODriver* _pDriver) : OConnection(_pDriver),m_nDocCount(0)
+{
+ // m_aFilenameExtension is not used
+}
+
+OCalcConnection::~OCalcConnection()
+{
+}
+
+void OCalcConnection::construct(const OUString& url,const Sequence< PropertyValue >& info)
+{
+ // open file
+
+ sal_Int32 nLen = url.indexOf(':');
+ nLen = url.indexOf(':',nLen+1);
+ OUString aDSN(url.copy(nLen+1));
+
+ m_aFileName = aDSN;
+ INetURLObject aURL;
+ aURL.SetSmartProtocol(INetProtocol::File);
+ {
+ SvtPathOptions aPathOptions;
+ m_aFileName = aPathOptions.SubstituteVariable(m_aFileName);
+ }
+ aURL.SetSmartURL(m_aFileName);
+ if ( aURL.GetProtocol() == INetProtocol::NotValid )
+ {
+ // don't pass invalid URL to loadComponentFromURL
+ throw SQLException();
+ }
+ m_aFileName = aURL.GetMainURL(INetURLObject::DecodeMechanism::NONE);
+
+ m_sPassword.clear();
+ const char pPwd[] = "password";
+
+ const PropertyValue *pIter = info.getConstArray();
+ const PropertyValue *pEnd = pIter + info.getLength();
+ for(;pIter != pEnd;++pIter)
+ {
+ if(pIter->Name == pPwd)
+ {
+ pIter->Value >>= m_sPassword;
+ break;
+ }
+ } // for(;pIter != pEnd;++pIter)
+ ODocHolder aDocHolder(this); // just to test that the doc can be loaded
+ acquireDoc();
+}
+
+Reference< XSpreadsheetDocument> const & OCalcConnection::acquireDoc()
+{
+ if ( m_xDoc.is() )
+ {
+ osl_atomic_increment(&m_nDocCount);
+ return m_xDoc;
+ }
+ // open read-only as long as updating isn't implemented
+ Sequence<PropertyValue> aArgs(m_sPassword.isEmpty() ? 2 : 3);
+ auto pArgs = aArgs.getArray();
+ pArgs[0].Name = "Hidden";
+ pArgs[0].Value <<= true;
+ pArgs[1].Name = "ReadOnly";
+ pArgs[1].Value <<= true;
+
+ if ( !m_sPassword.isEmpty() )
+ {
+ pArgs[2].Name = "Password";
+ pArgs[2].Value <<= m_sPassword;
+ }
+
+ Reference< XDesktop2 > xDesktop = Desktop::create( getDriver()->getComponentContext() );
+ Reference< XComponent > xComponent;
+ Any aLoaderException;
+ try
+ {
+ xComponent = xDesktop->loadComponentFromURL(
+ m_aFileName, "_blank", 0, aArgs );
+ }
+ catch( const Exception& )
+ {
+ aLoaderException = ::cppu::getCaughtException();
+ }
+
+ m_xDoc.set(xComponent, UNO_QUERY );
+
+ // if the URL is not a spreadsheet document, throw the exception here
+ // instead of at the first access to it
+ if ( !m_xDoc.is() )
+ {
+ Any aErrorDetails;
+ if ( aLoaderException.hasValue() )
+ {
+ Exception aLoaderError;
+ OSL_VERIFY( aLoaderException >>= aLoaderError );
+
+ SQLException aDetailException(m_aResources.getResourceStringWithSubstitution(
+ STR_LOAD_FILE_ERROR_MESSAGE, "$exception_type$",
+ aLoaderException.getValueTypeName(),
+ "$error_message$", aLoaderError.Message),
+ {}, {}, 0, {});
+ aErrorDetails <<= aDetailException;
+ }
+
+ const OUString sError( m_aResources.getResourceStringWithSubstitution(
+ STR_COULD_NOT_LOAD_FILE,
+ "$filename$", m_aFileName
+ ) );
+ ::dbtools::throwGenericSQLException( sError, *this, aErrorDetails );
+ }
+ osl_atomic_increment(&m_nDocCount);
+ m_xCloseVetoButTerminateListener.set(new CloseVetoButTerminateListener);
+ m_xCloseVetoButTerminateListener->start(m_xDoc, xDesktop);
+ return m_xDoc;
+}
+
+void OCalcConnection::releaseDoc()
+{
+ if ( osl_atomic_decrement(&m_nDocCount) == 0 )
+ {
+ if (m_xCloseVetoButTerminateListener.is())
+ {
+ m_xCloseVetoButTerminateListener->stop(); // dispose m_xDoc
+ m_xCloseVetoButTerminateListener.clear();
+ }
+ m_xDoc.clear();
+ }
+}
+
+void OCalcConnection::disposing()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+
+ m_nDocCount = 0;
+ if (m_xCloseVetoButTerminateListener.is())
+ {
+ m_xCloseVetoButTerminateListener->stop(); // dispose m_xDoc
+ m_xCloseVetoButTerminateListener.clear();
+ }
+ m_xDoc.clear();
+
+ OConnection::disposing();
+}
+
+// XServiceInfo
+
+
+IMPLEMENT_SERVICE_INFO(OCalcConnection, "com.sun.star.sdbc.drivers.calc.Connection", "com.sun.star.sdbc.Connection")
+
+
+Reference< XDatabaseMetaData > SAL_CALL OCalcConnection::getMetaData( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OConnection_BASE::rBHelper.bDisposed);
+
+
+ Reference< XDatabaseMetaData > xMetaData = m_xMetaData;
+ if(!xMetaData.is())
+ {
+ xMetaData = new OCalcDatabaseMetaData(this);
+ m_xMetaData = xMetaData;
+ }
+
+ return xMetaData;
+}
+
+
+css::uno::Reference< XTablesSupplier > OCalcConnection::createCatalog()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ Reference< XTablesSupplier > xTab = m_xCatalog;
+ if(!xTab.is())
+ {
+ xTab = new OCalcCatalog(this);
+ m_xCatalog = xTab;
+ }
+ return xTab;
+}
+
+
+Reference< XStatement > SAL_CALL OCalcConnection::createStatement( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OConnection_BASE::rBHelper.bDisposed);
+
+
+ Reference< XStatement > xReturn = new connectivity::component::OComponentStatement(this);
+ m_aStatements.push_back(WeakReferenceHelper(xReturn));
+ return xReturn;
+}
+
+
+Reference< XPreparedStatement > SAL_CALL OCalcConnection::prepareStatement( const OUString& sql )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OConnection_BASE::rBHelper.bDisposed);
+
+
+ rtl::Reference<connectivity::component::OComponentPreparedStatement> pStmt = new connectivity::component::OComponentPreparedStatement(this);
+ pStmt->construct(sql);
+ m_aStatements.push_back(WeakReferenceHelper(*pStmt));
+ return pStmt;
+}
+
+
+Reference< XPreparedStatement > SAL_CALL OCalcConnection::prepareCall( const OUString& /*sql*/ )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OConnection_BASE::rBHelper.bDisposed);
+
+ ::dbtools::throwFeatureNotImplementedSQLException( "XConnection::prepareCall", *this );
+ return nullptr;
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/calc/CDatabaseMetaData.cxx b/connectivity/source/drivers/calc/CDatabaseMetaData.cxx
new file mode 100644
index 0000000000..159349cacd
--- /dev/null
+++ b/connectivity/source/drivers/calc/CDatabaseMetaData.cxx
@@ -0,0 +1,217 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <calc/CDatabaseMetaData.hxx>
+#include <calc/CConnection.hxx>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
+#include <com/sun/star/sheet/XSpreadsheetDocument.hpp>
+#include <com/sun/star/sheet/XSpreadsheet.hpp>
+#include <com/sun/star/sheet/XCellRangeAddressable.hpp>
+#include <com/sun/star/sheet/XDatabaseRanges.hpp>
+#include <com/sun/star/sheet/XDatabaseRange.hpp>
+#include <FDatabaseMetaDataResultSet.hxx>
+
+using namespace connectivity::calc;
+using namespace connectivity::file;
+using namespace connectivity::component;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::table;
+using namespace ::com::sun::star::sheet;
+
+OCalcDatabaseMetaData::OCalcDatabaseMetaData(OConnection* _pCon) :OComponentDatabaseMetaData(_pCon)
+{
+}
+
+OCalcDatabaseMetaData::~OCalcDatabaseMetaData()
+{
+}
+
+OUString SAL_CALL OCalcDatabaseMetaData::getURL( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ return "sdbc:calc:" + m_pConnection->getURL();
+}
+
+static bool lcl_IsEmptyOrHidden( const Reference<XSpreadsheets>& xSheets, const OUString& rName )
+{
+ Any aAny = xSheets->getByName( rName );
+ Reference<XSpreadsheet> xSheet;
+ if ( !(aAny >>= xSheet) )
+ return false;
+
+ // test if sheet is hidden
+
+ Reference<XPropertySet> xProp( xSheet, UNO_QUERY );
+ if (xProp.is())
+ {
+ bool bVisible;
+ Any aVisAny = xProp->getPropertyValue("IsVisible");
+ if ( (aVisAny >>= bVisible) && !bVisible)
+ return true; // hidden
+ }
+
+ // use the same data area as in OCalcTable to test for empty table
+
+ Reference<XSheetCellCursor> xCursor = xSheet->createCursor();
+ Reference<XCellRangeAddressable> xRange( xCursor, UNO_QUERY );
+ if ( xRange.is() )
+ {
+ xCursor->collapseToSize( 1, 1 ); // single (first) cell
+ xCursor->collapseToCurrentRegion(); // contiguous data area
+
+ CellRangeAddress aRangeAddr = xRange->getRangeAddress();
+ if ( aRangeAddr.StartColumn == aRangeAddr.EndColumn &&
+ aRangeAddr.StartRow == aRangeAddr.EndRow )
+ {
+ // single cell -> check content
+ Reference<XCell> xCell = xCursor->getCellByPosition( 0, 0 );
+ if ( xCell.is() && xCell->getType() == CellContentType_EMPTY )
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static bool lcl_IsUnnamed( const Reference<XDatabaseRanges>& xRanges, const OUString& rName )
+{
+ bool bUnnamed = false;
+
+ Any aAny = xRanges->getByName( rName );
+ Reference<XDatabaseRange> xRange;
+ if ( aAny >>= xRange )
+ {
+ Reference<XPropertySet> xRangeProp( xRange, UNO_QUERY );
+ if ( xRangeProp.is() )
+ {
+ try
+ {
+ Any aUserAny = xRangeProp->getPropertyValue("IsUserDefined");
+ bool bUserDefined;
+ if ( aUserAny >>= bUserDefined )
+ bUnnamed = !bUserDefined;
+ }
+ catch ( UnknownPropertyException& )
+ {
+ // optional property
+ }
+ }
+ }
+
+ return bUnnamed;
+}
+
+Reference< XResultSet > SAL_CALL OCalcDatabaseMetaData::getTables(
+ const Any& /*catalog*/, const OUString& /*schemaPattern*/,
+ const OUString& tableNamePattern, const Sequence< OUString >& types )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ rtl::Reference<ODatabaseMetaDataResultSet> pResult = new ODatabaseMetaDataResultSet(ODatabaseMetaDataResultSet::eTables);
+
+ // check if ORowSetValue type is given
+ // when no types are given then we have to return all tables e.g. TABLE
+
+ OUString aTable("TABLE");
+
+ bool bTableFound = true;
+ sal_Int32 nLength = types.getLength();
+ if(nLength)
+ {
+ bTableFound = false;
+
+ const OUString* pIter = types.getConstArray();
+ const OUString* pEnd = pIter + nLength;
+ for(;pIter != pEnd;++pIter)
+ {
+ if(*pIter == aTable)
+ {
+ bTableFound = true;
+ break;
+ }
+ }
+ }
+ if(!bTableFound)
+ return pResult;
+
+ // get the sheet names from the document
+
+ OCalcConnection::ODocHolder aDocHolder(static_cast<OCalcConnection*>(m_pConnection));
+ const Reference<XSpreadsheetDocument>& xDoc = aDocHolder.getDoc();
+ if ( !xDoc.is() )
+ throw SQLException();
+ Reference<XSpreadsheets> xSheets = xDoc->getSheets();
+ if ( !xSheets.is() )
+ throw SQLException();
+ Sequence< OUString > aSheetNames = xSheets->getElementNames();
+
+ ODatabaseMetaDataResultSet::ORows aRows;
+ sal_Int32 nSheetCount = aSheetNames.getLength();
+ for (sal_Int32 nSheet=0; nSheet<nSheetCount; nSheet++)
+ {
+ OUString aName = aSheetNames[nSheet];
+ if ( !lcl_IsEmptyOrHidden( xSheets, aName ) && match(tableNamePattern,aName,'\0') )
+ {
+ aRows.push_back( { nullptr, nullptr, nullptr,
+ new ORowSetValueDecorator(aName),
+ new ORowSetValueDecorator(aTable),
+ ODatabaseMetaDataResultSet::getEmptyValue()
+ } );
+ }
+ }
+
+ // also use database ranges
+
+ Reference<XPropertySet> xDocProp( xDoc, UNO_QUERY );
+ if ( xDocProp.is() )
+ {
+ Any aRangesAny = xDocProp->getPropertyValue("DatabaseRanges");
+ Reference<XDatabaseRanges> xRanges;
+ if ( aRangesAny >>= xRanges )
+ {
+ Sequence< OUString > aDBNames = xRanges->getElementNames();
+ sal_Int32 nDBCount = aDBNames.getLength();
+ for (sal_Int32 nRange=0; nRange<nDBCount; nRange++)
+ {
+ OUString aName = aDBNames[nRange];
+ if ( !lcl_IsUnnamed( xRanges, aName ) && match(tableNamePattern,aName,'\0') )
+ {
+ aRows.push_back( { nullptr, nullptr, nullptr,
+ new ORowSetValueDecorator(aName),
+ new ORowSetValueDecorator(aTable),
+ ODatabaseMetaDataResultSet::getEmptyValue()
+ } );
+ }
+ }
+ }
+ }
+
+ pResult->setRows(std::move(aRows));
+
+ return pResult;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/calc/CDriver.cxx b/connectivity/source/drivers/calc/CDriver.cxx
new file mode 100644
index 0000000000..eccf97751c
--- /dev/null
+++ b/connectivity/source/drivers/calc/CDriver.cxx
@@ -0,0 +1,95 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <calc/CDriver.hxx>
+#include <calc/CConnection.hxx>
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <connectivity/dbexception.hxx>
+#include <resource/sharedresources.hxx>
+#include <strings.hrc>
+
+using namespace connectivity::calc;
+using namespace connectivity::file;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::lang;
+
+
+// ServiceInfo
+
+OUString SAL_CALL ODriver::getImplementationName( )
+{
+ return "com.sun.star.comp.sdbc.calc.ODriver";
+}
+
+// service names from file::OFileDriver
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+connectivity_calc_ODriver(
+ css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const&)
+{
+ rtl::Reference<ODriver> ret;
+ try {
+ ret = new ODriver(context);
+ } catch (...) {
+ }
+ if (ret)
+ ret->acquire();
+ return getXWeak(ret.get());
+}
+
+
+
+Reference< XConnection > SAL_CALL ODriver::connect( const OUString& url,
+ const Sequence< PropertyValue >& info )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if (ODriver_BASE::rBHelper.bDisposed)
+ throw DisposedException();
+
+ if ( ! acceptsURL(url) )
+ return nullptr;
+
+ rtl::Reference<OCalcConnection> pCon = new OCalcConnection(this);
+ pCon->construct(url,info);
+ m_xConnections.push_back(WeakReferenceHelper(*pCon));
+
+ return pCon;
+}
+
+sal_Bool SAL_CALL ODriver::acceptsURL( const OUString& url )
+{
+ return url.startsWith("sdbc:calc:");
+}
+
+Sequence< DriverPropertyInfo > SAL_CALL ODriver::getPropertyInfo( const OUString& url, const Sequence< PropertyValue >& /*info*/ )
+{
+ if ( !acceptsURL(url) )
+ {
+ SharedResources aResources;
+ const OUString sMessage = aResources.getResourceString(STR_URI_SYNTAX_ERROR);
+ ::dbtools::throwGenericSQLException(sMessage ,*this);
+ }
+ return Sequence< DriverPropertyInfo >();
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/calc/CTable.cxx b/connectivity/source/drivers/calc/CTable.cxx
new file mode 100644
index 0000000000..1225e8ace3
--- /dev/null
+++ b/connectivity/source/drivers/calc/CTable.cxx
@@ -0,0 +1,638 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <calc/CTable.hxx>
+#include <com/sun/star/sdbc/ColumnValue.hpp>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <com/sun/star/sheet/XSpreadsheetDocument.hpp>
+#include <com/sun/star/sheet/XSpreadsheet.hpp>
+#include <com/sun/star/sheet/XCellRangeAddressable.hpp>
+#include <com/sun/star/sheet/XCellRangesQuery.hpp>
+#include <com/sun/star/sheet/XDatabaseRanges.hpp>
+#include <com/sun/star/sheet/XDatabaseRange.hpp>
+#include <com/sun/star/sheet/XCellRangeReferrer.hpp>
+#include <com/sun/star/sheet/XUsedAreaCursor.hpp>
+#include <com/sun/star/sheet/CellFlags.hpp>
+#include <com/sun/star/sheet/FormulaResult.hpp>
+#include <com/sun/star/util/NumberFormat.hpp>
+#include <com/sun/star/util/XNumberFormatsSupplier.hpp>
+#include <com/sun/star/text/XText.hpp>
+#include <calc/CConnection.hxx>
+#include <connectivity/sdbcx/VColumn.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <sal/log.hxx>
+#include <rtl/math.hxx>
+#include <tools/time.hxx>
+#include <comphelper/servicehelper.hxx>
+
+using namespace connectivity;
+using namespace connectivity::calc;
+using namespace connectivity::file;
+using namespace ::cppu;
+using namespace ::dbtools;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::sheet;
+using namespace ::com::sun::star::table;
+using namespace ::com::sun::star::text;
+using namespace ::com::sun::star::util;
+
+
+static void lcl_UpdateArea( const Reference<XCellRange>& xUsedRange, sal_Int32& rEndCol, sal_Int32& rEndRow )
+{
+ // update rEndCol, rEndRow if any non-empty cell in xUsedRange is right/below
+
+ const Reference<XCellRangesQuery> xUsedQuery( xUsedRange, UNO_QUERY );
+ if ( !xUsedQuery.is() )
+ return;
+
+ const sal_Int16 nContentFlags =
+ CellFlags::STRING | CellFlags::VALUE | CellFlags::DATETIME | CellFlags::FORMULA | CellFlags::ANNOTATION;
+
+ const Reference<XSheetCellRanges> xUsedRanges = xUsedQuery->queryContentCells( nContentFlags );
+ const Sequence<CellRangeAddress> aAddresses = xUsedRanges->getRangeAddresses();
+
+ const sal_Int32 nCount = aAddresses.getLength();
+ const CellRangeAddress* pData = aAddresses.getConstArray();
+ for ( sal_Int32 i=0; i<nCount; i++ )
+ {
+ rEndCol = std::max(pData[i].EndColumn, rEndCol);
+ rEndRow = std::max(pData[i].EndRow, rEndRow);
+ }
+}
+
+static void lcl_GetDataArea( const Reference<XSpreadsheet>& xSheet, sal_Int32& rColumnCount, sal_Int32& rRowCount )
+{
+ Reference<XSheetCellCursor> xCursor = xSheet->createCursor();
+ Reference<XCellRangeAddressable> xRange( xCursor, UNO_QUERY );
+ if ( !xRange.is() )
+ {
+ rColumnCount = rRowCount = 0;
+ return;
+ }
+
+ // first find the contiguous cell area starting at A1
+
+ xCursor->collapseToSize( 1, 1 ); // single (first) cell
+ xCursor->collapseToCurrentRegion(); // contiguous data area
+
+ CellRangeAddress aRegionAddr = xRange->getRangeAddress();
+ sal_Int32 nEndCol = aRegionAddr.EndColumn;
+ sal_Int32 nEndRow = aRegionAddr.EndRow;
+
+ Reference<XUsedAreaCursor> xUsed( xCursor, UNO_QUERY );
+ if ( xUsed.is() )
+ {
+ // The used area from XUsedAreaCursor includes visible attributes.
+ // If the used area is larger than the contiguous cell area, find non-empty
+ // cells in that area.
+
+ xUsed->gotoEndOfUsedArea( false );
+ CellRangeAddress aUsedAddr = xRange->getRangeAddress();
+
+ if ( aUsedAddr.EndColumn > aRegionAddr.EndColumn )
+ {
+ Reference<XCellRange> xUsedRange = xSheet->getCellRangeByPosition(
+ aRegionAddr.EndColumn + 1, 0, aUsedAddr.EndColumn, aUsedAddr.EndRow );
+ lcl_UpdateArea( xUsedRange, nEndCol, nEndRow );
+ }
+
+ if ( aUsedAddr.EndRow > aRegionAddr.EndRow )
+ {
+ // only up to the last column of aRegionAddr, the other columns are handled above
+ Reference<XCellRange> xUsedRange = xSheet->getCellRangeByPosition(
+ 0, aRegionAddr.EndRow + 1, aRegionAddr.EndColumn, aUsedAddr.EndRow );
+ lcl_UpdateArea( xUsedRange, nEndCol, nEndRow );
+ }
+ }
+
+ rColumnCount = nEndCol + 1; // number of columns
+ rRowCount = nEndRow; // first row (headers) is not counted
+}
+
+static CellContentType lcl_GetContentOrResultType( const Reference<XCell>& xCell )
+{
+ CellContentType eCellType = xCell->getType();
+ if ( eCellType == CellContentType_FORMULA )
+ {
+ Reference<XPropertySet> xProp( xCell, UNO_QUERY );
+ try
+ {
+ xProp->getPropertyValue( "CellContentType" ) >>= eCellType; // type of cell content
+ }
+ catch (UnknownPropertyException&)
+ {
+ eCellType = CellContentType_VALUE; // if CellContentType property not available
+ }
+ }
+ return eCellType;
+}
+
+static Reference<XCell> lcl_GetUsedCell( const Reference<XSpreadsheet>& xSheet, sal_Int32 nDocColumn, sal_Int32 nDocRow )
+{
+ Reference<XCell> xCell = xSheet->getCellByPosition( nDocColumn, nDocRow );
+ if ( xCell.is() && xCell->getType() == CellContentType_EMPTY )
+ {
+ // get first non-empty cell
+
+ Reference<XCellRangeAddressable> xAddr( xSheet, UNO_QUERY );
+ if (xAddr.is())
+ {
+ CellRangeAddress aTotalRange = xAddr->getRangeAddress();
+ sal_Int32 nLastRow = aTotalRange.EndRow;
+ Reference<XCellRangesQuery> xQuery( xSheet->getCellRangeByPosition( nDocColumn, nDocRow, nDocColumn, nLastRow ), UNO_QUERY );
+ if (xQuery.is())
+ {
+ // queryIntersection to get a ranges object
+ Reference<XSheetCellRanges> xRanges = xQuery->queryIntersection( aTotalRange );
+ if (xRanges.is())
+ {
+ Reference<XEnumerationAccess> xCells = xRanges->getCells();
+ if (xCells.is())
+ {
+ Reference<XEnumeration> xEnum = xCells->createEnumeration();
+ if ( xEnum.is() && xEnum->hasMoreElements() )
+ {
+ // get first non-empty cell from enumeration
+ xCell.set(xEnum->nextElement(),UNO_QUERY);
+ }
+ // otherwise, keep empty cell
+ }
+ }
+ }
+ }
+ }
+ return xCell;
+}
+
+static bool lcl_HasTextInColumn( const Reference<XSpreadsheet>& xSheet, sal_Int32 nDocColumn, sal_Int32 nDocRow )
+{
+ // look for any text cell or text result in the column
+
+ Reference<XCellRangeAddressable> xAddr( xSheet, UNO_QUERY );
+ if (!xAddr)
+ return false;
+ CellRangeAddress aTotalRange = xAddr->getRangeAddress();
+ sal_Int32 nLastRow = aTotalRange.EndRow;
+ Reference<XCellRangesQuery> xQuery( xSheet->getCellRangeByPosition( nDocColumn, nDocRow, nDocColumn, nLastRow ), UNO_QUERY );
+ if (!xQuery)
+ return false;
+
+ // are there text cells in the column?
+ Reference<XSheetCellRanges> xTextContent = xQuery->queryContentCells( CellFlags::STRING );
+ if ( xTextContent.is() && xTextContent->hasElements() )
+ return true;
+
+ // are there formulas with text results in the column?
+ Reference<XSheetCellRanges> xTextFormula = xQuery->queryFormulaCells( FormulaResult::STRING );
+ if ( xTextFormula.is() && xTextFormula->hasElements() )
+ return true;
+
+ return false;
+}
+
+static void lcl_GetColumnInfo( const Reference<XSpreadsheet>& xSheet, const Reference<XNumberFormats>& xFormats,
+ sal_Int32 nDocColumn, sal_Int32 nStartRow, bool bHasHeaders,
+ OUString& rName, sal_Int32& rDataType, bool& rCurrency )
+{
+ //! avoid duplicate field names
+
+ // get column name from first row, if range contains headers
+
+ if ( bHasHeaders )
+ {
+ Reference<XText> xHeaderText( xSheet->getCellByPosition( nDocColumn, nStartRow ), UNO_QUERY );
+ if ( xHeaderText.is() )
+ rName = xHeaderText->getString();
+ }
+
+ // get column type from first data row
+
+ sal_Int32 nDataRow = nStartRow;
+ if ( bHasHeaders )
+ ++nDataRow;
+ Reference<XCell> xDataCell = lcl_GetUsedCell( xSheet, nDocColumn, nDataRow );
+
+ Reference<XPropertySet> xProp( xDataCell, UNO_QUERY );
+ if ( !xProp.is() )
+ return;
+
+ rCurrency = false; // set to true for currency below
+
+ const CellContentType eCellType = lcl_GetContentOrResultType( xDataCell );
+ // #i35178# use "text" type if there is any text cell in the column
+ if ( eCellType == CellContentType_TEXT || lcl_HasTextInColumn( xSheet, nDocColumn, nDataRow ) )
+ rDataType = DataType::VARCHAR;
+ else if ( eCellType == CellContentType_VALUE )
+ {
+ // get number format to distinguish between different types
+
+ sal_Int16 nNumType = NumberFormat::NUMBER;
+ try
+ {
+ sal_Int32 nKey = 0;
+
+ if ( xProp->getPropertyValue( "NumberFormat" ) >>= nKey )
+ {
+ const Reference<XPropertySet> xFormat = xFormats->getByKey( nKey );
+ if ( xFormat.is() )
+ {
+ xFormat->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE) ) >>= nNumType;
+ }
+ }
+ }
+ catch ( Exception& )
+ {
+ }
+
+ if ( nNumType & NumberFormat::TEXT )
+ rDataType = DataType::VARCHAR;
+ else if ( nNumType & NumberFormat::NUMBER )
+ rDataType = DataType::DECIMAL;
+ else if ( nNumType & NumberFormat::CURRENCY )
+ {
+ rCurrency = true;
+ rDataType = DataType::DECIMAL;
+ }
+ else if ( ( nNumType & NumberFormat::DATETIME ) == NumberFormat::DATETIME )
+ {
+ // NumberFormat::DATETIME is DATE | TIME
+ rDataType = DataType::TIMESTAMP;
+ }
+ else if ( nNumType & NumberFormat::DATE )
+ rDataType = DataType::DATE;
+ else if ( nNumType & NumberFormat::TIME )
+ rDataType = DataType::TIME;
+ else if ( nNumType & NumberFormat::LOGICAL )
+ rDataType = DataType::BIT;
+ else
+ rDataType = DataType::DECIMAL;
+ }
+ else
+ {
+ // whole column empty
+ rDataType = DataType::VARCHAR;
+ }
+}
+
+
+static void lcl_SetValue( ORowSetValue& rValue, const Reference<XSpreadsheet>& xSheet,
+ sal_Int32 nStartCol, sal_Int32 nStartRow, bool bHasHeaders,
+ const ::Date& rNullDate,
+ sal_Int32 nDBRow, sal_Int32 nDBColumn, sal_Int32 nType )
+{
+ sal_Int32 nDocColumn = nStartCol + nDBColumn - 1; // database counts from 1
+ sal_Int32 nDocRow = nStartRow + nDBRow - 1;
+ if (bHasHeaders)
+ ++nDocRow;
+
+ const Reference<XCell> xCell = xSheet->getCellByPosition( nDocColumn, nDocRow );
+ if ( !xCell.is() )
+ return;
+
+ CellContentType eCellType = lcl_GetContentOrResultType( xCell );
+ switch (nType)
+ {
+ case DataType::VARCHAR:
+ if ( eCellType == CellContentType_EMPTY )
+ rValue.setNull();
+ else
+ {
+ // #i25840# still let Calc convert numbers to text
+ const Reference<XText> xText( xCell, UNO_QUERY );
+ if ( xText.is() )
+ rValue = xText->getString();
+ }
+ break;
+ case DataType::DECIMAL:
+ if ( eCellType == CellContentType_VALUE )
+ rValue = xCell->getValue(); // double
+ else
+ rValue.setNull();
+ break;
+ case DataType::BIT:
+ if ( eCellType == CellContentType_VALUE )
+ rValue = xCell->getValue() != 0.0;
+ else
+ rValue.setNull();
+ break;
+ case DataType::DATE:
+ if ( eCellType == CellContentType_VALUE )
+ {
+ ::Date aDate( rNullDate );
+ aDate.AddDays(::rtl::math::approxFloor( xCell->getValue() ));
+ rValue = aDate.GetUNODate();
+ }
+ else
+ rValue.setNull();
+ break;
+ case DataType::TIME:
+ if ( eCellType == CellContentType_VALUE )
+ {
+ double fCellVal = xCell->getValue();
+ double fTime = fCellVal - rtl::math::approxFloor( fCellVal );
+ sal_Int64 nIntTime = static_cast<sal_Int64>(rtl::math::round( fTime * static_cast<double>(::tools::Time::nanoSecPerDay) ));
+ if ( nIntTime == ::tools::Time::nanoSecPerDay)
+ nIntTime = 0; // 23:59:59.9999999995 and above is 00:00:00.00
+ css::util::Time aTime;
+ aTime.NanoSeconds = static_cast<sal_uInt32>( nIntTime % ::tools::Time::nanoSecPerSec );
+ nIntTime /= ::tools::Time::nanoSecPerSec;
+ aTime.Seconds = static_cast<sal_uInt16>( nIntTime % 60 );
+ nIntTime /= 60;
+ aTime.Minutes = static_cast<sal_uInt16>( nIntTime % 60 );
+ nIntTime /= 60;
+ OSL_ENSURE( nIntTime < 24, "error in time calculation" );
+ aTime.Hours = static_cast<sal_uInt16>(nIntTime);
+ rValue = aTime;
+ }
+ else
+ rValue.setNull();
+ break;
+ case DataType::TIMESTAMP:
+ if ( eCellType == CellContentType_VALUE )
+ {
+ double fCellVal = xCell->getValue();
+ double fDays = ::rtl::math::approxFloor( fCellVal );
+ double fTime = fCellVal - fDays;
+ tools::Long nIntDays = static_cast<tools::Long>(fDays);
+ sal_Int64 nIntTime = ::rtl::math::round( fTime * static_cast<double>(::tools::Time::nanoSecPerDay) );
+ if ( nIntTime == ::tools::Time::nanoSecPerDay )
+ {
+ nIntTime = 0; // 23:59:59.9999999995 and above is 00:00:00.00
+ ++nIntDays; // (next day)
+ }
+
+ css::util::DateTime aDateTime;
+
+ aDateTime.NanoSeconds = static_cast<sal_uInt16>( nIntTime % ::tools::Time::nanoSecPerSec );
+ nIntTime /= ::tools::Time::nanoSecPerSec;
+ aDateTime.Seconds = static_cast<sal_uInt16>( nIntTime % 60 );
+ nIntTime /= 60;
+ aDateTime.Minutes = static_cast<sal_uInt16>( nIntTime % 60 );
+ nIntTime /= 60;
+ OSL_ENSURE( nIntTime < 24, "error in time calculation" );
+ aDateTime.Hours = static_cast<sal_uInt16>(nIntTime);
+
+ ::Date aDate( rNullDate );
+ aDate.AddDays( nIntDays );
+ aDateTime.Day = aDate.GetDay();
+ aDateTime.Month = aDate.GetMonth();
+ aDateTime.Year = aDate.GetYear();
+
+ rValue = aDateTime;
+ }
+ else
+ rValue.setNull();
+ break;
+ } // switch (nType)
+
+// rValue.setTypeKind(nType);
+}
+
+
+static OUString lcl_GetColumnStr( sal_Int32 nColumn )
+{
+ if ( nColumn < 26 )
+ return OUString( static_cast<sal_Unicode>( 'A' + nColumn ) );
+ else
+ {
+ OUStringBuffer aBuffer(2);
+ aBuffer.setLength( 2 );
+ aBuffer[0] = static_cast<sal_Unicode>( 'A' + ( nColumn / 26 ) - 1 );
+ aBuffer[1] = static_cast<sal_Unicode>( 'A' + ( nColumn % 26 ) );
+ return aBuffer.makeStringAndClear();
+ }
+}
+
+void OCalcTable::fillColumns()
+{
+ if ( !m_xSheet.is() )
+ throw SQLException();
+
+ OUString aTypeName;
+ ::comphelper::UStringMixEqual aCase(m_pConnection->getMetaData()->supportsMixedCaseQuotedIdentifiers());
+ const bool bStoresMixedCaseQuotedIdentifiers = getConnection()->getMetaData()->supportsMixedCaseQuotedIdentifiers();
+
+ for (sal_Int32 i = 0; i < m_nDataCols; i++)
+ {
+ OUString aColumnName;
+ sal_Int32 eType = DataType::OTHER;
+ bool bCurrency = false;
+
+ lcl_GetColumnInfo( m_xSheet, m_xFormats, m_nStartCol + i, m_nStartRow, m_bHasHeaders,
+ aColumnName, eType, bCurrency );
+
+ if ( aColumnName.isEmpty() )
+ aColumnName = lcl_GetColumnStr( i );
+
+ sal_Int32 nPrecision = 0; //! ...
+ sal_Int32 nDecimals = 0; //! ...
+
+ switch ( eType )
+ {
+ case DataType::VARCHAR:
+ aTypeName = "VARCHAR";
+ break;
+ case DataType::DECIMAL:
+ aTypeName = "DECIMAL";
+ break;
+ case DataType::BIT:
+ aTypeName = "BOOL";
+ break;
+ case DataType::DATE:
+ aTypeName = "DATE";
+ break;
+ case DataType::TIME:
+ aTypeName = "TIME";
+ break;
+ case DataType::TIMESTAMP:
+ aTypeName = "TIMESTAMP";
+ break;
+ default:
+ SAL_WARN( "connectivity.drivers","missing type name");
+ aTypeName.clear();
+ }
+
+ // check if the column name already exists
+ OUString aAlias = aColumnName;
+ OSQLColumns::const_iterator aFind = connectivity::find(m_aColumns->begin(),m_aColumns->end(),aAlias,aCase);
+ sal_Int32 nExprCnt = 0;
+ while(aFind != m_aColumns->end())
+ {
+ aAlias = aColumnName + OUString::number(++nExprCnt);
+ aFind = connectivity::find(m_aColumns->begin(),m_aColumns->end(),aAlias,aCase);
+ }
+
+ rtl::Reference<sdbcx::OColumn> pColumn = new sdbcx::OColumn( aAlias, aTypeName, OUString(),OUString(),
+ ColumnValue::NULLABLE, nPrecision, nDecimals,
+ eType, false, false, bCurrency,
+ bStoresMixedCaseQuotedIdentifiers,
+ m_CatalogName, getSchema(), getName());
+ m_aColumns->push_back(pColumn);
+ m_aTypes.push_back(eType);
+ }
+}
+
+
+OCalcTable::OCalcTable(sdbcx::OCollection* _pTables,OCalcConnection* _pConnection,
+ const OUString& Name,
+ const OUString& Type,
+ const OUString& Description ,
+ const OUString& SchemaName,
+ const OUString& CatalogName
+ ) : OCalcTable_BASE(_pTables,_pConnection,Name,
+ Type,
+ Description,
+ SchemaName,
+ CatalogName)
+ ,m_pCalcConnection(_pConnection)
+ ,m_nStartCol(0)
+ ,m_nStartRow(0)
+ ,m_nDataCols(0)
+ ,m_bHasHeaders(false)
+ ,m_aNullDate(::Date::EMPTY)
+{
+}
+
+void OCalcTable::construct()
+{
+ // get sheet object
+ Reference< XSpreadsheetDocument> xDoc = m_pCalcConnection->acquireDoc();
+ if (xDoc.is())
+ {
+ Reference<XSpreadsheets> xSheets = xDoc->getSheets();
+ if ( xSheets.is() && xSheets->hasByName( m_Name ) )
+ {
+ m_xSheet.set(xSheets->getByName( m_Name ),UNO_QUERY);
+ if ( m_xSheet.is() )
+ {
+ lcl_GetDataArea( m_xSheet, m_nDataCols, m_nDataRows );
+ m_bHasHeaders = true;
+ // whole sheet is always assumed to include a header row
+ }
+ }
+ else // no sheet -> try database range
+ {
+ Reference<XPropertySet> xDocProp( xDoc, UNO_QUERY );
+ if ( xDocProp.is() )
+ {
+ Reference<XDatabaseRanges> xRanges(xDocProp->getPropertyValue("DatabaseRanges"),UNO_QUERY);
+
+ if ( xRanges.is() && xRanges->hasByName( m_Name ) )
+ {
+ Reference<XDatabaseRange> xDBRange(xRanges->getByName( m_Name ),UNO_QUERY);
+ Reference<XCellRangeReferrer> xRefer( xDBRange, UNO_QUERY );
+ if ( xRefer.is() )
+ {
+ // Header flag is always stored with database range
+ // Get flag from FilterDescriptor
+
+ bool bRangeHeader = true;
+ Reference<XPropertySet> xFiltProp( xDBRange->getFilterDescriptor(), UNO_QUERY );
+ if ( xFiltProp.is() )
+ xFiltProp->getPropertyValue("ContainsHeader") >>= bRangeHeader;
+
+ Reference<XSheetCellRange> xSheetRange( xRefer->getReferredCells(), UNO_QUERY );
+ Reference<XCellRangeAddressable> xAddr( xSheetRange, UNO_QUERY );
+ if ( xSheetRange.is() && xAddr.is() )
+ {
+ m_xSheet = xSheetRange->getSpreadsheet();
+ CellRangeAddress aRangeAddr = xAddr->getRangeAddress();
+ m_nStartCol = aRangeAddr.StartColumn;
+ m_nStartRow = aRangeAddr.StartRow;
+ m_nDataCols = aRangeAddr.EndColumn - m_nStartCol + 1;
+ // m_nDataRows is excluding header row
+ m_nDataRows = aRangeAddr.EndRow - m_nStartRow;
+ if ( !bRangeHeader )
+ {
+ // m_nDataRows counts the whole range
+ m_nDataRows += 1;
+ }
+
+ m_bHasHeaders = bRangeHeader;
+ }
+ }
+ }
+ }
+ }
+
+ Reference<XNumberFormatsSupplier> xSupp( xDoc, UNO_QUERY );
+ if (xSupp.is())
+ m_xFormats = xSupp->getNumberFormats();
+
+ Reference<XPropertySet> xProp( xDoc, UNO_QUERY );
+ if (xProp.is())
+ {
+ css::util::Date aDateStruct;
+ if ( xProp->getPropertyValue("NullDate") >>= aDateStruct )
+ m_aNullDate = ::Date( aDateStruct.Day, aDateStruct.Month, aDateStruct.Year );
+ }
+ }
+
+ //! default if no null date available?
+
+ fillColumns();
+
+ refreshColumns();
+}
+
+void SAL_CALL OCalcTable::disposing()
+{
+ OFileTable::disposing();
+ ::osl::MutexGuard aGuard(m_aMutex);
+ m_aColumns = nullptr;
+ if ( m_pCalcConnection )
+ m_pCalcConnection->releaseDoc();
+ m_pCalcConnection = nullptr;
+
+}
+
+bool OCalcTable::fetchRow( OValueRefRow& _rRow, const OSQLColumns & _rCols,
+ bool bRetrieveData )
+{
+ // read the bookmark
+
+ _rRow->setDeleted(false);
+ *(*_rRow)[0] = m_nFilePos;
+
+ if (!bRetrieveData)
+ return true;
+
+ // fields
+
+ const OValueRefVector::size_type nCount = std::min(_rRow->size(), _rCols.size() + 1);
+ for (OValueRefVector::size_type i = 1; i < nCount; i++)
+ {
+ if ( (*_rRow)[i]->isBound() )
+ {
+ sal_Int32 nType = m_aTypes[i-1];
+
+ lcl_SetValue( (*_rRow)[i]->get(), m_xSheet, m_nStartCol, m_nStartRow, m_bHasHeaders,
+ m_aNullDate, m_nFilePos, i, nType );
+ }
+ }
+ return true;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/calc/CTables.cxx b/connectivity/source/drivers/calc/CTables.cxx
new file mode 100644
index 0000000000..08e5d63e3a
--- /dev/null
+++ b/connectivity/source/drivers/calc/CTables.cxx
@@ -0,0 +1,48 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <calc/CConnection.hxx>
+#include <calc/CTables.hxx>
+#include <calc/CTable.hxx>
+#include <file/FCatalog.hxx>
+#include <file/FConnection.hxx>
+
+using namespace ::comphelper;
+using namespace connectivity;
+using namespace connectivity::calc;
+using namespace connectivity::file;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::container;
+
+sdbcx::ObjectType OCalcTables::createObject(const OUString& _rName)
+{
+ rtl::Reference<OCalcTable> pTable = new OCalcTable(this, static_cast<OCalcConnection*>(static_cast<OFileCatalog&>(m_rParent).getConnection()),
+ _rName,"TABLE");
+ pTable->construct();
+ return pTable;
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/calc/calc.component b/connectivity/source/drivers/calc/calc.component
new file mode 100644
index 0000000000..a4fc7d8f11
--- /dev/null
+++ b/connectivity/source/drivers/calc/calc.component
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ -->
+
+<component loader="com.sun.star.loader.SharedLibrary" environment="@CPPU_ENV@"
+ xmlns="http://openoffice.org/2010/uno-components">
+ <implementation name="com.sun.star.comp.sdbc.calc.ODriver"
+ constructor="connectivity_calc_ODriver">
+ <service name="com.sun.star.sdbc.Driver"/>
+ <service name="com.sun.star.sdbcx.Driver"/>
+ </implementation>
+</component>
diff --git a/connectivity/source/drivers/component/CColumns.cxx b/connectivity/source/drivers/component/CColumns.cxx
new file mode 100644
index 0000000000..9f802b6e4c
--- /dev/null
+++ b/connectivity/source/drivers/component/CColumns.cxx
@@ -0,0 +1,44 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <component/CColumns.hxx>
+#include <file/FTable.hxx>
+
+using namespace connectivity::component;
+using namespace connectivity;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::container;
+
+
+sdbcx::ObjectType OComponentColumns::createObject(const OUString& _rName)
+{
+ ::rtl::Reference<OSQLColumns> aCols = m_pTable->getTableColumns();
+
+ OSQLColumns::const_iterator aIter = find(aCols->begin(),aCols->end(),_rName,::comphelper::UStringMixEqual(isCaseSensitive()));
+ sdbcx::ObjectType xRet;
+ if(aIter != aCols->end())
+ xRet = sdbcx::ObjectType(*aIter,UNO_QUERY);
+ return xRet;
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/component/CDatabaseMetaData.cxx b/connectivity/source/drivers/component/CDatabaseMetaData.cxx
new file mode 100644
index 0000000000..49d83e36af
--- /dev/null
+++ b/connectivity/source/drivers/component/CDatabaseMetaData.cxx
@@ -0,0 +1,235 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <component/CDatabaseMetaData.hxx>
+#include <file/FConnection.hxx>
+#include <com/sun/star/sdbc/ColumnSearch.hpp>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <com/sun/star/sdbc/ColumnValue.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
+#include <FDatabaseMetaDataResultSet.hxx>
+#include <comphelper/types.hxx>
+
+using namespace connectivity::component;
+using namespace connectivity::file;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::container;
+
+OComponentDatabaseMetaData::OComponentDatabaseMetaData(OConnection* _pCon) :ODatabaseMetaData(_pCon)
+{
+}
+
+OComponentDatabaseMetaData::~OComponentDatabaseMetaData()
+{
+}
+
+Reference< XResultSet > OComponentDatabaseMetaData::impl_getTypeInfo_throw( )
+{
+ rtl::Reference<ODatabaseMetaDataResultSet> pResult = new ODatabaseMetaDataResultSet(::connectivity::ODatabaseMetaDataResultSet::eTypeInfo);
+
+ ODatabaseMetaDataResultSet::ORows aRows;
+ aRows.reserve(6);
+ ODatabaseMetaDataResultSet::ORow aRow
+ {
+ ODatabaseMetaDataResultSet::getEmptyValue(),
+ new ORowSetValueDecorator(OUString("VARCHAR")),
+ new ORowSetValueDecorator(DataType::VARCHAR),
+ new ORowSetValueDecorator(sal_Int32(65535)),
+ ODatabaseMetaDataResultSet::getQuoteValue(),
+ ODatabaseMetaDataResultSet::getQuoteValue(),
+ ODatabaseMetaDataResultSet::getEmptyValue(),
+ ODatabaseMetaDataResultSet::get1Value(), // ORowSetValue((sal_Int32)ColumnValue::NULLABLE
+ ODatabaseMetaDataResultSet::get1Value(),
+ new ORowSetValueDecorator(sal_Int32(ColumnSearch::CHAR)),
+ ODatabaseMetaDataResultSet::get1Value(),
+ ODatabaseMetaDataResultSet::get0Value(),
+ ODatabaseMetaDataResultSet::get0Value(),
+ ODatabaseMetaDataResultSet::getEmptyValue(),
+ ODatabaseMetaDataResultSet::get0Value(),
+ ODatabaseMetaDataResultSet::get0Value(),
+ ODatabaseMetaDataResultSet::getEmptyValue(),
+ ODatabaseMetaDataResultSet::getEmptyValue(),
+ new ORowSetValueDecorator(sal_Int32(10))
+ };
+
+ aRows.push_back(aRow);
+
+ aRow[1] = new ORowSetValueDecorator(OUString("DECIMAL"));
+ aRow[2] = new ORowSetValueDecorator(DataType::DECIMAL);
+ aRow[3] = ODatabaseMetaDataResultSet::get0Value();
+ aRow[9] = ODatabaseMetaDataResultSet::getBasicValue();
+ aRow[15] = ODatabaseMetaDataResultSet::get0Value();
+ aRows.push_back(aRow);
+
+ aRow[1] = new ORowSetValueDecorator(OUString("BOOL"));
+ aRow[2] = new ORowSetValueDecorator(DataType::BIT);
+ aRow[3] = new ORowSetValueDecorator(sal_Int32(20));
+ aRow[9] = ODatabaseMetaDataResultSet::getBasicValue();
+ aRow[15] = new ORowSetValueDecorator(sal_Int32(15));
+ aRows.push_back(aRow);
+
+ aRow[1] = new ORowSetValueDecorator(OUString("DATE"));
+ aRow[2] = new ORowSetValueDecorator(DataType::DATE);
+ aRow[3] = ODatabaseMetaDataResultSet::get0Value();
+ aRow[9] = ODatabaseMetaDataResultSet::getBasicValue();
+ aRow[15] = ODatabaseMetaDataResultSet::get0Value();
+ aRows.push_back(aRow);
+
+ aRow[1] = new ORowSetValueDecorator(OUString("TIME"));
+ aRow[2] = new ORowSetValueDecorator(DataType::TIME);
+ aRow[3] = ODatabaseMetaDataResultSet::get0Value();
+ aRow[9] = ODatabaseMetaDataResultSet::getBasicValue();
+ aRow[15] = ODatabaseMetaDataResultSet::get0Value();
+ aRows.push_back(aRow);
+
+ aRow[1] = new ORowSetValueDecorator(OUString("TIMESTAMP"));
+ aRow[2] = new ORowSetValueDecorator(DataType::TIMESTAMP);
+ aRow[3] = ODatabaseMetaDataResultSet::get0Value();
+ aRow[9] = ODatabaseMetaDataResultSet::getBasicValue();
+ aRow[15] = ODatabaseMetaDataResultSet::get0Value();
+ aRows.push_back(aRow);
+
+ pResult->setRows(std::move(aRows));
+ return pResult;
+}
+
+Reference< XResultSet > SAL_CALL OComponentDatabaseMetaData::getColumns(
+ const Any& /*catalog*/, const OUString& /*schemaPattern*/, const OUString& tableNamePattern,
+ const OUString& columnNamePattern )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+
+ Reference< XTablesSupplier > xTables = m_pConnection->createCatalog();
+ if(!xTables.is())
+ throw SQLException();
+
+ Reference< XNameAccess> xNames = xTables->getTables();
+ if(!xNames.is())
+ throw SQLException();
+
+ ODatabaseMetaDataResultSet::ORows aRows;
+ ODatabaseMetaDataResultSet::ORow aRow(19);
+
+ aRow[10] = new ORowSetValueDecorator(sal_Int32(10));
+
+ Sequence< OUString> aTabNames(xNames->getElementNames());
+ const OUString* pTabIter = aTabNames.getConstArray();
+ const OUString* pTabEnd = pTabIter + aTabNames.getLength();
+ for(;pTabIter != pTabEnd;++pTabIter)
+ {
+ if(match(tableNamePattern,*pTabIter,'\0'))
+ {
+ const Reference< XColumnsSupplier> xTable(xNames->getByName(*pTabIter),UNO_QUERY_THROW);
+ aRow[3] = new ORowSetValueDecorator(*pTabIter);
+
+ const Reference< XNameAccess> xColumns = xTable->getColumns();
+ if(!xColumns.is())
+ throw SQLException();
+
+ const Sequence< OUString> aColNames(xColumns->getElementNames());
+
+ const OUString* pColumnIter = aColNames.getConstArray();
+ const OUString* pEnd = pColumnIter + aColNames.getLength();
+ Reference< XPropertySet> xColumn;
+ for(sal_Int32 i=1;pColumnIter != pEnd;++pColumnIter,++i)
+ {
+ if(match(columnNamePattern,*pColumnIter,'\0'))
+ {
+ aRow[4] = new ORowSetValueDecorator( *pColumnIter);
+
+ xColumns->getByName(*pColumnIter) >>= xColumn;
+ OSL_ENSURE(xColumn.is(),"Columns contains a column who isn't a fastpropertyset!");
+ aRow[5] = new ORowSetValueDecorator(::comphelper::getINT32(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE))));
+ aRow[6] = new ORowSetValueDecorator(::comphelper::getString(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPENAME))));
+ aRow[7] = new ORowSetValueDecorator(::comphelper::getINT32(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PRECISION))));
+ // aRow[8] = xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPENAME));
+ aRow[9] = new ORowSetValueDecorator(::comphelper::getINT32(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCALE))));
+ aRow[11] = new ORowSetValueDecorator(::comphelper::getINT32(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISNULLABLE))));
+ // aRow[12] = xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPENAME));
+ aRow[13] = new ORowSetValueDecorator(::comphelper::getString(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DEFAULTVALUE))));
+ // aRow[14] = xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPENAME));
+ // aRow[15] = xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPENAME));
+ switch(aRow[5]->getValue().getInt32())
+ {
+ case DataType::CHAR:
+ case DataType::VARCHAR:
+ aRow[16] = new ORowSetValueDecorator(sal_Int32(254));
+ break;
+ case DataType::LONGVARCHAR:
+ aRow[16] = new ORowSetValueDecorator(sal_Int32(65535));
+ break;
+ default:
+ aRow[16] = new ORowSetValueDecorator(sal_Int32(0));
+ }
+ aRow[17] = new ORowSetValueDecorator(i);
+ switch(aRow[11]->getValue().getInt32())
+ {
+ case ColumnValue::NO_NULLS:
+ aRow[18] = new ORowSetValueDecorator(OUString("NO"));
+ break;
+ case ColumnValue::NULLABLE:
+ aRow[18] = new ORowSetValueDecorator(OUString("YES"));
+ break;
+ default:
+ aRow[18] = new ORowSetValueDecorator(OUString());
+ }
+ aRows.push_back(aRow);
+ }
+ }
+ }
+ }
+
+ rtl::Reference<ODatabaseMetaDataResultSet> pResult = new ODatabaseMetaDataResultSet(::connectivity::ODatabaseMetaDataResultSet::eColumns);
+ pResult->setRows(std::move(aRows));
+
+ return pResult;
+}
+
+sal_Int32 SAL_CALL OComponentDatabaseMetaData::getMaxBinaryLiteralLength( )
+{
+ return SAL_MAX_INT32;
+}
+
+sal_Int32 SAL_CALL OComponentDatabaseMetaData::getMaxCharLiteralLength( )
+{
+ return SAL_MAX_INT32;
+}
+
+sal_Int32 SAL_CALL OComponentDatabaseMetaData::getMaxColumnNameLength( )
+{
+ return SAL_MAX_INT32;
+}
+
+sal_Int32 SAL_CALL OComponentDatabaseMetaData::getMaxColumnsInIndex( )
+{
+ return 1;
+}
+
+sal_Int32 SAL_CALL OComponentDatabaseMetaData::getMaxColumnsInTable( )
+{
+ return 256;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/component/CPreparedStatement.cxx b/connectivity/source/drivers/component/CPreparedStatement.cxx
new file mode 100644
index 0000000000..7c5c8e07f8
--- /dev/null
+++ b/connectivity/source/drivers/component/CPreparedStatement.cxx
@@ -0,0 +1,34 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <component/CPreparedStatement.hxx>
+#include <component/CResultSet.hxx>
+
+using namespace connectivity::component;
+using namespace connectivity::file;
+using namespace com::sun::star::uno;
+
+rtl::Reference<OResultSet> OComponentPreparedStatement::createResultSet()
+{
+ return new connectivity::component::OComponentResultSet(this,m_aSQLIterator);
+}
+
+IMPLEMENT_SERVICE_INFO(OComponentPreparedStatement,"com.sun.star.sdbc.driver.component.PreparedStatement","com.sun.star.sdbc.PreparedStatement");
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/component/CResultSet.cxx b/connectivity/source/drivers/component/CResultSet.cxx
new file mode 100644
index 0000000000..08e6e04aca
--- /dev/null
+++ b/connectivity/source/drivers/component/CResultSet.cxx
@@ -0,0 +1,172 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/sdbcx/CompareBookmark.hpp>
+#include <component/CResultSet.hxx>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <comphelper/sequence.hxx>
+#include <comphelper/types.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <connectivity/dbexception.hxx>
+
+using namespace ::comphelper;
+using namespace connectivity::component;
+using namespace connectivity::file;
+using namespace ::cppu;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::sdbc;
+using namespace com::sun::star::sdbcx;
+
+
+OComponentResultSet::OComponentResultSet( OStatement_Base* pStmt,connectivity::OSQLParseTreeIterator& _aSQLIterator)
+ : file::OResultSet(pStmt,_aSQLIterator)
+ ,m_bBookmarkable(true)
+{
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISBOOKMARKABLE), PROPERTY_ID_ISBOOKMARKABLE, PropertyAttribute::READONLY,&m_bBookmarkable, cppu::UnoType<bool>::get());
+}
+
+OUString SAL_CALL OComponentResultSet::getImplementationName( )
+{
+ return "com.sun.star.sdbcx.component.ResultSet";
+}
+
+Sequence< OUString > SAL_CALL OComponentResultSet::getSupportedServiceNames( )
+{
+ return { "com.sun.star.sdbc.ResultSet", "com.sun.star.sdbcx.ResultSet" };
+}
+
+sal_Bool SAL_CALL OComponentResultSet::supportsService( const OUString& _rServiceName )
+{
+ return cppu::supportsService(this, _rServiceName);
+}
+
+Any SAL_CALL OComponentResultSet::queryInterface( const Type & rType )
+{
+ Any aRet = OResultSet::queryInterface(rType);
+ return aRet.hasValue() ? aRet : OComponentResultSet_BASE::queryInterface(rType);
+}
+
+ Sequence< Type > SAL_CALL OComponentResultSet::getTypes( )
+{
+ return ::comphelper::concatSequences(OResultSet::getTypes(),OComponentResultSet_BASE::getTypes());
+}
+
+
+// XRowLocate
+Any SAL_CALL OComponentResultSet::getBookmark( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+
+ return Any((*m_aRow)[0]->getValue().getInt32());
+}
+
+sal_Bool SAL_CALL OComponentResultSet::moveToBookmark( const Any& bookmark )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+
+ m_bRowDeleted = m_bRowInserted = m_bRowUpdated = false;
+
+ return Move(IResultSetHelper::BOOKMARK,comphelper::getINT32(bookmark),true);
+}
+
+sal_Bool SAL_CALL OComponentResultSet::moveRelativeToBookmark( const Any& bookmark, sal_Int32 rows )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+
+ m_bRowDeleted = m_bRowInserted = m_bRowUpdated = false;
+
+ Move(IResultSetHelper::BOOKMARK,comphelper::getINT32(bookmark),false);
+
+ return relative(rows);
+}
+
+
+sal_Int32 SAL_CALL OComponentResultSet::compareBookmarks( const Any& lhs, const Any& rhs )
+{
+ return (lhs == rhs) ? CompareBookmark::EQUAL : CompareBookmark::NOT_EQUAL;
+}
+
+sal_Bool SAL_CALL OComponentResultSet::hasOrderedBookmarks( )
+{
+ return true;
+}
+
+sal_Int32 SAL_CALL OComponentResultSet::hashBookmark( const Any& bookmark )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+
+ return comphelper::getINT32(bookmark);
+}
+
+// XDeleteRows
+Sequence< sal_Int32 > SAL_CALL OComponentResultSet::deleteRows( const Sequence< Any >& /*rows*/ )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ ::dbtools::throwFeatureNotImplementedSQLException( "XDeleteRows::deleteRows", *this );
+ return Sequence< sal_Int32 >();
+}
+
+bool OComponentResultSet::fillIndexValues(const Reference< XColumnsSupplier> &/*_xIndex*/)
+{
+ // Writer or Calc table has no index
+ return false;
+}
+
+::cppu::IPropertyArrayHelper & OComponentResultSet::getInfoHelper()
+{
+ return *OComponentResultSet_BASE3::getArrayHelper();
+}
+
+::cppu::IPropertyArrayHelper* OComponentResultSet::createArrayHelper() const
+{
+ Sequence< Property > aProps;
+ describeProperties(aProps);
+ return new ::cppu::OPropertyArrayHelper(aProps);
+}
+
+
+void SAL_CALL OComponentResultSet::acquire() noexcept
+{
+ OComponentResultSet_BASE2::acquire();
+}
+
+void SAL_CALL OComponentResultSet::release() noexcept
+{
+ OComponentResultSet_BASE2::release();
+}
+
+css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL OComponentResultSet::getPropertySetInfo( )
+{
+ return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper());
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/component/CStatement.cxx b/connectivity/source/drivers/component/CStatement.cxx
new file mode 100644
index 0000000000..f3bd03e8b2
--- /dev/null
+++ b/connectivity/source/drivers/component/CStatement.cxx
@@ -0,0 +1,35 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <component/CStatement.hxx>
+#include <component/CResultSet.hxx>
+
+using namespace connectivity::component;
+using namespace connectivity::file;
+using namespace com::sun::star::uno;
+
+rtl::Reference<OResultSet> OComponentStatement::createResultSet()
+{
+ return new connectivity::component::OComponentResultSet(this, m_aSQLIterator);
+}
+
+IMPLEMENT_SERVICE_INFO(OComponentStatement, "com.sun.star.sdbc.driver.component.Statement",
+ "com.sun.star.sdbc.Statement");
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/component/CTable.cxx b/connectivity/source/drivers/component/CTable.cxx
new file mode 100644
index 0000000000..819ce7a970
--- /dev/null
+++ b/connectivity/source/drivers/component/CTable.cxx
@@ -0,0 +1,189 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <component/CTable.hxx>
+#include <component/CColumns.hxx>
+#include <cppuhelper/queryinterface.hxx>
+
+using namespace connectivity;
+using namespace connectivity::component;
+using namespace connectivity::file;
+using namespace ::cppu;
+using namespace ::dbtools;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::sheet;
+using namespace ::com::sun::star::util;
+
+
+OComponentTable::OComponentTable(sdbcx::OCollection* _pTables,file::OConnection* _pConnection,
+ const OUString& Name,
+ const OUString& Type,
+ const OUString& Description ,
+ const OUString& SchemaName,
+ const OUString& CatalogName
+ ) : OComponentTable_BASE(_pTables,_pConnection,Name,
+ Type,
+ Description,
+ SchemaName,
+ CatalogName)
+ ,m_nDataRows(0)
+{
+}
+
+void OComponentTable::refreshColumns()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ ::std::vector< OUString> aVector;
+
+ for(const auto& rxColumn : *m_aColumns)
+ aVector.push_back(Reference< XNamed>(rxColumn,UNO_QUERY_THROW)->getName());
+
+ if(m_xColumns)
+ m_xColumns->reFill(aVector);
+ else
+ m_xColumns.reset(new component::OComponentColumns(this,m_aMutex,aVector));
+}
+
+void OComponentTable::refreshIndexes()
+{
+ // Writer or Calc table has no index
+}
+
+
+Sequence< Type > SAL_CALL OComponentTable::getTypes( )
+{
+ Sequence< Type > aTypes = OTable_TYPEDEF::getTypes();
+ std::vector<Type> aOwnTypes;
+ aOwnTypes.reserve(aTypes.getLength());
+
+ const Type* pBegin = aTypes.getConstArray();
+ const Type* pEnd = pBegin + aTypes.getLength();
+ for(;pBegin != pEnd;++pBegin)
+ {
+ if(!( *pBegin == cppu::UnoType<XKeysSupplier>::get()||
+ *pBegin == cppu::UnoType<XIndexesSupplier>::get()||
+ *pBegin == cppu::UnoType<XRename>::get()||
+ *pBegin == cppu::UnoType<XAlterTable>::get()||
+ *pBegin == cppu::UnoType<XDataDescriptorFactory>::get()))
+ aOwnTypes.push_back(*pBegin);
+ }
+ aOwnTypes.push_back(cppu::UnoType<css::lang::XUnoTunnel>::get());
+
+ return Sequence< Type >(aOwnTypes.data(), aOwnTypes.size());
+}
+
+
+Any SAL_CALL OComponentTable::queryInterface( const Type & rType )
+{
+ if( rType == cppu::UnoType<XKeysSupplier>::get()||
+ rType == cppu::UnoType<XIndexesSupplier>::get()||
+ rType == cppu::UnoType<XRename>::get()||
+ rType == cppu::UnoType<XAlterTable>::get()||
+ rType == cppu::UnoType<XDataDescriptorFactory>::get())
+ return Any();
+
+ return OTable_TYPEDEF::queryInterface(rType);
+}
+
+
+sal_Int32 OComponentTable::getCurrentLastPos() const
+{
+ return m_nDataRows;
+}
+
+bool OComponentTable::seekRow(IResultSetHelper::Movement eCursorPosition, sal_Int32 nOffset, sal_Int32& nCurPos)
+{
+ // prepare positioning:
+
+ sal_uInt32 nNumberOfRecords = m_nDataRows;
+ sal_uInt32 nTempPos = m_nFilePos;
+ m_nFilePos = nCurPos;
+
+ switch(eCursorPosition)
+ {
+ case IResultSetHelper::NEXT:
+ m_nFilePos++;
+ break;
+ case IResultSetHelper::PRIOR:
+ if (m_nFilePos > 0)
+ m_nFilePos--;
+ break;
+ case IResultSetHelper::FIRST:
+ m_nFilePos = 1;
+ break;
+ case IResultSetHelper::LAST:
+ m_nFilePos = nNumberOfRecords;
+ break;
+ case IResultSetHelper::RELATIVE1:
+ m_nFilePos = (m_nFilePos + nOffset < 0) ? 0
+ : static_cast<sal_uInt32>(m_nFilePos + nOffset);
+ break;
+ case IResultSetHelper::ABSOLUTE1:
+ case IResultSetHelper::BOOKMARK:
+ m_nFilePos = static_cast<sal_uInt32>(nOffset);
+ break;
+ }
+
+ if (m_nFilePos > static_cast<sal_Int32>(nNumberOfRecords))
+ m_nFilePos = static_cast<sal_Int32>(nNumberOfRecords) + 1;
+
+ if (m_nFilePos == 0 || m_nFilePos == static_cast<sal_Int32>(nNumberOfRecords) + 1)
+ {
+ switch(eCursorPosition)
+ {
+ case IResultSetHelper::PRIOR:
+ case IResultSetHelper::FIRST:
+ m_nFilePos = 0;
+ break;
+ case IResultSetHelper::LAST:
+ case IResultSetHelper::NEXT:
+ case IResultSetHelper::ABSOLUTE1:
+ case IResultSetHelper::RELATIVE1:
+ if (nOffset > 0)
+ m_nFilePos = nNumberOfRecords + 1;
+ else if (nOffset < 0)
+ m_nFilePos = 0;
+ break;
+ case IResultSetHelper::BOOKMARK:
+ m_nFilePos = nTempPos; // previous position
+ break;
+ }
+ return false;
+ }
+
+ //! read buffer / setup row object etc?
+ nCurPos = m_nFilePos;
+ return true;
+}
+
+void OComponentTable::FileClose()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+
+ OComponentTable_BASE::FileClose();
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/dbase/DCatalog.cxx b/connectivity/source/drivers/dbase/DCatalog.cxx
new file mode 100644
index 0000000000..a8aaf89c52
--- /dev/null
+++ b/connectivity/source/drivers/dbase/DCatalog.cxx
@@ -0,0 +1,57 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <dbase/DCatalog.hxx>
+#include <dbase/DConnection.hxx>
+#include <dbase/DTables.hxx>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XResultSet.hpp>
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::container;
+
+using namespace connectivity::dbase;
+
+ODbaseCatalog::ODbaseCatalog(ODbaseConnection* _pCon)
+ : file::OFileCatalog(_pCon)
+{
+}
+
+void ODbaseCatalog::refreshTables()
+{
+ ::std::vector<OUString> aVector;
+ Sequence<OUString> aTypes;
+ Reference<XResultSet> xResult = m_xMetaData->getTables(Any(), "%", "%", aTypes);
+
+ if (xResult.is())
+ {
+ Reference<XRow> xRow(xResult, UNO_QUERY);
+ while (xResult->next())
+ aVector.push_back(xRow->getString(3));
+ }
+ if (m_pTables)
+ m_pTables->reFill(aVector);
+ else
+ m_pTables.reset(new ODbaseTables(m_xMetaData, *this, m_aMutex, aVector));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/dbase/DColumns.cxx b/connectivity/source/drivers/dbase/DColumns.cxx
new file mode 100644
index 0000000000..b997ec8d90
--- /dev/null
+++ b/connectivity/source/drivers/dbase/DColumns.cxx
@@ -0,0 +1,77 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <dbase/DColumns.hxx>
+#include <dbase/DTable.hxx>
+#include <connectivity/sdbcx/VColumn.hxx>
+
+using namespace connectivity::dbase;
+using namespace connectivity;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::container;
+
+sdbcx::ObjectType ODbaseColumns::createObject(const OUString& _rName)
+{
+ ODbaseTable* pTable = static_cast<ODbaseTable*>(m_pTable);
+
+ const ::rtl::Reference<OSQLColumns>& aCols = pTable->getTableColumns();
+ OSQLColumns::const_iterator aIter = find(aCols->begin(),aCols->end(),_rName,::comphelper::UStringMixEqual(isCaseSensitive()));
+
+ sdbcx::ObjectType xRet;
+ if(aIter != aCols->end())
+ xRet = sdbcx::ObjectType(*aIter,UNO_QUERY);
+ return xRet;
+}
+
+
+void ODbaseColumns::impl_refresh()
+{
+ m_pTable->refreshColumns();
+}
+
+Reference< XPropertySet > ODbaseColumns::createDescriptor()
+{
+ return new sdbcx::OColumn(isCaseSensitive());
+}
+
+
+// XAppend
+sdbcx::ObjectType ODbaseColumns::appendObject( const OUString& _rForName, const Reference< XPropertySet >& descriptor )
+{
+ if ( m_pTable->isNew() )
+ return cloneDescriptor( descriptor );
+
+ m_pTable->addColumn( descriptor );
+ return createObject( _rForName );
+}
+
+
+// XDrop
+void ODbaseColumns::dropObject(sal_Int32 _nPos, const OUString& /*_sElementName*/)
+{
+ if(!m_pTable->isNew())
+ m_pTable->dropColumn(_nPos);
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/dbase/DConnection.cxx b/connectivity/source/drivers/dbase/DConnection.cxx
new file mode 100644
index 0000000000..c9c7a93fa9
--- /dev/null
+++ b/connectivity/source/drivers/dbase/DConnection.cxx
@@ -0,0 +1,112 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <dbase/DConnection.hxx>
+#include <dbase/DDatabaseMetaData.hxx>
+#include <dbase/DCatalog.hxx>
+#include <dbase/DDriver.hxx>
+#include <dbase/DPreparedStatement.hxx>
+#include <dbase/DStatement.hxx>
+#include <connectivity/dbexception.hxx>
+
+using namespace connectivity::dbase;
+using namespace connectivity::file;
+
+typedef connectivity::file::OConnection OConnection_BASE;
+
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::lang;
+
+ODbaseConnection::ODbaseConnection(ODriver* _pDriver) : OConnection(_pDriver)
+{
+ m_aFilenameExtension = "dbf";
+}
+
+ODbaseConnection::~ODbaseConnection()
+{
+}
+
+// XServiceInfo
+
+IMPLEMENT_SERVICE_INFO(ODbaseConnection, "com.sun.star.sdbc.drivers.dbase.Connection", "com.sun.star.sdbc.Connection")
+
+
+Reference< XDatabaseMetaData > SAL_CALL ODbaseConnection::getMetaData( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OConnection_BASE::rBHelper.bDisposed);
+
+
+ Reference< XDatabaseMetaData > xMetaData = m_xMetaData;
+ if(!xMetaData.is())
+ {
+ xMetaData = new ODbaseDatabaseMetaData(this);
+ m_xMetaData = xMetaData;
+ }
+
+ return xMetaData;
+}
+
+css::uno::Reference< XTablesSupplier > ODbaseConnection::createCatalog()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ Reference< XTablesSupplier > xTab = m_xCatalog;
+ if(!xTab.is())
+ {
+ xTab = new ODbaseCatalog(this);
+ m_xCatalog = xTab;
+ }
+ return xTab;
+}
+
+Reference< XStatement > SAL_CALL ODbaseConnection::createStatement( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OConnection_BASE::rBHelper.bDisposed);
+
+
+ Reference< XStatement > xReturn = new ODbaseStatement(this);
+ m_aStatements.push_back(WeakReferenceHelper(xReturn));
+ return xReturn;
+}
+
+Reference< XPreparedStatement > SAL_CALL ODbaseConnection::prepareStatement( const OUString& sql )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OConnection_BASE::rBHelper.bDisposed);
+
+ rtl::Reference<ODbasePreparedStatement> pStmt = new ODbasePreparedStatement(this);
+ pStmt->construct(sql);
+ m_aStatements.push_back(WeakReferenceHelper(*pStmt));
+ return pStmt;
+}
+
+Reference< XPreparedStatement > SAL_CALL ODbaseConnection::prepareCall( const OUString& /*sql*/ )
+{
+ ::dbtools::throwFeatureNotImplementedSQLException( "XConnection::prepareCall", *this );
+ return nullptr;
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/dbase/DDatabaseMetaData.cxx b/connectivity/source/drivers/dbase/DDatabaseMetaData.cxx
new file mode 100644
index 0000000000..b3791f7d85
--- /dev/null
+++ b/connectivity/source/drivers/dbase/DDatabaseMetaData.cxx
@@ -0,0 +1,381 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <dbase/DDatabaseMetaData.hxx>
+#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
+#include <com/sun/star/sdbc/ColumnSearch.hpp>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <com/sun/star/sdbc/ColumnValue.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
+#include <com/sun/star/sdbcx/XIndexesSupplier.hpp>
+#include <FDatabaseMetaDataResultSet.hxx>
+#include <dbase/DIndex.hxx>
+#include <connectivity/FValue.hxx>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <comphelper/types.hxx>
+#include <ucbhelper/content.hxx>
+
+using namespace ::comphelper;
+using namespace connectivity::dbase;
+using namespace connectivity;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::ucb;
+using namespace ::com::sun::star::lang;
+
+ODbaseDatabaseMetaData::ODbaseDatabaseMetaData(::connectivity::file::OConnection* _pCon) :ODatabaseMetaData(_pCon)
+{
+}
+
+ODbaseDatabaseMetaData::~ODbaseDatabaseMetaData()
+{
+}
+
+Reference< XResultSet > ODbaseDatabaseMetaData::impl_getTypeInfo_throw( )
+{
+ rtl::Reference<::connectivity::ODatabaseMetaDataResultSet> pResult = new ::connectivity::ODatabaseMetaDataResultSet(::connectivity::ODatabaseMetaDataResultSet::eTypeInfo);
+
+ ODatabaseMetaDataResultSet::ORows aRows;
+ aRows.reserve(10);
+ ODatabaseMetaDataResultSet::ORow aRow
+ {
+ ODatabaseMetaDataResultSet::getEmptyValue(),
+ new ORowSetValueDecorator(OUString("VARCHAR")),
+ new ORowSetValueDecorator(DataType::VARCHAR),
+ new ORowSetValueDecorator(sal_Int32(254)),
+ ODatabaseMetaDataResultSet::getQuoteValue(),
+ ODatabaseMetaDataResultSet::getQuoteValue(),
+ new ORowSetValueDecorator(OUString("length")),
+ new ORowSetValueDecorator(sal_Int32(ColumnValue::NULLABLE)),
+ ODatabaseMetaDataResultSet::get1Value(),
+ new ORowSetValueDecorator(sal_Int32(ColumnSearch::FULL)),
+ ODatabaseMetaDataResultSet::get1Value(),
+ ODatabaseMetaDataResultSet::get0Value(),
+ ODatabaseMetaDataResultSet::get0Value(),
+ new ORowSetValueDecorator(OUString("C")),
+ ODatabaseMetaDataResultSet::get0Value(),
+ ODatabaseMetaDataResultSet::get0Value(),
+ ODatabaseMetaDataResultSet::getEmptyValue(),
+ ODatabaseMetaDataResultSet::getEmptyValue(),
+ new ORowSetValueDecorator(sal_Int32(10))
+ };
+
+ aRows.push_back(aRow);
+
+ aRow[1] = new ORowSetValueDecorator(OUString("LONGVARCHAR"));
+ aRow[2] = new ORowSetValueDecorator(DataType::LONGVARCHAR);
+ aRow[3] = new ORowSetValueDecorator(sal_Int32(2147483647));
+ aRow[6] = new ORowSetValueDecorator();
+ aRow[13] = new ORowSetValueDecorator(OUString("M"));
+ aRows.push_back(aRow);
+
+ aRow[1] = new ORowSetValueDecorator(OUString("DATE"));
+ aRow[2] = new ORowSetValueDecorator(DataType::DATE);
+ aRow[3] = new ORowSetValueDecorator(sal_Int32(10));
+ aRow[13] = new ORowSetValueDecorator(OUString("D"));
+ aRows.push_back(aRow);
+
+ aRow[1] = new ORowSetValueDecorator(OUString("BOOLEAN"));
+ aRow[2] = new ORowSetValueDecorator(DataType::BIT);
+ aRow[3] = ODatabaseMetaDataResultSet::get1Value();
+ aRow[4] = ODatabaseMetaDataResultSet::getEmptyValue();
+ aRow[5] = ODatabaseMetaDataResultSet::getEmptyValue();
+ aRow[6] = new ORowSetValueDecorator(OUString());
+ aRow[9] = ODatabaseMetaDataResultSet::getBasicValue();
+ aRow[13] = new ORowSetValueDecorator(OUString("L"));
+ aRows.push_back(aRow);
+
+ aRow[1] = new ORowSetValueDecorator(OUString("DOUBLE"));
+ aRow[2] = new ORowSetValueDecorator(DataType::DOUBLE);
+ aRow[3] = new ORowSetValueDecorator(sal_Int32(8));
+ aRow[13] = new ORowSetValueDecorator(OUString("B"));
+ aRows.push_back(aRow);
+
+ aRow[11] = new ORowSetValueDecorator(ORowSetValue(true));
+ aRow[13] = new ORowSetValueDecorator(OUString("Y"));
+ aRows.push_back(aRow);
+
+ aRow[1] = new ORowSetValueDecorator(OUString("TIMESTAMP"));
+ aRow[2] = new ORowSetValueDecorator(DataType::TIMESTAMP);
+ aRow[11] = new ORowSetValueDecorator(ORowSetValue(false));
+ aRow[13] = new ORowSetValueDecorator(OUString("T"));
+ aRows.push_back(aRow);
+
+ aRow[1] = new ORowSetValueDecorator(OUString("INTEGER"));
+ aRow[2] = new ORowSetValueDecorator(DataType::INTEGER);
+ aRow[3] = new ORowSetValueDecorator(sal_Int32(10));
+ aRow[13] = new ORowSetValueDecorator(OUString("I"));
+ aRows.push_back(aRow);
+
+ aRow[1] = new ORowSetValueDecorator(OUString("DECIMAL"));
+ aRow[2] = new ORowSetValueDecorator(DataType::DECIMAL);
+ aRow[3] = new ORowSetValueDecorator(sal_Int32(20));
+ aRow[6] = new ORowSetValueDecorator(OUString("length,scale"));
+ aRow[13] = new ORowSetValueDecorator(OUString("F"));
+ aRows.push_back(aRow);
+
+ aRow[1] = new ORowSetValueDecorator(OUString("NUMERIC"));
+ aRow[2] = new ORowSetValueDecorator(DataType::DECIMAL);
+ aRow[3] = new ORowSetValueDecorator(sal_Int32(16));
+ aRow[13] = new ORowSetValueDecorator(OUString("N"));
+ aRow[15] = new ORowSetValueDecorator(sal_Int32(16));
+ aRows.push_back(aRow);
+
+ pResult->setRows(std::move(aRows));
+ return pResult;
+}
+
+Reference< XResultSet > SAL_CALL ODbaseDatabaseMetaData::getColumns(
+ const Any& /*catalog*/, const OUString& /*schemaPattern*/, const OUString& tableNamePattern,
+ const OUString& columnNamePattern )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ Reference< XTablesSupplier > xTables = m_pConnection->createCatalog();
+ if(!xTables.is())
+ throw SQLException();
+
+ Reference< XNameAccess> xNames = xTables->getTables();
+ if(!xNames.is())
+ throw SQLException();
+
+ ODatabaseMetaDataResultSet::ORows aRows;
+ ODatabaseMetaDataResultSet::ORow aRow(19);
+
+ try
+ {
+ aRow[10] = new ORowSetValueDecorator(sal_Int32(10));
+ Sequence< OUString> aTabNames(xNames->getElementNames());
+ const OUString* pTabBegin = aTabNames.getConstArray();
+ const OUString* pTabEnd = pTabBegin + aTabNames.getLength();
+ for(;pTabBegin != pTabEnd;++pTabBegin)
+ {
+ if(match(tableNamePattern,*pTabBegin,'\0'))
+ {
+ Reference< XColumnsSupplier> xTable(
+ xNames->getByName(*pTabBegin), css::uno::UNO_QUERY);
+ OSL_ENSURE(xTable.is(),"Table not found! Normally an exception had to be thrown here!");
+ aRow[3] = new ORowSetValueDecorator(*pTabBegin);
+
+ Reference< XNameAccess> xColumns = xTable->getColumns();
+ if(!xColumns.is())
+ throw SQLException();
+
+ Sequence< OUString> aColNames(xColumns->getElementNames());
+
+ const OUString* pBegin = aColNames.getConstArray();
+ const OUString* pEnd = pBegin + aColNames.getLength();
+ Reference< XPropertySet> xColumn;
+ for(sal_Int32 i=1;pBegin != pEnd;++pBegin,++i)
+ {
+ if(match(columnNamePattern,*pBegin,'\0'))
+ {
+ aRow[4] = new ORowSetValueDecorator(*pBegin);
+
+ xColumn.set(
+ xColumns->getByName(*pBegin), css::uno::UNO_QUERY);
+ OSL_ENSURE(xColumn.is(),"Columns contains a column who isn't a fastpropertyset!");
+ aRow[5] = new ORowSetValueDecorator(getINT32(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE))));
+ aRow[6] = new ORowSetValueDecorator(getString(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPENAME))));
+ aRow[7] = new ORowSetValueDecorator(getINT32(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PRECISION))));
+ aRow[9] = new ORowSetValueDecorator(getINT32(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCALE))));
+ aRow[11] = new ORowSetValueDecorator(getINT32(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISNULLABLE))));
+ aRow[13] = new ORowSetValueDecorator(getString(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DEFAULTVALUE))));
+ switch(aRow[5]->getValue().getInt32())
+ {
+ case DataType::CHAR:
+ case DataType::VARCHAR:
+ aRow[16] = new ORowSetValueDecorator(sal_Int32(254));
+ break;
+ case DataType::LONGVARCHAR:
+ aRow[16] = new ORowSetValueDecorator(sal_Int32(65535));
+ break;
+ default:
+ aRow[16] = new ORowSetValueDecorator(sal_Int32(0));
+ }
+ aRow[17] = new ORowSetValueDecorator(i);
+ switch(aRow[11]->getValue().getInt32())
+ {
+ case ColumnValue::NO_NULLS:
+ aRow[18] = new ORowSetValueDecorator(OUString("NO"));
+ break;
+ case ColumnValue::NULLABLE:
+ aRow[18] = new ORowSetValueDecorator(OUString("YES"));
+ break;
+ default:
+ aRow[18] = new ORowSetValueDecorator(OUString());
+ }
+ aRows.push_back(aRow);
+ }
+ }
+ }
+ }
+ }
+ catch (const WrappedTargetException& e)
+ {
+ SQLException aSql;
+ if (e.TargetException >>= aSql)
+ throw aSql;
+ throw WrappedTargetRuntimeException(e.Message, e.Context, e.TargetException);
+ }
+ rtl::Reference<::connectivity::ODatabaseMetaDataResultSet> pResult = new ::connectivity::ODatabaseMetaDataResultSet(::connectivity::ODatabaseMetaDataResultSet::eColumns);
+ pResult->setRows(std::move(aRows));
+
+ return pResult;
+}
+
+Reference< XResultSet > SAL_CALL ODbaseDatabaseMetaData::getIndexInfo(
+ const Any& /*catalog*/, const OUString& /*schema*/, const OUString& table,
+ sal_Bool unique, sal_Bool /*approximate*/ )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ Reference< XTablesSupplier > xTables = m_pConnection->createCatalog();
+ if(!xTables.is())
+ throw SQLException();
+
+ Reference< XNameAccess> xNames = xTables->getTables();
+ if(!xNames.is())
+ throw SQLException();
+
+ ODatabaseMetaDataResultSet::ORows aRows;
+ ODatabaseMetaDataResultSet::ORow aRow(14);
+
+ aRow[5] = new ORowSetValueDecorator(OUString());
+ aRow[10] = new ORowSetValueDecorator(OUString("A"));
+
+ Reference< XIndexesSupplier> xTable(
+ xNames->getByName(table), css::uno::UNO_QUERY);
+ aRow[3] = new ORowSetValueDecorator(table);
+ aRow[7] = new ORowSetValueDecorator(sal_Int32(3));
+
+ Reference< XNameAccess> xIndexes = xTable->getIndexes();
+ if(!xIndexes.is())
+ throw SQLException();
+
+ Sequence< OUString> aIdxNames(xIndexes->getElementNames());
+
+ const OUString* pBegin = aIdxNames.getConstArray();
+ const OUString* pEnd = pBegin + aIdxNames.getLength();
+ Reference< XPropertySet> xIndex;
+ for(;pBegin != pEnd;++pBegin)
+ {
+ xIndex.set(xIndexes->getByName(*pBegin), css::uno::UNO_QUERY);
+ OSL_ENSURE(xIndex.is(),"Indexes contains a column who isn't a fastpropertyset!");
+
+ if(unique && !getBOOL(xIndex->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISUNIQUE))))
+ continue;
+ aRow[4] = new ORowSetValueDecorator(ORowSetValue(getBOOL(xIndex->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISUNIQUE)))));
+ aRow[6] = new ORowSetValueDecorator(*pBegin);
+
+ auto pIndex = dynamic_cast<ODbaseIndex*>(xIndex.get());
+ if(pIndex)
+ {
+ aRow[11] = new ORowSetValueDecorator(static_cast<sal_Int32>(pIndex->getHeader().db_maxkeys));
+ aRow[12] = new ORowSetValueDecorator(static_cast<sal_Int32>(pIndex->getHeader().db_pagecount));
+ }
+
+ Reference<XColumnsSupplier> xColumnsSup(xIndex,UNO_QUERY);
+ Reference< XNameAccess> xColumns = xColumnsSup->getColumns();
+ Sequence< OUString> aColNames(xColumns->getElementNames());
+
+ const OUString* pColBegin = aColNames.getConstArray();
+ const OUString* pColEnd = pColBegin + aColNames.getLength();
+ for(sal_Int32 j=1;pColBegin != pColEnd;++pColBegin,++j)
+ {
+ aRow[8] = new ORowSetValueDecorator(j);
+ aRow[9] = new ORowSetValueDecorator(*pColBegin);
+ aRows.push_back(aRow);
+ }
+ }
+
+ rtl::Reference<::connectivity::ODatabaseMetaDataResultSet> pResult = new ::connectivity::ODatabaseMetaDataResultSet(::connectivity::ODatabaseMetaDataResultSet::eIndexInfo);
+ pResult->setRows(std::move(aRows));
+ return pResult;
+}
+
+OUString SAL_CALL ODbaseDatabaseMetaData::getURL( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ return "sdbc:dbase:" + m_pConnection->getURL();
+}
+
+sal_Int32 SAL_CALL ODbaseDatabaseMetaData::getMaxBinaryLiteralLength( )
+{
+ return SAL_MAX_INT32;
+}
+
+sal_Int32 SAL_CALL ODbaseDatabaseMetaData::getMaxCharLiteralLength( )
+{
+ return 254;
+}
+
+sal_Int32 SAL_CALL ODbaseDatabaseMetaData::getMaxColumnNameLength( )
+{
+ return 10;
+}
+
+sal_Int32 SAL_CALL ODbaseDatabaseMetaData::getMaxColumnsInIndex( )
+{
+ return 1;
+}
+
+sal_Int32 SAL_CALL ODbaseDatabaseMetaData::getMaxColumnsInTable( )
+{
+ return 128;
+}
+
+sal_Bool SAL_CALL ODbaseDatabaseMetaData::supportsAlterTableWithAddColumn( )
+{
+ return true;
+}
+
+sal_Bool SAL_CALL ODbaseDatabaseMetaData::supportsAlterTableWithDropColumn( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODbaseDatabaseMetaData::isReadOnly( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ bool bReadOnly = false;
+ ::ucbhelper::Content aFile(m_pConnection->getContent(),Reference< XCommandEnvironment >(), comphelper::getProcessComponentContext());
+ aFile.getPropertyValue("IsReadOnly") >>= bReadOnly;
+
+ return bReadOnly;
+}
+
+bool ODbaseDatabaseMetaData::impl_storesMixedCaseQuotedIdentifiers_throw( )
+{
+ return true;
+}
+
+bool ODbaseDatabaseMetaData::impl_supportsMixedCaseQuotedIdentifiers_throw( )
+{
+ return true;
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/dbase/DDriver.cxx b/connectivity/source/drivers/dbase/DDriver.cxx
new file mode 100644
index 0000000000..ff0ec256e1
--- /dev/null
+++ b/connectivity/source/drivers/dbase/DDriver.cxx
@@ -0,0 +1,118 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <dbase/DDriver.hxx>
+#include <dbase/DConnection.hxx>
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <connectivity/dbexception.hxx>
+#include <strings.hrc>
+
+using namespace connectivity::dbase;
+using namespace connectivity::file;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::lang;
+
+
+// XServiceInfo
+
+OUString SAL_CALL ODriver::getImplementationName( )
+{
+ return "com.sun.star.comp.sdbc.dbase.ODriver";
+}
+
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+connectivity_dbase_ODriver(
+ css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const&)
+{
+ rtl::Reference<ODriver> ret;
+ try {
+ ret = new ODriver(context);
+ } catch (...) {
+ }
+ if (ret)
+ ret->acquire();
+ return getXWeak(ret.get());
+}
+
+
+Reference< XConnection > SAL_CALL ODriver::connect( const OUString& url, const Sequence< PropertyValue >& info )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if (ODriver_BASE::rBHelper.bDisposed)
+ throw DisposedException();
+
+ if ( ! acceptsURL(url) )
+ return nullptr;
+
+ rtl::Reference<ODbaseConnection> pCon = new ODbaseConnection(this);
+ pCon->construct(url,info);
+ m_xConnections.push_back(WeakReferenceHelper(*pCon));
+
+ return pCon;
+}
+
+sal_Bool SAL_CALL ODriver::acceptsURL( const OUString& url )
+{
+ return url.startsWith("sdbc:dbase:");
+}
+
+Sequence< DriverPropertyInfo > SAL_CALL ODriver::getPropertyInfo( const OUString& url, const Sequence< PropertyValue >& /*info*/ )
+{
+ if ( acceptsURL(url) )
+ {
+ Sequence< OUString > aBoolean { "0", "1" };
+
+ return
+ {
+ {
+ "CharSet"
+ ,"CharSet of the database."
+ ,false
+ ,OUString()
+ ,Sequence< OUString >()
+ },
+ {
+ "ShowDeleted"
+ ,"Display inactive records."
+ ,false
+ ,"0"
+ ,aBoolean
+ },
+ {
+ "EnableSQL92Check"
+ ,"Use SQL92 naming constraints."
+ ,false
+ ,"0"
+ ,aBoolean
+ }
+ };
+ }
+
+ SharedResources aResources;
+ const OUString sMessage = aResources.getResourceString(STR_URI_SYNTAX_ERROR);
+ ::dbtools::throwGenericSQLException(sMessage ,*this);
+ return Sequence< DriverPropertyInfo >();
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/dbase/DIndex.cxx b/connectivity/source/drivers/dbase/DIndex.cxx
new file mode 100644
index 0000000000..cc489ad77c
--- /dev/null
+++ b/connectivity/source/drivers/dbase/DIndex.cxx
@@ -0,0 +1,591 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <dbase/DIndex.hxx>
+#include <dbase/DIndexColumns.hxx>
+#include <dbase/DTable.hxx>
+#include <dbase/DIndexIter.hxx>
+#include <osl/file.hxx>
+#include <sal/log.hxx>
+#include <tools/config.hxx>
+#include <connectivity/CommonTools.hxx>
+#include <com/sun/star/sdbc/XResultSet.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <unotools/ucbhelper.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <comphelper/types.hxx>
+#include <connectivity/dbexception.hxx>
+#include <dbase/DResultSet.hxx>
+#include <strings.hrc>
+#include <unotools/sharedunocomponent.hxx>
+
+using namespace ::comphelper;
+
+using namespace connectivity;
+using namespace utl;
+using namespace ::cppu;
+using namespace connectivity::file;
+using namespace connectivity::sdbcx;
+using namespace connectivity::dbase;
+using namespace com::sun::star::sdbc;
+using namespace com::sun::star::sdbcx;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::lang;
+
+IMPLEMENT_SERVICE_INFO(ODbaseIndex,"com.sun.star.sdbcx.driver.dbase.Index","com.sun.star.sdbcx.Index");
+
+ODbaseIndex::ODbaseIndex(ODbaseTable* _pTable)
+ : OIndex(true/*_pTable->getConnection()->getMetaData()->supportsMixedCaseQuotedIdentifiers()*/)
+ , m_nCurNode(NODE_NOTFOUND)
+ , m_nPageCount(0)
+ , m_nRootPage(0)
+ , m_pTable(_pTable)
+ , m_bUseCollector(false)
+{
+ construct();
+}
+
+ODbaseIndex::ODbaseIndex( ODbaseTable* _pTable,
+ const NDXHeader& _rHeader,
+ const OUString& _rName)
+ : OIndex(_rName, OUString(), _rHeader.db_unique, false, false, true)
+ , m_aHeader(_rHeader)
+ , m_nCurNode(NODE_NOTFOUND)
+ , m_nPageCount(0)
+ , m_nRootPage(0)
+ , m_pTable(_pTable)
+ , m_bUseCollector(false)
+{
+ construct();
+}
+
+ODbaseIndex::~ODbaseIndex()
+{
+ closeImpl();
+}
+
+void ODbaseIndex::refreshColumns()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ ::std::vector< OUString> aVector;
+ if(!isNew())
+ {
+ OSL_ENSURE(m_pFileStream,"FileStream is not opened!");
+ OSL_ENSURE(m_aHeader.db_name[0] != '\0',"Invalid name for the column!");
+ aVector.push_back(OUString::createFromAscii(m_aHeader.db_name));
+ }
+
+ if(m_pColumns)
+ m_pColumns->reFill(aVector);
+ else
+ m_pColumns.reset(new ODbaseIndexColumns(this,m_aMutex,aVector));
+}
+
+ONDXPagePtr const & ODbaseIndex::getRoot()
+{
+ openIndexFile();
+ if (!m_aRoot.Is())
+ {
+ m_nRootPage = m_aHeader.db_rootpage;
+ m_nPageCount = m_aHeader.db_pagecount;
+ m_aRoot = CreatePage(m_nRootPage,nullptr,true);
+ }
+ return m_aRoot;
+}
+
+void ODbaseIndex::openIndexFile()
+{
+ if(m_pFileStream)
+ return;
+
+ OUString sFile = getCompletePath();
+ if(UCBContentHelper::Exists(sFile))
+ {
+ m_pFileStream = OFileTable::createStream_simpleError(sFile, StreamMode::READWRITE | StreamMode::NOCREATE | StreamMode::SHARE_DENYWRITE);
+ if (!m_pFileStream)
+ m_pFileStream = OFileTable::createStream_simpleError(sFile, StreamMode::READ | StreamMode::NOCREATE | StreamMode::SHARE_DENYNONE);
+ if(m_pFileStream)
+ {
+ m_pFileStream->SetEndian(SvStreamEndian::LITTLE);
+ m_pFileStream->SetBufferSize(DINDEX_PAGE_SIZE);
+ (*m_pFileStream) >> *this;
+ }
+ }
+ if(!m_pFileStream)
+ {
+ const OUString sError( m_pTable->getConnection()->getResources().getResourceStringWithSubstitution(
+ STR_COULD_NOT_LOAD_FILE,
+ "$filename$", sFile
+ ) );
+ ::dbtools::throwGenericSQLException( sError, *this );
+ }
+}
+
+std::unique_ptr<OIndexIterator> ODbaseIndex::createIterator()
+{
+ openIndexFile();
+ return std::make_unique<OIndexIterator>(this);
+}
+
+bool ODbaseIndex::ConvertToKey(ONDXKey* rKey, sal_uInt32 nRec, const ORowSetValue& rValue)
+{
+ OSL_ENSURE(m_pFileStream,"FileStream is not opened!");
+ // Search a specific value in Index
+ // If the Index is unique, the key doesn't matter
+ try
+ {
+ if (m_aHeader.db_keytype == 0)
+ {
+ *rKey = ONDXKey(rValue.getString(), nRec );
+ }
+ else
+ {
+ if (rValue.isNull())
+ *rKey = ONDXKey(rValue.getDouble(), DataType::DOUBLE, nRec );
+ else
+ *rKey = ONDXKey(rValue.getDouble(), nRec );
+ }
+ }
+ catch (Exception&)
+ {
+ OSL_ASSERT(false);
+ return false;
+ }
+ return true;
+}
+
+
+bool ODbaseIndex::Find(sal_uInt32 nRec, const ORowSetValue& rValue)
+{
+ openIndexFile();
+ OSL_ENSURE(m_pFileStream,"FileStream is not opened!");
+ // Search a specific value in Index
+ // If the Index is unique, the key doesn't matter
+ ONDXKey aKey;
+ return ConvertToKey(&aKey, nRec, rValue) && getRoot()->Find(aKey);
+}
+
+
+bool ODbaseIndex::Insert(sal_uInt32 nRec, const ORowSetValue& rValue)
+{
+ openIndexFile();
+ OSL_ENSURE(m_pFileStream,"FileStream is not opened!");
+ ONDXKey aKey;
+
+ // Does the value already exist
+ // Use Find() always to determine the actual leaf
+ if (!ConvertToKey(&aKey, nRec, rValue) || (getRoot()->Find(aKey) && isUnique()))
+ return false;
+
+ ONDXNode aNewNode(aKey);
+
+ // insert in the current leaf
+ if (!m_aCurLeaf.Is())
+ return false;
+
+ bool bResult = m_aCurLeaf->Insert(aNewNode);
+ Release(bResult);
+
+ return bResult;
+}
+
+
+bool ODbaseIndex::Update(sal_uInt32 nRec, const ORowSetValue& rOldValue,
+ const ORowSetValue& rNewValue)
+{
+ openIndexFile();
+ OSL_ENSURE(m_pFileStream,"FileStream is not opened!");
+ ONDXKey aKey;
+ if (!ConvertToKey(&aKey, nRec, rNewValue) || (isUnique() && getRoot()->Find(aKey)))
+ return false;
+ else
+ return Delete(nRec, rOldValue) && Insert(nRec,rNewValue);
+}
+
+
+bool ODbaseIndex::Delete(sal_uInt32 nRec, const ORowSetValue& rValue)
+{
+ openIndexFile();
+ OSL_ENSURE(m_pFileStream,"FileStream is not opened!");
+ // Does the value already exist
+ // Always use Find() to determine the actual leaf
+ ONDXKey aKey;
+ if (!ConvertToKey(&aKey, nRec, rValue) || !getRoot()->Find(aKey))
+ return false;
+
+ // insert in the current leaf
+ if (!m_aCurLeaf.Is())
+ return false;
+#if OSL_DEBUG_LEVEL > 1
+ m_aRoot->PrintPage();
+#endif
+
+ m_aCurLeaf->Delete(m_nCurNode);
+ return true;
+}
+
+void ODbaseIndex::Collect(ONDXPage* pPage)
+{
+ if (pPage)
+ m_aCollector.push_back(pPage);
+}
+
+void ODbaseIndex::Release(bool bSave)
+{
+ // Release the Index-resources
+ m_bUseCollector = false;
+
+ if (m_aCurLeaf.Is())
+ {
+ m_aCurLeaf->Release(bSave);
+ m_aCurLeaf.Clear();
+ }
+
+ // Release the root
+ if (m_aRoot.Is())
+ {
+ m_aRoot->Release(bSave);
+ m_aRoot.Clear();
+ }
+ // Release all references, before the FileStream will be closed
+ for (auto& i : m_aCollector)
+ i->QueryDelete();
+
+ m_aCollector.clear();
+
+ // Header modified?
+ if (bSave && (m_aHeader.db_rootpage != m_nRootPage ||
+ m_aHeader.db_pagecount != m_nPageCount))
+ {
+ m_aHeader.db_rootpage = m_nRootPage;
+ m_aHeader.db_pagecount = m_nPageCount;
+ WriteODbaseIndex( *m_pFileStream, *this );
+ }
+ m_nRootPage = m_nPageCount = 0;
+ m_nCurNode = NODE_NOTFOUND;
+
+ closeImpl();
+}
+
+void ODbaseIndex::closeImpl()
+{
+ m_pFileStream.reset();
+}
+
+ONDXPage* ODbaseIndex::CreatePage(sal_uInt32 nPagePos, ONDXPage* pParent, bool bLoad)
+{
+ OSL_ENSURE(m_pFileStream,"FileStream is not opened!");
+
+ ONDXPage* pPage;
+ if ( !m_aCollector.empty() )
+ {
+ pPage = *(m_aCollector.rbegin());
+ m_aCollector.pop_back();
+ pPage->SetPagePos(nPagePos);
+ pPage->SetParent(pParent);
+ }
+ else
+ pPage = new ONDXPage(*this, nPagePos, pParent);
+
+ if (bLoad)
+ (*m_pFileStream) >> *pPage;
+
+ return pPage;
+}
+
+void connectivity::dbase::ReadHeader(
+ SvStream & rStream, ODbaseIndex::NDXHeader & rHeader)
+{
+#if !defined(NDEBUG)
+ sal_uInt64 const nOldPos(rStream.Tell());
+#endif
+ rStream.ReadUInt32(rHeader.db_rootpage);
+ rStream.ReadUInt32(rHeader.db_pagecount);
+ rStream.ReadBytes(&rHeader.db_free, 4);
+ rStream.ReadUInt16(rHeader.db_keylen);
+ rStream.ReadUInt16(rHeader.db_maxkeys);
+ rStream.ReadUInt16(rHeader.db_keytype);
+ rStream.ReadUInt16(rHeader.db_keyrec);
+ rStream.ReadBytes(&rHeader.db_free1, 3);
+ rStream.ReadUChar(rHeader.db_unique);
+ rStream.ReadBytes(&rHeader.db_name, 488);
+ assert(rStream.GetError() || rStream.Tell() == nOldPos + DINDEX_PAGE_SIZE);
+}
+
+SvStream& connectivity::dbase::operator >> (SvStream &rStream, ODbaseIndex& rIndex)
+{
+ rStream.Seek(0);
+ ReadHeader(rStream, rIndex.m_aHeader);
+
+ rIndex.m_nRootPage = rIndex.m_aHeader.db_rootpage;
+ rIndex.m_nPageCount = rIndex.m_aHeader.db_pagecount;
+ return rStream;
+}
+
+SvStream& connectivity::dbase::WriteODbaseIndex(SvStream &rStream, const ODbaseIndex& rIndex)
+{
+ rStream.Seek(0);
+ rStream.WriteUInt32(rIndex.m_aHeader.db_rootpage);
+ rStream.WriteUInt32(rIndex.m_aHeader.db_pagecount);
+ rStream.WriteBytes(&rIndex.m_aHeader.db_free, 4);
+ rStream.WriteUInt16(rIndex.m_aHeader.db_keylen);
+ rStream.WriteUInt16(rIndex.m_aHeader.db_maxkeys);
+ rStream.WriteUInt16(rIndex.m_aHeader.db_keytype);
+ rStream.WriteUInt16(rIndex.m_aHeader.db_keyrec);
+ rStream.WriteBytes(&rIndex.m_aHeader.db_free1, 3);
+ rStream.WriteUChar(rIndex.m_aHeader.db_unique);
+ rStream.WriteBytes(&rIndex.m_aHeader.db_name, 488);
+ assert(rStream.GetError() || rStream.Tell() == DINDEX_PAGE_SIZE);
+ SAL_WARN_IF(rStream.GetError(), "connectivity.dbase", "write error");
+ return rStream;
+}
+
+OUString ODbaseIndex::getCompletePath() const
+{
+ OUString sDir = m_pTable->getConnection()->getURL() +
+ OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DELIMITER) +
+ m_Name + ".ndx";
+ return sDir;
+}
+
+void ODbaseIndex::createINFEntry()
+{
+ // synchronize inf-file
+ const OUString sEntry(m_Name + ".ndx");
+
+ OUString sCfgFile(m_pTable->getConnection()->getURL() +
+ OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DELIMITER) +
+ m_pTable->getName() +
+ ".inf");
+
+ OUString sPhysicalPath;
+ osl::FileBase::getSystemPathFromFileURL(sCfgFile, sPhysicalPath);
+
+ Config aInfFile(sPhysicalPath);
+ aInfFile.SetGroup(dBASE_III_GROUP);
+
+ sal_uInt16 nSuffix = aInfFile.GetKeyCount();
+ OString aNewEntry,aKeyName;
+ bool bCase = isCaseSensitive();
+ while (aNewEntry.isEmpty())
+ {
+ aNewEntry = "NDX" + OString::number(++nSuffix);
+ for (sal_uInt16 i = 0; i < aInfFile.GetKeyCount(); i++)
+ {
+ aKeyName = aInfFile.GetKeyName(i);
+ if (bCase ? aKeyName == aNewEntry : aKeyName.equalsIgnoreAsciiCase(aNewEntry))
+ {
+ aNewEntry.clear();
+ break;
+ }
+ }
+ }
+ aInfFile.WriteKey(aNewEntry, OUStringToOString(sEntry, m_pTable->getConnection()->getTextEncoding()));
+}
+
+void ODbaseIndex::DropImpl()
+{
+ closeImpl();
+
+ OUString sPath = getCompletePath();
+ if(UCBContentHelper::Exists(sPath))
+ {
+ if(!UCBContentHelper::Kill(sPath))
+ m_pTable->getConnection()->throwGenericSQLException(STR_COULD_NOT_DELETE_INDEX,*m_pTable);
+ }
+
+ // synchronize inf-file
+ OUString sCfgFile = m_pTable->getConnection()->getURL() +
+ OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DELIMITER) +
+ m_pTable->getName() + ".inf";
+
+ OUString sPhysicalPath;
+ OSL_VERIFY( osl::FileBase::getSystemPathFromFileURL(sCfgFile, sPhysicalPath)
+ == osl::FileBase::E_None );
+
+ Config aInfFile(sPhysicalPath);
+ aInfFile.SetGroup(dBASE_III_GROUP);
+ sal_uInt16 nKeyCnt = aInfFile.GetKeyCount();
+ OString aKeyName;
+ OUString sEntry = m_Name + ".ndx";
+
+ // delete entries from the inf file
+ for (sal_uInt16 nKey = 0; nKey < nKeyCnt; nKey++)
+ {
+ // References the Key to an Index-file?
+ aKeyName = aInfFile.GetKeyName( nKey );
+ if (aKeyName.startsWith("NDX"))
+ {
+ if(sEntry == OStringToOUString(aInfFile.ReadKey(aKeyName),m_pTable->getConnection()->getTextEncoding()))
+ {
+ aInfFile.DeleteKey(aKeyName);
+ break;
+ }
+ }
+ }
+}
+
+void ODbaseIndex::impl_killFileAndthrowError_throw(TranslateId pErrorId, const OUString& _sFile)
+{
+ closeImpl();
+ if(UCBContentHelper::Exists(_sFile))
+ UCBContentHelper::Kill(_sFile);
+ m_pTable->getConnection()->throwGenericSQLException(pErrorId, *this);
+}
+
+void ODbaseIndex::CreateImpl()
+{
+ // Create the Index
+ const OUString sFile = getCompletePath();
+ if(UCBContentHelper::Exists(sFile))
+ {
+ const OUString sError( m_pTable->getConnection()->getResources().getResourceStringWithSubstitution(
+ STR_COULD_NOT_CREATE_INDEX_NAME,
+ "$filename$", sFile
+ ) );
+ ::dbtools::throwGenericSQLException( sError, *this );
+ }
+ // Index comprises only one column
+ if (m_pColumns->getCount() > 1)
+ m_pTable->getConnection()->throwGenericSQLException(STR_ONL_ONE_COLUMN_PER_INDEX,*this);
+
+ Reference<XFastPropertySet> xCol(m_pColumns->getByIndex(0),UNO_QUERY);
+
+ // Is the column already indexed?
+ if ( !xCol.is() )
+ ::dbtools::throwFunctionSequenceException(*this);
+
+ // create the index file
+ m_pFileStream = OFileTable::createStream_simpleError(sFile,StreamMode::READWRITE | StreamMode::SHARE_DENYWRITE | StreamMode::TRUNC);
+ if (!m_pFileStream)
+ {
+ const OUString sError( m_pTable->getConnection()->getResources().getResourceStringWithSubstitution(
+ STR_COULD_NOT_LOAD_FILE,
+ "$filename$", sFile
+ ) );
+ ::dbtools::throwGenericSQLException( sError, *this );
+ }
+
+ m_pFileStream->SetEndian(SvStreamEndian::LITTLE);
+ m_pFileStream->SetBufferSize(DINDEX_PAGE_SIZE);
+
+ // firstly the result must be sorted
+ utl::SharedUNOComponent<XStatement> xStmt;
+ utl::SharedUNOComponent<XResultSet> xSet;
+ OUString aName;
+ try
+ {
+ xStmt.set( m_pTable->getConnection()->createStatement(), UNO_SET_THROW);
+
+ aName = getString(xCol->getFastPropertyValue(PROPERTY_ID_NAME));
+
+ const OUString aQuote(m_pTable->getConnection()->getMetaData()->getIdentifierQuoteString());
+ OUString aStatement( "SELECT " + aQuote + aName + aQuote +" FROM " + aQuote + m_pTable->getName() + aQuote + " ORDER BY " + aQuote + aName + aQuote);
+
+ xSet.set( xStmt->executeQuery(aStatement),UNO_SET_THROW );
+ }
+ catch(const Exception& )
+ {
+ impl_killFileAndthrowError_throw(STR_COULD_NOT_CREATE_INDEX,sFile);
+ }
+ if (!xSet.is())
+ {
+ impl_killFileAndthrowError_throw(STR_COULD_NOT_CREATE_INDEX,sFile);
+ }
+
+ // Set the header info
+ memset(&m_aHeader,0,sizeof(m_aHeader));
+ sal_Int32 nType = 0;
+ ::rtl::Reference<OSQLColumns> aCols = m_pTable->getTableColumns();
+ const Reference< XPropertySet > xTableCol(*find(aCols->begin(),aCols->end(),aName,::comphelper::UStringMixEqual(isCaseSensitive())));
+
+ xTableCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE)) >>= nType;
+
+ m_aHeader.db_keytype = (nType == DataType::VARCHAR || nType == DataType::CHAR) ? 0 : 1;
+ m_aHeader.db_keylen = (m_aHeader.db_keytype) ? 8 : static_cast<sal_uInt16>(getINT32(xTableCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PRECISION))));
+ m_aHeader.db_keylen = (( m_aHeader.db_keylen - 1) / 4 + 1) * 4;
+ m_aHeader.db_maxkeys = (DINDEX_PAGE_SIZE - 4) / (8 + m_aHeader.db_keylen);
+ if ( m_aHeader.db_maxkeys < 3 )
+ {
+ impl_killFileAndthrowError_throw(STR_COULD_NOT_CREATE_INDEX_KEYSIZE,sFile);
+ }
+
+ m_pFileStream->SetStreamSize(DINDEX_PAGE_SIZE);
+
+ OString aCol(OUStringToOString(aName, m_pTable->getConnection()->getTextEncoding()));
+ strncpy(m_aHeader.db_name, aCol.getStr(), std::min<size_t>(sizeof(m_aHeader.db_name), aCol.getLength()));
+ m_aHeader.db_unique = m_IsUnique ? 1: 0;
+ m_aHeader.db_keyrec = m_aHeader.db_keylen + 8;
+
+ // modifications of the header are detected by differences between
+ // the HeaderInfo and nRootPage or nPageCount respectively
+ m_nRootPage = 1;
+ m_nPageCount = 2;
+
+ m_aCurLeaf = m_aRoot = CreatePage(m_nRootPage);
+ m_aRoot->SetModified(true);
+
+ m_bUseCollector = true;
+
+ sal_Int32 nRowsLeft = 0;
+ Reference<XRow> xRow(xSet,UNO_QUERY);
+
+ if(xSet->last())
+ {
+ ODbaseResultSet* pDbaseRes = dynamic_cast<ODbaseResultSet*>(xSet.getTyped().get());
+ assert(pDbaseRes); //"No dbase resultset found? What's going on here!
+ nRowsLeft = xSet->getRow();
+
+ xSet->beforeFirst();
+ ONDXKey aKey(ORowSetValue(), nType, 0);
+ ONDXKey aInsertKey(ORowSetValue(), nType, 0);
+ // Create the index structure
+ while (xSet->next())
+ {
+ ORowSetValue aValue(m_aHeader.db_keytype ? ORowSetValue(xRow->getDouble(1)) : ORowSetValue(xRow->getString(1)));
+ // checking for duplicate entries
+ if (m_IsUnique && m_nCurNode != NODE_NOTFOUND)
+ {
+ aKey.setValue(aValue);
+ if (aKey == (*m_aCurLeaf)[m_nCurNode].GetKey())
+ {
+ impl_killFileAndthrowError_throw(STR_COULD_NOT_CREATE_INDEX_NOT_UNIQUE,sFile);
+ }
+ }
+ aInsertKey.setValue(aValue);
+ aInsertKey.setRecord(pDbaseRes->getCurrentFilePos());
+
+ ONDXNode aNewNode(aInsertKey);
+ if (!m_aCurLeaf->Insert(aNewNode, --nRowsLeft))
+ break;
+ }
+ }
+
+ if(nRowsLeft)
+ {
+ impl_killFileAndthrowError_throw(STR_COULD_NOT_CREATE_INDEX,sFile);
+ }
+ Release();
+ createINFEntry();
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/dbase/DIndexColumns.cxx b/connectivity/source/drivers/dbase/DIndexColumns.cxx
new file mode 100644
index 0000000000..886c7273db
--- /dev/null
+++ b/connectivity/source/drivers/dbase/DIndexColumns.cxx
@@ -0,0 +1,82 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <dbase/DIndexColumns.hxx>
+#include <dbase/DTable.hxx>
+#include <sdbcx/VIndexColumn.hxx>
+#include <comphelper/types.hxx>
+
+using namespace ::comphelper;
+
+using namespace connectivity::dbase;
+using namespace connectivity;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::container;
+
+
+sdbcx::ObjectType ODbaseIndexColumns::createObject(const OUString& _rName)
+{
+ const ODbaseTable* pTable = m_pIndex->getTable();
+
+ const ::rtl::Reference<OSQLColumns>& aCols = pTable->getTableColumns();
+ OSQLColumns::const_iterator aIter = find(aCols->begin(),aCols->end(),_rName,::comphelper::UStringMixEqual(isCaseSensitive()));
+
+ Reference< XPropertySet > xCol;
+ if(aIter != aCols->end())
+ xCol = *aIter;
+
+ if(!xCol.is())
+ return sdbcx::ObjectType();
+
+ sdbcx::ObjectType xRet = new sdbcx::OIndexColumn(true,_rName
+ ,getString(xCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPENAME)))
+ ,OUString()
+ ,getINT32(xCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISNULLABLE)))
+ ,getINT32(xCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PRECISION)))
+ ,getINT32(xCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCALE)))
+ ,getINT32(xCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE)))
+ ,pTable->getConnection()->getMetaData()->supportsMixedCaseQuotedIdentifiers()
+ ,getString(xCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_CATALOGNAME)))
+ ,getString(xCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCHEMANAME)))
+ ,getString(xCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TABLENAME))));
+
+ return xRet;
+}
+
+
+void ODbaseIndexColumns::impl_refresh()
+{
+ m_pIndex->refreshColumns();
+}
+
+Reference< XPropertySet > ODbaseIndexColumns::createDescriptor()
+{
+ return new sdbcx::OIndexColumn(m_pIndex->getTable()->getConnection()->getMetaData()->supportsMixedCaseQuotedIdentifiers());
+}
+
+sdbcx::ObjectType ODbaseIndexColumns::appendObject( const OUString& /*_rForName*/, const Reference< XPropertySet >& descriptor )
+{
+ return cloneDescriptor( descriptor );
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/dbase/DIndexIter.cxx b/connectivity/source/drivers/dbase/DIndexIter.cxx
new file mode 100644
index 0000000000..37e28a073f
--- /dev/null
+++ b/connectivity/source/drivers/dbase/DIndexIter.cxx
@@ -0,0 +1,282 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <dbase/DIndexIter.hxx>
+#include <com/sun/star/sdb/SQLFilterOperator.hpp>
+
+using namespace ::com::sun::star::sdb;
+using namespace connectivity;
+using namespace connectivity::dbase;
+using namespace connectivity::file;
+
+// OIndexIterator
+
+OIndexIterator::~OIndexIterator() {}
+
+sal_uInt32 OIndexIterator::First() { return Find(true); }
+
+sal_uInt32 OIndexIterator::Next() { return Find(false); }
+
+sal_uInt32 OIndexIterator::Find(bool bFirst)
+{
+ sal_uInt32 nRes = NODE_NOTFOUND;
+
+ if (bFirst)
+ {
+ m_aRoot = m_xIndex->getRoot();
+ m_aCurLeaf.Clear();
+ }
+
+ if (!m_pOperator)
+ {
+ // Preparation, position on the smallest element
+ if (bFirst)
+ {
+ ONDXPage* pPage = m_aRoot;
+ while (pPage && !pPage->IsLeaf())
+ pPage = pPage->GetChild(m_xIndex.get());
+
+ m_aCurLeaf = pPage;
+ m_nCurNode = NODE_NOTFOUND;
+ }
+ ONDXKey* pKey = GetNextKey();
+ nRes = pKey ? pKey->GetRecord() : NODE_NOTFOUND;
+ }
+ else if (dynamic_cast<const OOp_ISNOTNULL*>(m_pOperator) != nullptr)
+ nRes = GetNotNull(bFirst);
+ else if (dynamic_cast<const OOp_ISNULL*>(m_pOperator) != nullptr)
+ nRes = GetNull(bFirst);
+ else if (dynamic_cast<const OOp_LIKE*>(m_pOperator) != nullptr)
+ nRes = GetLike(bFirst);
+ else if (dynamic_cast<const OOp_COMPARE*>(m_pOperator) != nullptr)
+ nRes = GetCompare(bFirst);
+
+ return nRes;
+}
+
+ONDXKey* OIndexIterator::GetFirstKey(ONDXPage* pPage, const OOperand& rKey)
+{
+ // searches a given key
+ // Speciality: At the end of the algorithm
+ // the actual page and the position of the node which fulfil the
+ // '<='-condition are saved. this is considered for inserts.
+ // ONDXIndex* m_pIndex = GetNDXIndex();
+ OOp_COMPARE aTempOp(SQLFilterOperator::GREATER);
+ sal_uInt16 i = 0;
+
+ if (pPage->IsLeaf())
+ {
+ // in the leaf the actual operation is run, otherwise temp. (>)
+ while (i < pPage->Count() && !m_pOperator->operate(&((*pPage)[i]).GetKey(), &rKey))
+ i++;
+ }
+ else
+ while (i < pPage->Count() && !aTempOp.operate(&((*pPage)[i]).GetKey(), &rKey))
+ i++;
+
+ ONDXKey* pFoundKey = nullptr;
+ if (!pPage->IsLeaf())
+ {
+ // descend further
+ ONDXPagePtr aPage = (i == 0) ? pPage->GetChild(m_xIndex.get())
+ : ((*pPage)[i - 1]).GetChild(m_xIndex.get(), pPage);
+ pFoundKey = aPage.Is() ? GetFirstKey(aPage, rKey) : nullptr;
+ }
+ else if (i == pPage->Count())
+ {
+ pFoundKey = nullptr;
+ }
+ else
+ {
+ pFoundKey = &(*pPage)[i].GetKey();
+ if (!m_pOperator->operate(pFoundKey, &rKey))
+ pFoundKey = nullptr;
+
+ m_aCurLeaf = pPage;
+ m_nCurNode = pFoundKey ? i : i - 1;
+ }
+ return pFoundKey;
+}
+
+sal_uInt32 OIndexIterator::GetCompare(bool bFirst)
+{
+ ONDXKey* pKey = nullptr;
+ sal_Int32 ePredicateType = dynamic_cast<file::OOp_COMPARE&>(*m_pOperator).getPredicateType();
+
+ if (bFirst)
+ {
+ // Preparation, position on the smallest element
+ ONDXPage* pPage = m_aRoot;
+ switch (ePredicateType)
+ {
+ case SQLFilterOperator::NOT_EQUAL:
+ case SQLFilterOperator::LESS:
+ case SQLFilterOperator::LESS_EQUAL:
+ while (pPage && !pPage->IsLeaf())
+ pPage = pPage->GetChild(m_xIndex.get());
+
+ m_aCurLeaf = pPage;
+ m_nCurNode = NODE_NOTFOUND;
+ }
+
+ switch (ePredicateType)
+ {
+ case SQLFilterOperator::NOT_EQUAL:
+ while ((pKey = GetNextKey()) != nullptr)
+ if (m_pOperator->operate(pKey, m_pOperand))
+ break;
+ break;
+ case SQLFilterOperator::LESS:
+ while ((pKey = GetNextKey()) != nullptr)
+ if (!pKey->getValue().isNull())
+ break;
+ break;
+ case SQLFilterOperator::LESS_EQUAL:
+ while ((pKey = GetNextKey()) != nullptr)
+ ;
+ break;
+ case SQLFilterOperator::GREATER_EQUAL:
+ case SQLFilterOperator::EQUAL:
+ pKey = GetFirstKey(m_aRoot, *m_pOperand);
+ break;
+ case SQLFilterOperator::GREATER:
+ pKey = GetFirstKey(m_aRoot, *m_pOperand);
+ if (!pKey)
+ while ((pKey = GetNextKey()) != nullptr)
+ if (m_pOperator->operate(pKey, m_pOperand))
+ break;
+ }
+ }
+ else
+ {
+ switch (ePredicateType)
+ {
+ case SQLFilterOperator::NOT_EQUAL:
+ while ((pKey = GetNextKey()) != nullptr)
+ if (m_pOperator->operate(pKey, m_pOperand))
+ break;
+ break;
+ case SQLFilterOperator::LESS:
+ case SQLFilterOperator::LESS_EQUAL:
+ case SQLFilterOperator::EQUAL:
+ pKey = GetNextKey();
+ if (pKey == nullptr || !m_pOperator->operate(pKey, m_pOperand))
+ {
+ pKey = nullptr;
+ m_aCurLeaf.Clear();
+ }
+ break;
+ case SQLFilterOperator::GREATER_EQUAL:
+ case SQLFilterOperator::GREATER:
+ pKey = GetNextKey();
+ }
+ }
+
+ return pKey ? pKey->GetRecord() : NODE_NOTFOUND;
+}
+
+sal_uInt32 OIndexIterator::GetLike(bool bFirst)
+{
+ if (bFirst)
+ {
+ ONDXPage* pPage = m_aRoot;
+
+ while (pPage && !pPage->IsLeaf())
+ pPage = pPage->GetChild(m_xIndex.get());
+
+ m_aCurLeaf = pPage;
+ m_nCurNode = NODE_NOTFOUND;
+ }
+
+ ONDXKey* pKey;
+ while ((pKey = GetNextKey()) != nullptr)
+ if (m_pOperator->operate(pKey, m_pOperand))
+ break;
+ return pKey ? pKey->GetRecord() : NODE_NOTFOUND;
+}
+
+sal_uInt32 OIndexIterator::GetNull(bool bFirst)
+{
+ if (bFirst)
+ {
+ ONDXPage* pPage = m_aRoot;
+ while (pPage && !pPage->IsLeaf())
+ pPage = pPage->GetChild(m_xIndex.get());
+
+ m_aCurLeaf = pPage;
+ m_nCurNode = NODE_NOTFOUND;
+ }
+
+ ONDXKey* pKey = GetNextKey();
+ if (pKey == nullptr || !pKey->getValue().isNull())
+ {
+ pKey = nullptr;
+ m_aCurLeaf.Clear();
+ }
+ return pKey ? pKey->GetRecord() : NODE_NOTFOUND;
+}
+
+sal_uInt32 OIndexIterator::GetNotNull(bool bFirst)
+{
+ ONDXKey* pKey;
+ if (bFirst)
+ {
+ // go through all NULL values first
+ for (sal_uInt32 nRec = GetNull(bFirst); nRec != NODE_NOTFOUND; nRec = GetNull(false))
+ ;
+ pKey = m_aCurLeaf.Is() ? &(*m_aCurLeaf)[m_nCurNode].GetKey() : nullptr;
+ }
+ else
+ pKey = GetNextKey();
+
+ return pKey ? pKey->GetRecord() : NODE_NOTFOUND;
+}
+
+ONDXKey* OIndexIterator::GetNextKey()
+{
+ if (m_aCurLeaf.Is() && ((++m_nCurNode) >= m_aCurLeaf->Count()))
+ {
+ ONDXPage* pPage = m_aCurLeaf;
+ // search next page
+ while (pPage)
+ {
+ ONDXPage* pParentPage = pPage->GetParent();
+ if (pParentPage)
+ {
+ sal_uInt16 nPos = pParentPage->Search(pPage);
+ if (nPos != pParentPage->Count() - 1)
+ { // page found
+ pPage = (*pParentPage)[nPos + 1].GetChild(m_xIndex.get(), pParentPage);
+ break;
+ }
+ }
+ pPage = pParentPage;
+ }
+
+ // now go on with leaf
+ while (pPage && !pPage->IsLeaf())
+ pPage = pPage->GetChild(m_xIndex.get());
+
+ m_aCurLeaf = pPage;
+ m_nCurNode = 0;
+ }
+ return m_aCurLeaf.Is() ? &(*m_aCurLeaf)[m_nCurNode].GetKey() : nullptr;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/dbase/DIndexes.cxx b/connectivity/source/drivers/dbase/DIndexes.cxx
new file mode 100644
index 0000000000..c0a4dead50
--- /dev/null
+++ b/connectivity/source/drivers/dbase/DIndexes.cxx
@@ -0,0 +1,111 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <dbase/DIndexes.hxx>
+#include <dbase/DIndex.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <connectivity/dbexception.hxx>
+#include <unotools/ucbhelper.hxx>
+#include <strings.hrc>
+
+using namespace ::comphelper;
+
+using namespace utl;
+using namespace ::connectivity;
+using namespace ::dbtools;
+using namespace ::connectivity::dbase;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+
+sdbcx::ObjectType ODbaseIndexes::createObject(const OUString& _rName)
+{
+ OUString sFile = m_pTable->getConnection()->getURL() +
+ OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DELIMITER) +
+ _rName + ".ndx";
+ if ( !UCBContentHelper::Exists(sFile) )
+ {
+ const OUString sError( m_pTable->getConnection()->getResources().getResourceStringWithSubstitution(
+ STR_COULD_NOT_LOAD_FILE,
+ "$filename$", sFile
+ ) );
+ ::dbtools::throwGenericSQLException( sError, *m_pTable );
+ }
+
+ sdbcx::ObjectType xRet;
+ std::unique_ptr<SvStream> pFileStream = ::connectivity::file::OFileTable::createStream_simpleError(sFile, StreamMode::READ | StreamMode::NOCREATE | StreamMode::SHARE_DENYWRITE);
+ if(pFileStream)
+ {
+ pFileStream->SetEndian(SvStreamEndian::LITTLE);
+ pFileStream->SetBufferSize(DINDEX_PAGE_SIZE);
+ ODbaseIndex::NDXHeader aHeader;
+
+ pFileStream->Seek(0);
+ ReadHeader(*pFileStream, aHeader);
+ pFileStream.reset();
+
+ rtl::Reference<ODbaseIndex> pIndex = new ODbaseIndex(m_pTable,aHeader,_rName);
+ xRet = pIndex;
+ pIndex->openIndexFile();
+ }
+ else
+ {
+ const OUString sError( m_pTable->getConnection()->getResources().getResourceStringWithSubstitution(
+ STR_COULD_NOT_LOAD_FILE,
+ "$filename$", sFile
+ ) );
+ ::dbtools::throwGenericSQLException( sError, *m_pTable );
+ }
+ return xRet;
+}
+
+void ODbaseIndexes::impl_refresh( )
+{
+ if(m_pTable)
+ m_pTable->refreshIndexes();
+}
+
+Reference< XPropertySet > ODbaseIndexes::createDescriptor()
+{
+ return new ODbaseIndex(m_pTable);
+}
+
+// XAppend
+sdbcx::ObjectType ODbaseIndexes::appendObject( const OUString& _rForName, const Reference< XPropertySet >& descriptor )
+{
+ ODbaseIndex* pIndex = dynamic_cast<ODbaseIndex*>(descriptor.get());
+ if(pIndex)
+ pIndex->CreateImpl();
+
+ return createObject( _rForName );
+}
+
+// XDrop
+void ODbaseIndexes::dropObject(sal_Int32 _nPos, const OUString& /*_sElementName*/)
+{
+ rtl::Reference<ODbaseIndex> pIndex = dynamic_cast<ODbaseIndex*>(getObject(_nPos).get());
+ if ( pIndex )
+ pIndex->DropImpl();
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/dbase/DPreparedStatement.cxx b/connectivity/source/drivers/dbase/DPreparedStatement.cxx
new file mode 100644
index 0000000000..9a2b54409b
--- /dev/null
+++ b/connectivity/source/drivers/dbase/DPreparedStatement.cxx
@@ -0,0 +1,35 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <dbase/DPreparedStatement.hxx>
+#include <dbase/DResultSet.hxx>
+
+using namespace connectivity::dbase;
+using namespace connectivity::file;
+using namespace com::sun::star::uno;
+
+rtl::Reference<OResultSet> ODbasePreparedStatement::createResultSet()
+{
+ return new ODbaseResultSet(this, m_aSQLIterator);
+}
+
+IMPLEMENT_SERVICE_INFO(ODbasePreparedStatement, "com.sun.star.sdbc.driver.dbase.PreparedStatement",
+ "com.sun.star.sdbc.PreparedStatement");
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/dbase/DResultSet.cxx b/connectivity/source/drivers/dbase/DResultSet.cxx
new file mode 100644
index 0000000000..123a29b8b0
--- /dev/null
+++ b/connectivity/source/drivers/dbase/DResultSet.cxx
@@ -0,0 +1,211 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/sdbcx/CompareBookmark.hpp>
+#include <dbase/DResultSet.hxx>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <comphelper/sequence.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <dbase/DIndex.hxx>
+#include <dbase/DIndexIter.hxx>
+#include <comphelper/types.hxx>
+#include <connectivity/dbexception.hxx>
+#include <strings.hrc>
+
+using namespace ::comphelper;
+
+using namespace connectivity::dbase;
+using namespace connectivity::file;
+using namespace ::cppu;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::sdbc;
+using namespace com::sun::star::sdbcx;
+
+ODbaseResultSet::ODbaseResultSet( OStatement_Base* pStmt,connectivity::OSQLParseTreeIterator& _aSQLIterator)
+ : file::OResultSet(pStmt,_aSQLIterator)
+ ,m_bBookmarkable(true)
+{
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISBOOKMARKABLE), PROPERTY_ID_ISBOOKMARKABLE, PropertyAttribute::READONLY,&m_bBookmarkable, cppu::UnoType<bool>::get());
+}
+
+OUString SAL_CALL ODbaseResultSet::getImplementationName( )
+{
+ return "com.sun.star.sdbcx.dbase.ResultSet";
+}
+
+Sequence< OUString > SAL_CALL ODbaseResultSet::getSupportedServiceNames( )
+{
+ return { "com.sun.star.sdbc.ResultSet", "com.sun.star.sdbcx.ResultSet" };
+}
+
+sal_Bool SAL_CALL ODbaseResultSet::supportsService( const OUString& _rServiceName )
+{
+ return cppu::supportsService(this, _rServiceName);
+}
+
+Any SAL_CALL ODbaseResultSet::queryInterface( const Type & rType )
+{
+ Any aRet = ODbaseResultSet_BASE::queryInterface(rType);
+ return aRet.hasValue() ? aRet : OResultSet::queryInterface(rType);
+}
+
+ Sequence< Type > SAL_CALL ODbaseResultSet::getTypes( )
+{
+ return ::comphelper::concatSequences(OResultSet::getTypes(),ODbaseResultSet_BASE::getTypes());
+}
+
+
+// XRowLocate
+Any SAL_CALL ODbaseResultSet::getBookmark( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+ OSL_ENSURE((m_bShowDeleted || !m_aRow->isDeleted()),"getBookmark called for deleted row");
+
+ return Any((*m_aRow)[0]->getValue().getInt32());
+}
+
+sal_Bool SAL_CALL ODbaseResultSet::moveToBookmark( const Any& bookmark )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+
+ m_bRowDeleted = m_bRowInserted = m_bRowUpdated = false;
+
+ return m_pTable.is() && Move(IResultSetHelper::BOOKMARK,comphelper::getINT32(bookmark),true);
+}
+
+sal_Bool SAL_CALL ODbaseResultSet::moveRelativeToBookmark( const Any& bookmark, sal_Int32 rows )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+ if(!m_pTable.is())
+ return false;
+
+
+ Move(IResultSetHelper::BOOKMARK,comphelper::getINT32(bookmark),false);
+
+ return relative(rows);
+}
+
+
+sal_Int32 SAL_CALL ODbaseResultSet::compareBookmarks( const Any& lhs, const Any& rhs )
+{
+ sal_Int32 nFirst(0),nSecond(0),nResult(0);
+ if ( !( lhs >>= nFirst ) || !( rhs >>= nSecond ) )
+ {
+ ::connectivity::SharedResources aResources;
+ const OUString sMessage = aResources.getResourceString(STR_INVALID_BOOKMARK);
+ ::dbtools::throwGenericSQLException(sMessage ,*this);
+ } // if ( !( lhs >>= nFirst ) || !( rhs >>= nSecond ) )
+
+ if(nFirst < nSecond)
+ nResult = CompareBookmark::LESS;
+ else if(nFirst > nSecond)
+ nResult = CompareBookmark::GREATER;
+ else
+ nResult = CompareBookmark::EQUAL;
+
+ return nResult;
+}
+
+sal_Bool SAL_CALL ODbaseResultSet::hasOrderedBookmarks( )
+{
+ return true;
+}
+
+sal_Int32 SAL_CALL ODbaseResultSet::hashBookmark( const Any& bookmark )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+
+ return comphelper::getINT32(bookmark);
+}
+
+// XDeleteRows
+Sequence< sal_Int32 > SAL_CALL ODbaseResultSet::deleteRows( const Sequence< Any >& /*rows*/ )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ ::dbtools::throwFeatureNotImplementedSQLException( "XDeleteRows::deleteRows", *this );
+ return Sequence< sal_Int32 >();
+}
+
+bool ODbaseResultSet::fillIndexValues(const Reference< XColumnsSupplier> &_xIndex)
+{
+ auto pIndex = dynamic_cast<dbase::ODbaseIndex*>(_xIndex.get());
+ if(pIndex)
+ {
+ std::unique_ptr<dbase::OIndexIterator> pIter = pIndex->createIterator();
+
+ if (pIter)
+ {
+ sal_uInt32 nRec = pIter->First();
+ while (nRec != NODE_NOTFOUND)
+ {
+ m_pFileSet->push_back(nRec);
+ nRec = pIter->Next();
+ }
+ m_pFileSet->setFrozen();
+ return true;
+ }
+ }
+ return false;
+}
+
+::cppu::IPropertyArrayHelper & ODbaseResultSet::getInfoHelper()
+{
+ return *ODbaseResultSet_BASE3::getArrayHelper();
+}
+
+::cppu::IPropertyArrayHelper* ODbaseResultSet::createArrayHelper() const
+{
+ Sequence< Property > aProps;
+ describeProperties(aProps);
+ return new ::cppu::OPropertyArrayHelper(aProps);
+}
+
+void SAL_CALL ODbaseResultSet::acquire() noexcept
+{
+ ODbaseResultSet_BASE2::acquire();
+}
+
+void SAL_CALL ODbaseResultSet::release() noexcept
+{
+ ODbaseResultSet_BASE2::release();
+}
+
+css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL ODbaseResultSet::getPropertySetInfo( )
+{
+ return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper());
+}
+
+sal_Int32 ODbaseResultSet::getCurrentFilePos() const
+{
+ return m_pTable->getFilePos();
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/dbase/DStatement.cxx b/connectivity/source/drivers/dbase/DStatement.cxx
new file mode 100644
index 0000000000..d253723277
--- /dev/null
+++ b/connectivity/source/drivers/dbase/DStatement.cxx
@@ -0,0 +1,35 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <dbase/DStatement.hxx>
+#include <dbase/DResultSet.hxx>
+
+using namespace connectivity::dbase;
+using namespace connectivity::file;
+using namespace com::sun::star::uno;
+
+
+rtl::Reference<OResultSet> ODbaseStatement::createResultSet()
+{
+ return new ODbaseResultSet(this,m_aSQLIterator);
+}
+
+IMPLEMENT_SERVICE_INFO(ODbaseStatement,"com.sun.star.sdbc.driver.dbase.Statement","com.sun.star.sdbc.Statement");
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/dbase/DTable.cxx b/connectivity/source/drivers/dbase/DTable.cxx
new file mode 100644
index 0000000000..3995ee8984
--- /dev/null
+++ b/connectivity/source/drivers/dbase/DTable.cxx
@@ -0,0 +1,2747 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <dbase/DTable.hxx>
+#include <com/sun/star/container/ElementExistException.hpp>
+#include <com/sun/star/sdbc/ColumnValue.hpp>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <com/sun/star/ucb/XContentAccess.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <o3tl/safeint.hxx>
+#include <svl/converter.hxx>
+#include <dbase/DConnection.hxx>
+#include <dbase/DColumns.hxx>
+#include <tools/config.hxx>
+#include <comphelper/diagnose_ex.hxx>
+#include <dbase/DIndex.hxx>
+#include <dbase/DIndexes.hxx>
+#include <comphelper/processfactory.hxx>
+#include <rtl/math.hxx>
+#include <ucbhelper/content.hxx>
+#include <com/sun/star/ucb/ContentCreationException.hpp>
+#include <connectivity/dbexception.hxx>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <comphelper/property.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <o3tl/string_view.hxx>
+#include <comphelper/string.hxx>
+#include <unotools/configmgr.hxx>
+#include <unotools/tempfile.hxx>
+#include <unotools/ucbhelper.hxx>
+#include <comphelper/types.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+#include <cppuhelper/queryinterface.hxx>
+#include <connectivity/dbtools.hxx>
+#include <connectivity/FValue.hxx>
+#include <connectivity/dbconversion.hxx>
+#include <connectivity/sdbcx/VColumn.hxx>
+#include <strings.hrc>
+#include <rtl/strbuf.hxx>
+#include <sal/log.hxx>
+#include <tools/date.hxx>
+#include <i18nutil/calendar.hxx>
+
+#include <algorithm>
+#include <cassert>
+#include <memory>
+#include <string_view>
+
+using namespace ::comphelper;
+using namespace connectivity;
+using namespace connectivity::sdbcx;
+using namespace connectivity::dbase;
+using namespace connectivity::file;
+using namespace ::ucbhelper;
+using namespace ::utl;
+using namespace ::cppu;
+using namespace ::dbtools;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::ucb;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::i18n;
+
+// stored as the Field Descriptor terminator
+#define FIELD_DESCRIPTOR_TERMINATOR 0x0D
+#define DBF_EOL 0x1A
+
+namespace
+{
+std::size_t lcl_getFileSize(SvStream& _rStream)
+{
+ std::size_t nFileSize = 0;
+ _rStream.Seek(STREAM_SEEK_TO_END);
+ _rStream.SeekRel(-1);
+ char cEOL;
+ _rStream.ReadChar( cEOL );
+ nFileSize = _rStream.Tell();
+ if ( cEOL == DBF_EOL )
+ nFileSize -= 1;
+ return nFileSize;
+}
+/**
+ calculates the Julian date
+*/
+void lcl_CalcJulDate(sal_Int32& _nJulianDate,sal_Int32& _nJulianTime, const css::util::DateTime& rDateTime)
+{
+ css::util::DateTime aDateTime = rDateTime;
+ // weird: months fix
+ if (aDateTime.Month > 12)
+ {
+ aDateTime.Month--;
+ sal_uInt16 delta = rDateTime.Month / 12;
+ aDateTime.Year += delta;
+ aDateTime.Month -= delta * 12;
+ aDateTime.Month++;
+ }
+
+ _nJulianTime = ((aDateTime.Hours*3600000)+(aDateTime.Minutes*60000)+(aDateTime.Seconds*1000)+(aDateTime.NanoSeconds/1000000));
+ /* conversion factors */
+ sal_uInt16 iy0;
+ sal_uInt16 im0;
+ if ( aDateTime.Month <= 2 )
+ {
+ iy0 = aDateTime.Year - 1;
+ im0 = aDateTime.Month + 12;
+ }
+ else
+ {
+ iy0 = aDateTime.Year;
+ im0 = aDateTime.Month;
+ }
+ sal_Int32 ia = iy0 / 100;
+ sal_Int32 ib = 2 - ia + (ia >> 2);
+ /* calculate julian date */
+ if ( aDateTime.Year <= 0 )
+ {
+ _nJulianDate = static_cast<sal_Int32>((365.25 * iy0) - 0.75)
+ + static_cast<sal_Int32>(i18nutil::monthDaysWithoutJanFeb * (im0 + 1) )
+ + aDateTime.Day + 1720994;
+ } // if ( rDateTime.Year <= 0 )
+ else
+ {
+ _nJulianDate = static_cast<sal_Int32>(365.25 * iy0)
+ + static_cast<sal_Int32>(i18nutil::monthDaysWithoutJanFeb * (im0 + 1))
+ + aDateTime.Day + 1720994;
+ }
+ double JD = _nJulianDate + 0.5;
+ _nJulianDate = static_cast<sal_Int32>( JD + 0.5);
+ const double gyr = aDateTime.Year + (0.01 * aDateTime.Month) + (0.0001 * aDateTime.Day);
+ if ( gyr >= 1582.1015 ) /* on or after 15 October 1582 */
+ _nJulianDate += ib;
+}
+
+/**
+ calculates date time from the Julian Date
+*/
+void lcl_CalDate(sal_Int32 _nJulianDate,sal_Int32 _nJulianTime,css::util::DateTime& _rDateTime)
+{
+ if ( _nJulianDate )
+ {
+ sal_Int64 ka = _nJulianDate;
+ if ( _nJulianDate >= 2299161 )
+ {
+ sal_Int64 ialp = static_cast<sal_Int64>( (static_cast<double>(_nJulianDate) - 1867216.25 ) / 36524.25 );
+ ka = ka + 1 + ialp - ( ialp >> 2 );
+ }
+ sal_Int64 kb = ka + 1524;
+ sal_Int64 kc = static_cast<sal_Int64>((static_cast<double>(kb) - 122.1) / 365.25);
+ sal_Int64 kd = static_cast<sal_Int64>(static_cast<double>(kc) * 365.25);
+ sal_Int64 ke = static_cast<sal_Int64>(static_cast<double>(kb - kd) / i18nutil::monthDaysWithoutJanFeb);
+ _rDateTime.Day = static_cast<sal_uInt16>(kb - kd - static_cast<sal_Int64>( static_cast<double>(ke) * i18nutil::monthDaysWithoutJanFeb ));
+ if ( ke > 13 )
+ _rDateTime.Month = static_cast<sal_uInt16>(ke - 13);
+ else
+ _rDateTime.Month = static_cast<sal_uInt16>(ke - 1);
+ if ( (_rDateTime.Month == 2) && (_rDateTime.Day > 28) )
+ _rDateTime.Day = 29;
+ if ( (_rDateTime.Month == 2) && (_rDateTime.Day == 29) && (ke == 3) )
+ _rDateTime.Year = static_cast<sal_uInt16>(kc - 4716);
+ else if ( _rDateTime.Month > 2 )
+ _rDateTime.Year = static_cast<sal_uInt16>(kc - 4716);
+ else
+ _rDateTime.Year = static_cast<sal_uInt16>(kc - 4715);
+ }
+
+ if ( _nJulianTime )
+ {
+ double d_s = _nJulianTime / 1000.0;
+ double d_m = d_s / 60.0;
+ double d_h = d_m / 60.0;
+ _rDateTime.Hours = static_cast<sal_uInt16>(d_h);
+ _rDateTime.Minutes = static_cast<sal_uInt16>((d_h - static_cast<double>(_rDateTime.Hours)) * 60.0);
+ _rDateTime.Seconds = static_cast<sal_uInt16>(((d_m - static_cast<double>(_rDateTime.Minutes)) * 60.0)
+ - (static_cast<double>(_rDateTime.Hours) * 3600.0));
+ }
+}
+
+}
+
+
+void ODbaseTable::readHeader()
+{
+ OSL_ENSURE(m_pFileStream,"No Stream available!");
+ if(!m_pFileStream)
+ return;
+ m_pFileStream->RefreshBuffer(); // Make sure, that the header information actually is read again
+ m_pFileStream->Seek(STREAM_SEEK_TO_BEGIN);
+
+ sal_uInt8 nType=0;
+ m_pFileStream->ReadUChar( nType );
+ if(ERRCODE_NONE != m_pFileStream->GetErrorCode())
+ throwInvalidDbaseFormat();
+
+ m_pFileStream->ReadBytes(m_aHeader.dateElems, 3);
+ if(ERRCODE_NONE != m_pFileStream->GetErrorCode())
+ throwInvalidDbaseFormat();
+
+ m_pFileStream->ReadUInt32( m_aHeader.nbRecords);
+ if(ERRCODE_NONE != m_pFileStream->GetErrorCode())
+ throwInvalidDbaseFormat();
+
+ m_pFileStream->ReadUInt16( m_aHeader.headerLength);
+ if(ERRCODE_NONE != m_pFileStream->GetErrorCode())
+ throwInvalidDbaseFormat();
+
+ m_pFileStream->ReadUInt16( m_aHeader.recordLength);
+ if(ERRCODE_NONE != m_pFileStream->GetErrorCode())
+ throwInvalidDbaseFormat();
+ if (m_aHeader.recordLength == 0)
+ throwInvalidDbaseFormat();
+
+ m_pFileStream->ReadBytes(m_aHeader.trailer, 20);
+ if(ERRCODE_NONE != m_pFileStream->GetErrorCode())
+ throwInvalidDbaseFormat();
+
+
+ if ( ( ( m_aHeader.headerLength - 1 ) / 32 - 1 ) <= 0 ) // number of fields
+ {
+ // no dBASE file
+ throwInvalidDbaseFormat();
+ }
+ else
+ {
+ // Consistency check of the header:
+ m_aHeader.type = static_cast<DBFType>(nType);
+ switch (m_aHeader.type)
+ {
+ case dBaseIII:
+ case dBaseIV:
+ case dBaseV:
+ case VisualFoxPro:
+ case VisualFoxProAuto:
+ case dBaseFS:
+ case dBaseFSMemo:
+ case dBaseIVMemoSQL:
+ case dBaseIIIMemo:
+ case FoxProMemo:
+ m_pFileStream->SetEndian(SvStreamEndian::LITTLE);
+ if( getConnection()->isTextEncodingDefaulted() &&
+ !dbfDecodeCharset(m_eEncoding, nType, m_aHeader.trailer[17]))
+ {
+ m_eEncoding = RTL_TEXTENCODING_IBM_850;
+ }
+ break;
+ case dBaseIVMemo:
+ m_pFileStream->SetEndian(SvStreamEndian::LITTLE);
+ break;
+ default:
+ {
+ throwInvalidDbaseFormat();
+ }
+ }
+ }
+}
+
+void ODbaseTable::fillColumns()
+{
+ m_pFileStream->Seek(STREAM_SEEK_TO_BEGIN);
+ if (!checkSeek(*m_pFileStream, 32))
+ {
+ SAL_WARN("connectivity.drivers", "ODbaseTable::fillColumns: bad offset!");
+ return;
+ }
+
+ if(!m_aColumns.is())
+ m_aColumns = new OSQLColumns();
+ else
+ m_aColumns->clear();
+
+ m_aTypes.clear();
+ m_aPrecisions.clear();
+ m_aScales.clear();
+
+ // Number of fields:
+ sal_Int32 nFieldCount = (m_aHeader.headerLength - 1) / 32 - 1;
+ if (nFieldCount <= 0)
+ {
+ SAL_WARN("connectivity.drivers", "No columns in table!");
+ return;
+ }
+
+ auto nRemainingsize = m_pFileStream->remainingSize();
+ auto nMaxPossibleRecords = nRemainingsize / 32;
+ if (o3tl::make_unsigned(nFieldCount) > nMaxPossibleRecords)
+ {
+ SAL_WARN("connectivity.drivers", "Parsing error: " << nMaxPossibleRecords <<
+ " max possible entries, but " << nFieldCount << " claimed, truncating");
+ nFieldCount = nMaxPossibleRecords;
+ }
+
+ m_aColumns->reserve(nFieldCount);
+ m_aTypes.reserve(nFieldCount);
+ m_aPrecisions.reserve(nFieldCount);
+ m_aScales.reserve(nFieldCount);
+
+ OUString aTypeName;
+ const bool bCase = getConnection()->getMetaData()->supportsMixedCaseQuotedIdentifiers();
+ const bool bFoxPro = m_aHeader.type == VisualFoxPro || m_aHeader.type == VisualFoxProAuto || m_aHeader.type == FoxProMemo;
+
+ sal_Int32 i = 0;
+ for (; i < nFieldCount; i++)
+ {
+ DBFColumn aDBFColumn;
+ m_pFileStream->ReadBytes(aDBFColumn.db_fnm, 11);
+ m_pFileStream->ReadUChar(aDBFColumn.db_typ);
+ m_pFileStream->ReadUInt32(aDBFColumn.db_adr);
+ m_pFileStream->ReadUChar(aDBFColumn.db_flng);
+ m_pFileStream->ReadUChar(aDBFColumn.db_dez);
+ m_pFileStream->ReadBytes(aDBFColumn.db_free2, 14);
+ if (!m_pFileStream->good())
+ {
+ SAL_WARN("connectivity.drivers", "ODbaseTable::fillColumns: short read!");
+ break;
+ }
+ if ( FIELD_DESCRIPTOR_TERMINATOR == aDBFColumn.db_fnm[0] ) // 0x0D stored as the Field Descriptor terminator.
+ break;
+
+ aDBFColumn.db_fnm[sizeof(aDBFColumn.db_fnm)-1] = 0; //ensure null termination for broken input
+ const OUString aColumnName(reinterpret_cast<char *>(aDBFColumn.db_fnm), strlen(reinterpret_cast<char *>(aDBFColumn.db_fnm)), m_eEncoding);
+
+ bool bIsRowVersion = bFoxPro && ( aDBFColumn.db_free2[0] & 0x01 ) == 0x01;
+
+ m_aRealFieldLengths.push_back(aDBFColumn.db_flng);
+ sal_Int32 nPrecision = aDBFColumn.db_flng;
+ sal_Int32 eType;
+ bool bIsCurrency = false;
+
+ char cType[2];
+ cType[0] = aDBFColumn.db_typ;
+ cType[1] = 0;
+ aTypeName = OUString(cType, 1, RTL_TEXTENCODING_ASCII_US);
+ SAL_INFO( "connectivity.drivers","column type: " << aDBFColumn.db_typ);
+
+ switch (aDBFColumn.db_typ)
+ {
+ case 'C':
+ eType = DataType::VARCHAR;
+ aTypeName = "VARCHAR";
+ break;
+ case 'F':
+ case 'N':
+ aTypeName = "DECIMAL";
+ if ( aDBFColumn.db_typ == 'N' )
+ aTypeName = "NUMERIC";
+ eType = DataType::DECIMAL;
+
+ // for numeric fields two characters more are written, then the precision of the column description predescribes,
+ // to keep room for the possible sign and the comma. This has to be considered...
+ nPrecision = SvDbaseConverter::ConvertPrecisionToOdbc(nPrecision,aDBFColumn.db_dez);
+ // This is not true for older versions...
+ break;
+ case 'L':
+ eType = DataType::BIT;
+ aTypeName = "BOOLEAN";
+ break;
+ case 'Y':
+ bIsCurrency = true;
+ eType = DataType::DOUBLE;
+ aTypeName = "DOUBLE";
+ break;
+ case 'D':
+ eType = DataType::DATE;
+ aTypeName = "DATE";
+ break;
+ case 'T':
+ eType = DataType::TIMESTAMP;
+ aTypeName = "TIMESTAMP";
+ break;
+ case 'I':
+ eType = DataType::INTEGER;
+ aTypeName = "INTEGER";
+ break;
+ case 'M':
+ if ( bFoxPro && ( aDBFColumn.db_free2[0] & 0x04 ) == 0x04 )
+ {
+ eType = DataType::LONGVARBINARY;
+ aTypeName = "LONGVARBINARY";
+ }
+ else
+ {
+ aTypeName = "LONGVARCHAR";
+ eType = DataType::LONGVARCHAR;
+ }
+ nPrecision = 2147483647;
+ break;
+ case 'P':
+ aTypeName = "LONGVARBINARY";
+ eType = DataType::LONGVARBINARY;
+ nPrecision = 2147483647;
+ break;
+ case '0':
+ case 'B':
+ if ( m_aHeader.type == VisualFoxPro || m_aHeader.type == VisualFoxProAuto )
+ {
+ aTypeName = "DOUBLE";
+ eType = DataType::DOUBLE;
+ }
+ else
+ {
+ aTypeName = "LONGVARBINARY";
+ eType = DataType::LONGVARBINARY;
+ nPrecision = 2147483647;
+ }
+ break;
+ default:
+ eType = DataType::OTHER;
+ }
+
+ m_aTypes.push_back(eType);
+ m_aPrecisions.push_back(nPrecision);
+ m_aScales.push_back(aDBFColumn.db_dez);
+
+ Reference< XPropertySet> xCol = new sdbcx::OColumn(aColumnName,
+ aTypeName,
+ OUString(),
+ OUString(),
+ ColumnValue::NULLABLE,
+ nPrecision,
+ aDBFColumn.db_dez,
+ eType,
+ false,
+ bIsRowVersion,
+ bIsCurrency,
+ bCase,
+ m_CatalogName, getSchema(), getName());
+ m_aColumns->push_back(xCol);
+ } // for (; i < nFieldCount; i++)
+ OSL_ENSURE(i,"No columns in table!");
+}
+
+ODbaseTable::ODbaseTable(sdbcx::OCollection* _pTables, ODbaseConnection* _pConnection)
+ : ODbaseTable_BASE(_pTables,_pConnection)
+{
+ // initialize the header
+ m_aHeader.type = dBaseIII;
+ m_eEncoding = getConnection()->getTextEncoding();
+}
+
+ODbaseTable::ODbaseTable(sdbcx::OCollection* _pTables, ODbaseConnection* _pConnection,
+ const OUString& Name,
+ const OUString& Type,
+ const OUString& Description ,
+ const OUString& SchemaName,
+ const OUString& CatalogName )
+ : ODbaseTable_BASE(_pTables,_pConnection,Name,
+ Type,
+ Description,
+ SchemaName,
+ CatalogName)
+{
+ m_eEncoding = getConnection()->getTextEncoding();
+}
+
+void ODbaseTable::construct()
+{
+ // initialize the header
+ m_aHeader.type = dBaseIII;
+ m_aHeader.nbRecords = 0;
+ m_aHeader.headerLength = 0;
+ m_aHeader.recordLength = 0;
+ m_aMemoHeader.db_size = 0;
+
+ OUString sFileName(getEntry(m_pConnection, m_Name));
+
+ INetURLObject aURL;
+ aURL.SetURL(sFileName);
+
+ OSL_ENSURE( m_pConnection->matchesExtension( aURL.getExtension() ),
+ "ODbaseTable::ODbaseTable: invalid extension!");
+ // getEntry is expected to ensure the correct file name
+
+ m_pFileStream = createStream_simpleError( sFileName, StreamMode::READWRITE | StreamMode::NOCREATE | StreamMode::SHARE_DENYWRITE);
+ m_bWriteable = ( m_pFileStream != nullptr );
+
+ if ( !m_pFileStream )
+ {
+ m_bWriteable = false;
+ m_pFileStream = createStream_simpleError( sFileName, StreamMode::READ | StreamMode::NOCREATE | StreamMode::SHARE_DENYNONE);
+ }
+
+ if (!m_pFileStream)
+ return;
+
+ readHeader();
+
+ std::size_t nFileSize = lcl_getFileSize(*m_pFileStream);
+
+ if (m_aHeader.headerLength > nFileSize)
+ {
+ SAL_WARN("connectivity.drivers", "Parsing error: " << nFileSize <<
+ " max possible size, but " << m_aHeader.headerLength << " claimed, abandoning");
+ return;
+ }
+
+ if (m_aHeader.recordLength)
+ {
+ std::size_t nMaxPossibleRecords = (nFileSize - m_aHeader.headerLength) / m_aHeader.recordLength;
+ // #i83401# seems to be empty or someone wrote nonsense into the dbase
+ // file try and recover if m_aHeader.db_slng is sane
+ if (m_aHeader.nbRecords == 0)
+ {
+ SAL_WARN("connectivity.drivers", "Parsing warning: 0 records claimed, recovering");
+ m_aHeader.nbRecords = nMaxPossibleRecords;
+ }
+ else if (m_aHeader.nbRecords > nMaxPossibleRecords)
+ {
+ SAL_WARN("connectivity.drivers", "Parsing error: " << nMaxPossibleRecords <<
+ " max possible records, but " << m_aHeader.nbRecords << " claimed, truncating");
+ m_aHeader.nbRecords = std::max(nMaxPossibleRecords, static_cast<size_t>(1));
+ }
+ }
+
+ if (HasMemoFields())
+ {
+ // Create Memo-Filename (.DBT):
+ // nyi: Ugly for Unix and Mac!
+
+ if ( m_aHeader.type == FoxProMemo || m_aHeader.type == VisualFoxPro || m_aHeader.type == VisualFoxProAuto) // foxpro uses another extension
+ aURL.SetExtension(u"fpt");
+ else
+ aURL.SetExtension(u"dbt");
+
+ // If the memo file isn't found, the data will be displayed anyhow.
+ // However, updates can't be done
+ // but the operation is executed
+ m_pMemoStream = createStream_simpleError( aURL.GetMainURL(INetURLObject::DecodeMechanism::NONE), StreamMode::READWRITE | StreamMode::NOCREATE | StreamMode::SHARE_DENYWRITE);
+ if ( !m_pMemoStream )
+ {
+ m_pMemoStream = createStream_simpleError( aURL.GetMainURL(INetURLObject::DecodeMechanism::NONE), StreamMode::READ | StreamMode::NOCREATE | StreamMode::SHARE_DENYNONE);
+ }
+ if (m_pMemoStream)
+ ReadMemoHeader();
+ }
+
+ fillColumns();
+ m_pFileStream->Seek(STREAM_SEEK_TO_BEGIN);
+
+
+ // Buffersize dependent on the file size
+ m_pFileStream->SetBufferSize(nFileSize > 1000000 ? 32768 :
+ nFileSize > 100000 ? 16384 :
+ nFileSize > 10000 ? 4096 : 1024);
+
+ if (m_pMemoStream)
+ {
+ // set the buffer exactly to the length of a record
+ nFileSize = m_pMemoStream->TellEnd();
+ m_pMemoStream->Seek(STREAM_SEEK_TO_BEGIN);
+
+ // Buffersize dependent on the file size
+ m_pMemoStream->SetBufferSize(nFileSize > 1000000 ? 32768 :
+ nFileSize > 100000 ? 16384 :
+ nFileSize > 10000 ? 4096 :
+ m_aMemoHeader.db_size);
+ }
+
+ AllocBuffer();
+}
+
+void ODbaseTable::ReadMemoHeader()
+{
+ m_pMemoStream->SetEndian(SvStreamEndian::LITTLE);
+ m_pMemoStream->RefreshBuffer(); // make sure that the header information is actually read again
+ m_pMemoStream->Seek(0);
+
+ (*m_pMemoStream).ReadUInt32( m_aMemoHeader.db_next );
+ switch (m_aHeader.type)
+ {
+ case dBaseIIIMemo: // dBase III: fixed block size
+ case dBaseIVMemo:
+ // sometimes dBase3 is attached to dBase4 memo
+ m_pMemoStream->Seek(20);
+ (*m_pMemoStream).ReadUInt16( m_aMemoHeader.db_size );
+ if (m_aMemoHeader.db_size > 1 && m_aMemoHeader.db_size != 512) // 1 is also for dBase 3
+ m_aMemoHeader.db_typ = MemodBaseIV;
+ else if (m_aMemoHeader.db_size == 512)
+ {
+ // There are files using size specification, though they are dBase-files
+ char sHeader[4];
+ m_pMemoStream->Seek(m_aMemoHeader.db_size);
+ m_pMemoStream->ReadBytes(sHeader, 4);
+
+ if ((m_pMemoStream->GetErrorCode() != ERRCODE_NONE) || static_cast<sal_uInt8>(sHeader[0]) != 0xFF || static_cast<sal_uInt8>(sHeader[1]) != 0xFF || static_cast<sal_uInt8>(sHeader[2]) != 0x08)
+ m_aMemoHeader.db_typ = MemodBaseIII;
+ else
+ m_aMemoHeader.db_typ = MemodBaseIV;
+ }
+ else
+ {
+ m_aMemoHeader.db_typ = MemodBaseIII;
+ m_aMemoHeader.db_size = 512;
+ }
+ break;
+ case VisualFoxPro:
+ case VisualFoxProAuto:
+ case FoxProMemo:
+ m_aMemoHeader.db_typ = MemoFoxPro;
+ m_pMemoStream->Seek(6);
+ m_pMemoStream->SetEndian(SvStreamEndian::BIG);
+ (*m_pMemoStream).ReadUInt16( m_aMemoHeader.db_size );
+ break;
+ default:
+ SAL_WARN( "connectivity.drivers", "ODbaseTable::ReadMemoHeader: unsupported memo type!" );
+ break;
+ }
+}
+
+OUString ODbaseTable::getEntry(file::OConnection const * _pConnection, std::u16string_view _sName )
+{
+ OUString sURL;
+ try
+ {
+ Reference< XResultSet > xDir = _pConnection->getDir()->getStaticResultSet();
+ Reference< XRow> xRow(xDir,UNO_QUERY);
+ OUString sName;
+ OUString sExt;
+ INetURLObject aURL;
+ xDir->beforeFirst();
+ while(xDir->next())
+ {
+ sName = xRow->getString(1);
+ aURL.SetSmartProtocol(INetProtocol::File);
+ OUString sUrl = _pConnection->getURL() + "/" + sName;
+ aURL.SetSmartURL( sUrl );
+
+ // cut the extension
+ sExt = aURL.getExtension();
+
+ // name and extension have to coincide
+ if ( _pConnection->matchesExtension( sExt ) )
+ {
+ sName = sName.replaceAt(sName.getLength() - (sExt.getLength() + 1), sExt.getLength() + 1, u"");
+ if ( sName == _sName )
+ {
+ Reference< XContentAccess > xContentAccess( xDir, UNO_QUERY );
+ sURL = xContentAccess->queryContentIdentifierString();
+ break;
+ }
+ }
+ }
+ xDir->beforeFirst(); // move back to before first record
+ }
+ catch(const Exception&)
+ {
+ OSL_ASSERT(false);
+ }
+ return sURL;
+}
+
+void ODbaseTable::refreshColumns()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ ::std::vector< OUString> aVector;
+ aVector.reserve(m_aColumns->size());
+
+ for (auto const& column : *m_aColumns)
+ aVector.push_back(Reference< XNamed>(column,UNO_QUERY_THROW)->getName());
+
+ if(m_xColumns)
+ m_xColumns->reFill(aVector);
+ else
+ m_xColumns.reset(new ODbaseColumns(this,m_aMutex,aVector));
+}
+
+void ODbaseTable::refreshIndexes()
+{
+ ::std::vector< OUString> aVector;
+ if(m_pFileStream && (!m_xIndexes || m_xIndexes->getCount() == 0))
+ {
+ INetURLObject aURL;
+ aURL.SetURL(getEntry(m_pConnection,m_Name));
+
+ aURL.setExtension(u"inf");
+ Config aInfFile(aURL.getFSysPath(FSysStyle::Detect));
+ aInfFile.SetGroup(dBASE_III_GROUP);
+ sal_uInt16 nKeyCnt = aInfFile.GetKeyCount();
+ OString aKeyName;
+
+ for (sal_uInt16 nKey = 0; nKey < nKeyCnt; nKey++)
+ {
+ // References the key an index-file?
+ aKeyName = aInfFile.GetKeyName( nKey );
+ //...if yes, add the index list of the table
+ if (aKeyName.startsWith("NDX"))
+ {
+ OString aIndexName = aInfFile.ReadKey(aKeyName);
+ aURL.setName(OStringToOUString(aIndexName, m_eEncoding));
+ try
+ {
+ Content aCnt(aURL.GetMainURL(INetURLObject::DecodeMechanism::NONE),Reference<XCommandEnvironment>(), comphelper::getProcessComponentContext());
+ if (aCnt.isDocument())
+ {
+ aVector.push_back(aURL.getBase());
+ }
+ }
+ catch(const Exception&) // an exception is thrown when no file exists
+ {
+ }
+ }
+ }
+ }
+ if(m_xIndexes)
+ m_xIndexes->reFill(aVector);
+ else
+ m_xIndexes.reset(new ODbaseIndexes(this,m_aMutex,aVector));
+}
+
+
+void SAL_CALL ODbaseTable::disposing()
+{
+ OFileTable::disposing();
+ ::osl::MutexGuard aGuard(m_aMutex);
+ m_aColumns = nullptr;
+}
+
+Sequence< Type > SAL_CALL ODbaseTable::getTypes( )
+{
+ Sequence< Type > aTypes = OTable_TYPEDEF::getTypes();
+ std::vector<Type> aOwnTypes;
+ aOwnTypes.reserve(aTypes.getLength());
+
+ const Type* pBegin = aTypes.getConstArray();
+ const Type* pEnd = pBegin + aTypes.getLength();
+ for(;pBegin != pEnd;++pBegin)
+ {
+ if(*pBegin != cppu::UnoType<XKeysSupplier>::get() &&
+ *pBegin != cppu::UnoType<XDataDescriptorFactory>::get())
+ {
+ aOwnTypes.push_back(*pBegin);
+ }
+ }
+ aOwnTypes.push_back(cppu::UnoType<css::lang::XUnoTunnel>::get());
+ return Sequence< Type >(aOwnTypes.data(), aOwnTypes.size());
+}
+
+
+Any SAL_CALL ODbaseTable::queryInterface( const Type & rType )
+{
+ if( rType == cppu::UnoType<XKeysSupplier>::get()||
+ rType == cppu::UnoType<XDataDescriptorFactory>::get())
+ return Any();
+
+ Any aRet = OTable_TYPEDEF::queryInterface(rType);
+ return aRet;
+}
+
+
+bool ODbaseTable::fetchRow(OValueRefRow& _rRow, const OSQLColumns & _rCols, bool bRetrieveData)
+{
+ if (!m_pBuffer)
+ return false;
+
+ // Read the data
+ bool bIsCurRecordDeleted = m_pBuffer[0] == '*';
+
+ // only read the bookmark
+
+ // Mark record as deleted
+ _rRow->setDeleted(bIsCurRecordDeleted);
+ *(*_rRow)[0] = m_nFilePos;
+
+ if (!bRetrieveData)
+ return true;
+
+ std::size_t nByteOffset = 1;
+ // Fields:
+ OSQLColumns::const_iterator aIter = _rCols.begin();
+ OSQLColumns::const_iterator aEnd = _rCols.end();
+ const std::size_t nCount = _rRow->size();
+ for (std::size_t i = 1; aIter != aEnd && nByteOffset <= m_nBufferSize && i < nCount;++aIter, i++)
+ {
+ // Lengths depending on data type:
+ sal_Int32 nLen = m_aPrecisions[i-1];
+ sal_Int32 nType = m_aTypes[i-1];
+
+ switch(nType)
+ {
+ case DataType::INTEGER:
+ case DataType::DOUBLE:
+ case DataType::TIMESTAMP:
+ case DataType::DATE:
+ case DataType::BIT:
+ case DataType::LONGVARCHAR:
+ case DataType::LONGVARBINARY:
+ nLen = m_aRealFieldLengths[i-1];
+ break;
+ case DataType::DECIMAL:
+ nLen = SvDbaseConverter::ConvertPrecisionToDbase(nLen,m_aScales[i-1]);
+ break; // the sign and the comma
+
+ case DataType::BINARY:
+ case DataType::OTHER:
+ nByteOffset += nLen;
+ continue;
+ }
+
+ // Is the variable bound?
+ if ( !(*_rRow)[i]->isBound() )
+ {
+ // No - next field.
+ nByteOffset += nLen;
+ OSL_ENSURE( nByteOffset <= m_nBufferSize ,"ByteOffset > m_nBufferSize!");
+ continue;
+ } // if ( !(_rRow->get())[i]->isBound() )
+ if ( ( nByteOffset + nLen) > m_nBufferSize )
+ break; // length doesn't match buffer size.
+
+ char *pData = reinterpret_cast<char *>(m_pBuffer.get() + nByteOffset);
+
+ if (nType == DataType::CHAR || nType == DataType::VARCHAR)
+ {
+ sal_Int32 nLastPos = -1;
+ for (sal_Int32 k = 0; k < nLen; ++k)
+ {
+ if (pData[k] != ' ')
+ // Record last non-empty position.
+ nLastPos = k;
+ }
+ if (nLastPos < 0)
+ {
+ // Empty string. Skip it.
+ (*_rRow)[i]->setNull();
+ }
+ else
+ {
+ // Commit the string
+ *(*_rRow)[i] = OUString(pData, static_cast<sal_Int32>(nLastPos+1), m_eEncoding);
+ }
+ } // if (nType == DataType::CHAR || nType == DataType::VARCHAR)
+ else if ( DataType::TIMESTAMP == nType )
+ {
+ sal_Int32 nDate = 0,nTime = 0;
+ if (o3tl::make_unsigned(nLen) < 8)
+ {
+ SAL_WARN("connectivity.drivers", "short TIMESTAMP");
+ return false;
+ }
+ memcpy(&nDate, pData, 4);
+ memcpy(&nTime, pData + 4, 4);
+ if ( !nDate && !nTime )
+ {
+ (*_rRow)[i]->setNull();
+ }
+ else
+ {
+ css::util::DateTime aDateTime;
+ lcl_CalDate(nDate,nTime,aDateTime);
+ *(*_rRow)[i] = aDateTime;
+ }
+ }
+ else if ( DataType::INTEGER == nType )
+ {
+ sal_Int32 nValue = 0;
+ if (o3tl::make_unsigned(nLen) > sizeof(nValue))
+ return false;
+ memcpy(&nValue, pData, nLen);
+ *(*_rRow)[i] = nValue;
+ }
+ else if ( DataType::DOUBLE == nType )
+ {
+ double d = 0.0;
+ if (getBOOL((*aIter)->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISCURRENCY)))) // Currency is treated separately
+ {
+ sal_Int64 nValue = 0;
+ if (o3tl::make_unsigned(nLen) > sizeof(nValue))
+ return false;
+ memcpy(&nValue, pData, nLen);
+
+ if ( m_aScales[i-1] )
+ d = (nValue / pow(10.0,static_cast<int>(m_aScales[i-1])));
+ else
+ d = static_cast<double>(nValue);
+ }
+ else
+ {
+ if (o3tl::make_unsigned(nLen) > sizeof(d))
+ return false;
+ memcpy(&d, pData, nLen);
+ }
+
+ *(*_rRow)[i] = d;
+ }
+ else
+ {
+ sal_Int32 nPos1 = -1, nPos2 = -1;
+ // If the string contains Nul-characters, then convert them to blanks!
+ for (sal_Int32 k = 0; k < nLen; k++)
+ {
+ if (pData[k] == '\0')
+ pData[k] = ' ';
+
+ if (pData[k] != ' ')
+ {
+ if (nPos1 < 0)
+ // first non-empty char position.
+ nPos1 = k;
+
+ // last non-empty char position.
+ nPos2 = k;
+ }
+ }
+
+ if (nPos1 < 0)
+ {
+ // Empty string. Skip it.
+ nByteOffset += nLen;
+ (*_rRow)[i]->setNull(); // no values -> done
+ continue;
+ }
+
+ OUString aStr(pData+nPos1, nPos2-nPos1+1, m_eEncoding);
+
+ switch (nType)
+ {
+ case DataType::DATE:
+ {
+ if (nLen < 8 || aStr.getLength() != nLen)
+ {
+ (*_rRow)[i]->setNull();
+ break;
+ }
+ const sal_uInt16 nYear = static_cast<sal_uInt16>(o3tl::toInt32(aStr.subView( 0, 4 )));
+ const sal_uInt16 nMonth = static_cast<sal_uInt16>(o3tl::toInt32(aStr.subView( 4, 2 )));
+ const sal_uInt16 nDay = static_cast<sal_uInt16>(o3tl::toInt32(aStr.subView( 6, 2 )));
+
+ const css::util::Date aDate(nDay,nMonth,nYear);
+ *(*_rRow)[i] = aDate;
+ }
+ break;
+ case DataType::DECIMAL:
+ *(*_rRow)[i] = ORowSetValue(aStr);
+ break;
+ case DataType::BIT:
+ {
+ bool b;
+ switch (*pData)
+ {
+ case 'T':
+ case 'Y':
+ case 'J': b = true; break;
+ default: b = false; break;
+ }
+ *(*_rRow)[i] = b;
+ }
+ break;
+ case DataType::LONGVARBINARY:
+ case DataType::BINARY:
+ case DataType::LONGVARCHAR:
+ {
+ const tools::Long nBlockNo = aStr.toInt32(); // read blocknumber
+ if (nBlockNo > 0 && m_pMemoStream) // Read data from memo-file, only if
+ {
+ if ( !ReadMemo(nBlockNo, (*_rRow)[i]->get()) )
+ break;
+ }
+ else
+ (*_rRow)[i]->setNull();
+ } break;
+ default:
+ SAL_WARN( "connectivity.drivers","Wrong type");
+ }
+ (*_rRow)[i]->setTypeKind(nType);
+ }
+
+ nByteOffset += nLen;
+ OSL_ENSURE( nByteOffset <= m_nBufferSize ,"ByteOffset > m_nBufferSize!");
+ }
+ return true;
+}
+
+
+void ODbaseTable::FileClose()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+
+ m_pMemoStream.reset();
+
+ ODbaseTable_BASE::FileClose();
+}
+
+bool ODbaseTable::CreateImpl()
+{
+ OSL_ENSURE(!m_pFileStream, "SequenceError");
+
+ if ( m_pConnection->isCheckEnabled() && ::dbtools::convertName2SQLName(m_Name, u"") != m_Name )
+ {
+ const OUString sError( getConnection()->getResources().getResourceStringWithSubstitution(
+ STR_SQL_NAME_ERROR,
+ "$name$", m_Name
+ ) );
+ ::dbtools::throwGenericSQLException( sError, *this );
+ }
+
+ INetURLObject aURL;
+ aURL.SetSmartProtocol(INetProtocol::File);
+ OUString aName = getEntry(m_pConnection, m_Name);
+ if(aName.isEmpty())
+ {
+ OUString aIdent = m_pConnection->getContent()->getIdentifier()->getContentIdentifier();
+ if ( aIdent.lastIndexOf('/') != (aIdent.getLength()-1) )
+ aIdent += "/";
+ aIdent += m_Name;
+ aName = aIdent;
+ }
+ aURL.SetURL(aName);
+
+ if ( !m_pConnection->matchesExtension( aURL.getExtension() ) )
+ aURL.setExtension(m_pConnection->getExtension());
+
+ try
+ {
+ Content aContent(aURL.GetMainURL(INetURLObject::DecodeMechanism::NONE),Reference<XCommandEnvironment>(), comphelper::getProcessComponentContext());
+ if (aContent.isDocument())
+ {
+ // Only if the file exists with length > 0 raise an error
+ std::unique_ptr<SvStream> pFileStream(createStream_simpleError( aURL.GetMainURL(INetURLObject::DecodeMechanism::NONE), StreamMode::READ));
+
+ if (pFileStream && pFileStream->TellEnd())
+ return false;
+ }
+ }
+ catch(const Exception&) // an exception is thrown when no file exists
+ {
+ }
+
+ bool bMemoFile = false;
+
+ bool bOk = CreateFile(aURL, bMemoFile);
+
+ FileClose();
+
+ if (!bOk)
+ {
+ try
+ {
+ Content aContent(aURL.GetMainURL(INetURLObject::DecodeMechanism::NONE),Reference<XCommandEnvironment>(), comphelper::getProcessComponentContext());
+ aContent.executeCommand( "delete", css::uno::Any( true ) );
+ }
+ catch(const Exception&) // an exception is thrown when no file exists
+ {
+ }
+ return false;
+ }
+
+ if (bMemoFile)
+ {
+ OUString aExt = aURL.getExtension();
+ aURL.setExtension(u"dbt"); // extension for memo file
+
+ bool bMemoAlreadyExists = false;
+ try
+ {
+ Content aMemo1Content(aURL.GetMainURL(INetURLObject::DecodeMechanism::NONE),Reference<XCommandEnvironment>(), comphelper::getProcessComponentContext());
+ bMemoAlreadyExists = aMemo1Content.isDocument();
+ }
+ catch(const Exception&) // an exception is thrown when no file exists
+ {
+ }
+ if (bMemoAlreadyExists)
+ {
+ aURL.setExtension(aExt); // kill dbf file
+ try
+ {
+ Content aMemoContent(aURL.GetMainURL(INetURLObject::DecodeMechanism::NONE),Reference<XCommandEnvironment>(), comphelper::getProcessComponentContext());
+ aMemoContent.executeCommand( "delete", css::uno::Any( true ) );
+ }
+ catch(const Exception&)
+ {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ const OUString sError( getConnection()->getResources().getResourceStringWithSubstitution(
+ STR_COULD_NOT_DELETE_FILE,
+ "$name$", aName
+ ) );
+ ::dbtools::throwGenericSQLException( sError, *this, anyEx );
+ }
+ }
+ if (!CreateMemoFile(aURL))
+ {
+ aURL.setExtension(aExt); // kill dbf file
+ try
+ {
+ Content aMemoContent(aURL.GetMainURL(INetURLObject::DecodeMechanism::NONE),Reference<XCommandEnvironment>(), comphelper::getProcessComponentContext());
+ aMemoContent.executeCommand( "delete", css::uno::Any( true ) );
+ }
+ catch(const ContentCreationException&)
+ {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ const OUString sError( getConnection()->getResources().getResourceStringWithSubstitution(
+ STR_COULD_NOT_DELETE_FILE,
+ "$name$", aName
+ ) );
+ ::dbtools::throwGenericSQLException( sError, *this, anyEx );
+ }
+ return false;
+ }
+ m_aHeader.type = dBaseIIIMemo;
+ }
+ else
+ m_aHeader.type = dBaseIII;
+
+ return true;
+}
+
+void ODbaseTable::throwInvalidColumnType(TranslateId pErrorId, const OUString& _sColumnName)
+{
+ try
+ {
+ // we have to drop the file because it is corrupted now
+ DropImpl();
+ }
+ catch(const Exception&)
+ {
+ }
+
+ const OUString sError( getConnection()->getResources().getResourceStringWithSubstitution(
+ pErrorId,
+ "$columnname$", _sColumnName
+ ) );
+ ::dbtools::throwGenericSQLException( sError, *this );
+}
+
+// creates in principle dBase IV file format
+bool ODbaseTable::CreateFile(const INetURLObject& aFile, bool& bCreateMemo)
+{
+ bCreateMemo = false;
+ Date aDate( Date::SYSTEM ); // current date
+
+ m_pFileStream = createStream_simpleError( aFile.GetMainURL(INetURLObject::DecodeMechanism::NONE),StreamMode::READWRITE | StreamMode::SHARE_DENYWRITE | StreamMode::TRUNC );
+
+ if (!m_pFileStream)
+ return false;
+
+ sal_uInt8 nDbaseType = dBaseIII;
+ Reference<XIndexAccess> xColumns(getColumns(),UNO_QUERY);
+ Reference<XPropertySet> xCol;
+ const OUString sPropType = OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE);
+
+ try
+ {
+ const sal_Int32 nCount = xColumns->getCount();
+ for(sal_Int32 i=0;i<nCount;++i)
+ {
+ xColumns->getByIndex(i) >>= xCol;
+ OSL_ENSURE(xCol.is(),"This should be a column!");
+
+ switch (getINT32(xCol->getPropertyValue(sPropType)))
+ {
+ case DataType::DOUBLE:
+ case DataType::INTEGER:
+ case DataType::TIMESTAMP:
+ case DataType::LONGVARBINARY:
+ nDbaseType = VisualFoxPro;
+ i = nCount; // no more columns need to be checked
+ break;
+ } // switch (getINT32(xCol->getPropertyValue(sPropType)))
+ }
+ }
+ catch ( const Exception& )
+ {
+ try
+ {
+ // we have to drop the file because it is corrupted now
+ DropImpl();
+ }
+ catch(const Exception&) { }
+ throw;
+ }
+
+ char aBuffer[21] = {}; // write buffer
+
+ m_pFileStream->Seek(0);
+ (*m_pFileStream).WriteUChar( nDbaseType ); // dBase format
+ (*m_pFileStream).WriteUChar( aDate.GetYearUnsigned() % 100 ); // current date
+
+
+ (*m_pFileStream).WriteUChar( aDate.GetMonth() );
+ (*m_pFileStream).WriteUChar( aDate.GetDay() );
+ (*m_pFileStream).WriteUInt32( 0 ); // number of data records
+ (*m_pFileStream).WriteUInt16( (m_xColumns->getCount()+1) * 32 + 1 ); // header information,
+ // pColumns contains always an additional column
+ (*m_pFileStream).WriteUInt16( 0 ); // record length will be determined later
+ m_pFileStream->WriteBytes(aBuffer, 20);
+
+ sal_uInt16 nRecLength = 1; // Length 1 for deleted flag
+ sal_Int32 nMaxFieldLength = m_pConnection->getMetaData()->getMaxColumnNameLength();
+ OUString aName;
+ const OUString sPropName = OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME);
+ const OUString sPropPrec = OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PRECISION);
+ const OUString sPropScale = OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCALE);
+
+ try
+ {
+ const sal_Int32 nCount = xColumns->getCount();
+ for(sal_Int32 i=0;i<nCount;++i)
+ {
+ xColumns->getByIndex(i) >>= xCol;
+ OSL_ENSURE(xCol.is(),"This should be a column!");
+
+ char cTyp( 'C' );
+
+ xCol->getPropertyValue(sPropName) >>= aName;
+
+ OString aCol;
+ if ( DBTypeConversion::convertUnicodeString( aName, aCol, m_eEncoding ) > nMaxFieldLength)
+ {
+ throwInvalidColumnType( STR_INVALID_COLUMN_NAME_LENGTH, aName );
+ }
+
+ m_pFileStream->WriteOString( aCol );
+ m_pFileStream->WriteBytes(aBuffer, 11 - aCol.getLength());
+
+ sal_Int32 nPrecision = 0;
+ xCol->getPropertyValue(sPropPrec) >>= nPrecision;
+ sal_Int32 nScale = 0;
+ xCol->getPropertyValue(sPropScale) >>= nScale;
+
+ bool bBinary = false;
+
+ switch (getINT32(xCol->getPropertyValue(sPropType)))
+ {
+ case DataType::CHAR:
+ case DataType::VARCHAR:
+ cTyp = 'C';
+ break;
+ case DataType::DOUBLE:
+ if (getBOOL(xCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISCURRENCY)))) // Currency will be treated separately
+ cTyp = 'Y';
+ else
+ cTyp = 'B';
+ break;
+ case DataType::INTEGER:
+ cTyp = 'I';
+ break;
+ case DataType::TINYINT:
+ case DataType::SMALLINT:
+ case DataType::BIGINT:
+ case DataType::DECIMAL:
+ case DataType::NUMERIC:
+ case DataType::REAL:
+ cTyp = 'N'; // only dBase 3 format
+ break;
+ case DataType::TIMESTAMP:
+ cTyp = 'T';
+ break;
+ case DataType::DATE:
+ cTyp = 'D';
+ break;
+ case DataType::BIT:
+ cTyp = 'L';
+ break;
+ case DataType::LONGVARBINARY:
+ bBinary = true;
+ [[fallthrough]];
+ case DataType::LONGVARCHAR:
+ cTyp = 'M';
+ break;
+ default:
+ {
+ throwInvalidColumnType(STR_INVALID_COLUMN_TYPE, aName);
+ }
+ }
+
+ (*m_pFileStream).WriteChar( cTyp );
+ if ( nDbaseType == VisualFoxPro )
+ (*m_pFileStream).WriteUInt32( nRecLength-1 );
+ else
+ m_pFileStream->WriteBytes(aBuffer, 4);
+
+ switch(cTyp)
+ {
+ case 'C':
+ OSL_ENSURE(nPrecision < 255, "ODbaseTable::Create: Column too long!");
+ if (nPrecision > 254)
+ {
+ throwInvalidColumnType(STR_INVALID_COLUMN_PRECISION, aName);
+ }
+ (*m_pFileStream).WriteUChar( std::min(static_cast<unsigned>(nPrecision), 255U) ); // field length
+ nRecLength = nRecLength + static_cast<sal_uInt16>(std::min(static_cast<sal_uInt16>(nPrecision), sal_uInt16(255UL)));
+ (*m_pFileStream).WriteUChar( 0 ); // decimals
+ break;
+ case 'F':
+ case 'N':
+ OSL_ENSURE(nPrecision >= nScale,
+ "ODbaseTable::Create: Field length must be larger than decimal places!");
+ if (nPrecision < nScale)
+ {
+ throwInvalidColumnType(STR_INVALID_PRECISION_SCALE, aName);
+ }
+ if (getBOOL(xCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISCURRENCY)))) // Currency will be treated separately
+ {
+ (*m_pFileStream).WriteUChar( 10 ); // standard length
+ (*m_pFileStream).WriteUChar( 4 );
+ nRecLength += 10;
+ }
+ else
+ {
+ sal_Int32 nPrec = SvDbaseConverter::ConvertPrecisionToDbase(nPrecision,nScale);
+
+ (*m_pFileStream).WriteUChar( nPrec );
+ (*m_pFileStream).WriteUChar( nScale );
+ nRecLength += static_cast<sal_uInt16>(nPrec);
+ }
+ break;
+ case 'L':
+ (*m_pFileStream).WriteUChar( 1 );
+ (*m_pFileStream).WriteUChar( 0 );
+ ++nRecLength;
+ break;
+ case 'I':
+ (*m_pFileStream).WriteUChar( 4 );
+ (*m_pFileStream).WriteUChar( 0 );
+ nRecLength += 4;
+ break;
+ case 'Y':
+ case 'B':
+ case 'T':
+ case 'D':
+ (*m_pFileStream).WriteUChar( 8 );
+ (*m_pFileStream).WriteUChar( 0 );
+ nRecLength += 8;
+ break;
+ case 'M':
+ bCreateMemo = true;
+ (*m_pFileStream).WriteUChar( 10 );
+ (*m_pFileStream).WriteUChar( 0 );
+ nRecLength += 10;
+ if ( bBinary )
+ aBuffer[0] = 0x06;
+ break;
+ default:
+ throwInvalidColumnType(STR_INVALID_COLUMN_TYPE, aName);
+ }
+ m_pFileStream->WriteBytes(aBuffer, 14);
+ aBuffer[0] = 0x00;
+ }
+
+ (*m_pFileStream).WriteUChar( FIELD_DESCRIPTOR_TERMINATOR ); // end of header
+ (*m_pFileStream).WriteChar( char(DBF_EOL) );
+ m_pFileStream->Seek(10);
+ (*m_pFileStream).WriteUInt16( nRecLength ); // set record length afterwards
+
+ if (bCreateMemo)
+ {
+ m_pFileStream->Seek(0);
+ if (nDbaseType == VisualFoxPro)
+ (*m_pFileStream).WriteUChar( FoxProMemo );
+ else
+ (*m_pFileStream).WriteUChar( dBaseIIIMemo );
+ } // if (bCreateMemo)
+ }
+ catch ( const Exception& )
+ {
+ try
+ {
+ // we have to drop the file because it is corrupted now
+ DropImpl();
+ }
+ catch(const Exception&) { }
+ throw;
+ }
+ return true;
+}
+
+bool ODbaseTable::HasMemoFields() const
+{
+ return m_aHeader.type > dBaseIV && !utl::ConfigManager::IsFuzzing();
+}
+
+// creates in principle dBase III file format
+bool ODbaseTable::CreateMemoFile(const INetURLObject& aFile)
+{
+ // filehandling macro for table creation
+ m_pMemoStream = createStream_simpleError( aFile.GetMainURL(INetURLObject::DecodeMechanism::NONE),StreamMode::READWRITE | StreamMode::SHARE_DENYWRITE);
+
+ if (!m_pMemoStream)
+ return false;
+
+ m_pMemoStream->SetStreamSize(512);
+
+ m_pMemoStream->Seek(0);
+ (*m_pMemoStream).WriteUInt32( 1 ); // pointer to the first free block
+
+ m_pMemoStream.reset();
+ return true;
+}
+
+bool ODbaseTable::Drop_Static(std::u16string_view _sUrl, bool _bHasMemoFields, OCollection* _pIndexes )
+{
+ INetURLObject aURL;
+ aURL.SetURL(_sUrl);
+
+ bool bDropped = ::utl::UCBContentHelper::Kill(aURL.GetMainURL(INetURLObject::DecodeMechanism::NONE));
+
+ if(bDropped)
+ {
+ if (_bHasMemoFields)
+ { // delete the memo fields
+ aURL.setExtension(u"dbt");
+ bDropped = ::utl::UCBContentHelper::Kill(aURL.GetMainURL(INetURLObject::DecodeMechanism::NONE));
+ }
+
+ if(bDropped)
+ {
+ if(_pIndexes)
+ {
+ try
+ {
+ sal_Int32 i = _pIndexes->getCount();
+ while (i)
+ {
+ _pIndexes->dropByIndex(--i);
+ }
+ }
+ catch(const SQLException&)
+ {
+ }
+ }
+ aURL.setExtension(u"inf");
+
+ // as the inf file does not necessarily exist, we aren't allowed to use UCBContentHelper::Kill
+ try
+ {
+ ::ucbhelper::Content aDeleteContent( aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), Reference< XCommandEnvironment >(), comphelper::getProcessComponentContext() );
+ aDeleteContent.executeCommand( "delete", Any( true ) );
+ }
+ catch(const Exception&)
+ {
+ // silently ignore this...
+ }
+ }
+ }
+ return bDropped;
+}
+
+bool ODbaseTable::DropImpl()
+{
+ FileClose();
+
+ if(!m_xIndexes)
+ refreshIndexes(); // look for indexes which must be deleted as well
+
+ bool bDropped = Drop_Static(getEntry(m_pConnection,m_Name),HasMemoFields(),m_xIndexes.get());
+ if(!bDropped)
+ {// we couldn't drop the table so we have to reopen it
+ construct();
+ if(m_xColumns)
+ m_xColumns->refresh();
+ }
+ return bDropped;
+}
+
+
+bool ODbaseTable::InsertRow(OValueRefVector& rRow, const Reference<XIndexAccess>& _xCols)
+{
+ // fill buffer with blanks
+ if (!AllocBuffer())
+ return false;
+
+ memset(m_pBuffer.get(), 0, m_aHeader.recordLength);
+ m_pBuffer[0] = ' ';
+
+ // Copy new row completely:
+ // ... and add at the end as new Record:
+ std::size_t nTempPos = m_nFilePos;
+
+ m_nFilePos = static_cast<std::size_t>(m_aHeader.nbRecords) + 1;
+ bool bInsertRow = UpdateBuffer( rRow, nullptr, _xCols, true );
+ if ( bInsertRow )
+ {
+ std::size_t nFileSize = 0, nMemoFileSize = 0;
+
+ nFileSize = lcl_getFileSize(*m_pFileStream);
+
+ if (HasMemoFields() && m_pMemoStream)
+ {
+ m_pMemoStream->Seek(STREAM_SEEK_TO_END);
+ nMemoFileSize = m_pMemoStream->Tell();
+ }
+
+ if (!WriteBuffer())
+ {
+ m_pFileStream->SetStreamSize(nFileSize); // restore old size
+
+ if (HasMemoFields() && m_pMemoStream)
+ m_pMemoStream->SetStreamSize(nMemoFileSize); // restore old size
+ m_nFilePos = nTempPos; // restore file position
+ }
+ else
+ {
+ (*m_pFileStream).WriteChar( char(DBF_EOL) ); // write EOL
+ // raise number of datasets in the header:
+ m_pFileStream->Seek( 4 );
+ (*m_pFileStream).WriteUInt32( m_aHeader.nbRecords + 1 );
+
+ m_pFileStream->Flush();
+
+ // raise number if successfully
+ m_aHeader.nbRecords++;
+ *rRow[0] = m_nFilePos; // set bookmark
+ m_nFilePos = nTempPos;
+ }
+ }
+ else
+ m_nFilePos = nTempPos;
+
+ return bInsertRow;
+}
+
+
+bool ODbaseTable::UpdateRow(OValueRefVector& rRow, OValueRefRow& pOrgRow, const Reference<XIndexAccess>& _xCols)
+{
+ // fill buffer with blanks
+ if (!AllocBuffer())
+ return false;
+
+ // position on desired record:
+ std::size_t nPos = m_aHeader.headerLength + static_cast<tools::Long>(m_nFilePos-1) * m_aHeader.recordLength;
+ m_pFileStream->Seek(nPos);
+ m_pFileStream->ReadBytes(m_pBuffer.get(), m_aHeader.recordLength);
+
+ std::size_t nMemoFileSize( 0 );
+ if (HasMemoFields() && m_pMemoStream)
+ {
+ m_pMemoStream->Seek(STREAM_SEEK_TO_END);
+ nMemoFileSize = m_pMemoStream->Tell();
+ }
+ if (!UpdateBuffer(rRow, pOrgRow, _xCols, false) || !WriteBuffer())
+ {
+ if (HasMemoFields() && m_pMemoStream)
+ m_pMemoStream->SetStreamSize(nMemoFileSize); // restore old size
+ }
+ else
+ {
+ m_pFileStream->Flush();
+ }
+ return true;
+}
+
+
+bool ODbaseTable::DeleteRow(const OSQLColumns& _rCols)
+{
+ // Set the Delete-Flag (be it set or not):
+ // Position on desired record:
+ std::size_t nFilePos = m_aHeader.headerLength + static_cast<tools::Long>(m_nFilePos-1) * m_aHeader.recordLength;
+ m_pFileStream->Seek(nFilePos);
+
+ OValueRefRow aRow = new OValueRefVector(_rCols.size());
+
+ if (!fetchRow(aRow,_rCols,true))
+ return false;
+
+ Reference<XPropertySet> xCol;
+ OUString aColName;
+ ::comphelper::UStringMixEqual aCase(isCaseSensitive());
+ for (sal_Int32 i = 0; i < m_xColumns->getCount(); i++)
+ {
+ Reference<XPropertySet> xIndex = isUniqueByColumnName(i);
+ if (xIndex.is())
+ {
+ xCol.set(m_xColumns->getByIndex(i), css::uno::UNO_QUERY);
+ OSL_ENSURE(xCol.is(),"ODbaseTable::DeleteRow column is null!");
+ if(xCol.is())
+ {
+ xCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME)) >>= aColName;
+
+ ODbaseIndex* pIndex = dynamic_cast<ODbaseIndex*>(xIndex.get());
+ assert(pIndex && "ODbaseTable::DeleteRow: No Index returned!");
+
+ OSQLColumns::const_iterator aIter = std::find_if(_rCols.begin(), _rCols.end(),
+ [&aCase, &aColName](const OSQLColumns::value_type& rxCol) {
+ return aCase(getString(rxCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_REALNAME))), aColName); });
+ if (aIter == _rCols.end())
+ continue;
+
+ auto nPos = static_cast<sal_Int32>(std::distance(_rCols.begin(), aIter)) + 1;
+ pIndex->Delete(m_nFilePos,*(*aRow)[nPos]);
+ }
+ }
+ }
+
+ m_pFileStream->Seek(nFilePos);
+ (*m_pFileStream).WriteUChar( '*' ); // mark the row in the table as deleted
+ m_pFileStream->Flush();
+ return true;
+}
+
+Reference<XPropertySet> ODbaseTable::isUniqueByColumnName(sal_Int32 _nColumnPos)
+{
+ if(!m_xIndexes)
+ refreshIndexes();
+ if(m_xIndexes->hasElements())
+ {
+ Reference<XPropertySet> xCol;
+ m_xColumns->getByIndex(_nColumnPos) >>= xCol;
+ OSL_ENSURE(xCol.is(),"ODbaseTable::isUniqueByColumnName column is null!");
+ OUString sColName;
+ xCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME)) >>= sColName;
+
+ Reference<XPropertySet> xIndex;
+ for(sal_Int32 i=0;i<m_xIndexes->getCount();++i)
+ {
+ xIndex.set(m_xIndexes->getByIndex(i), css::uno::UNO_QUERY);
+ if(xIndex.is() && getBOOL(xIndex->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISUNIQUE))))
+ {
+ Reference<XNameAccess> xCols(Reference<XColumnsSupplier>(xIndex,UNO_QUERY_THROW)->getColumns());
+ if(xCols->hasByName(sColName))
+ return xIndex;
+
+ }
+ }
+ }
+ return Reference<XPropertySet>();
+}
+
+static double toDouble(std::string_view rString)
+{
+ return ::rtl::math::stringToDouble( rString, '.', ',' );
+}
+
+
+bool ODbaseTable::UpdateBuffer(OValueRefVector& rRow, const OValueRefRow& pOrgRow, const Reference<XIndexAccess>& _xCols, const bool bForceAllFields)
+{
+ OSL_ENSURE(m_pBuffer,"Buffer is NULL!");
+ if ( !m_pBuffer )
+ return false;
+ sal_Int32 nByteOffset = 1;
+
+ // Update fields:
+ Reference<XPropertySet> xCol;
+ Reference<XPropertySet> xIndex;
+ OUString aColName;
+ const sal_Int32 nColumnCount = m_xColumns->getCount();
+ std::vector< Reference<XPropertySet> > aIndexedCols(nColumnCount);
+
+ ::comphelper::UStringMixEqual aCase(isCaseSensitive());
+
+ Reference<XIndexAccess> xColumns(m_xColumns.get());
+ // first search a key that exist already in the table
+ for (sal_Int32 i = 0; i < nColumnCount; ++i)
+ {
+ sal_Int32 nPos = i;
+ if(_xCols != xColumns)
+ {
+ m_xColumns->getByIndex(i) >>= xCol;
+ OSL_ENSURE(xCol.is(),"ODbaseTable::UpdateBuffer column is null!");
+ xCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME)) >>= aColName;
+
+ for(nPos = 0;nPos<_xCols->getCount();++nPos)
+ {
+ Reference<XPropertySet> xFindCol(
+ _xCols->getByIndex(nPos), css::uno::UNO_QUERY);
+ OSL_ENSURE(xFindCol.is(),"ODbaseTable::UpdateBuffer column is null!");
+ if(aCase(getString(xFindCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME))),aColName))
+ break;
+ }
+ if (nPos >= _xCols->getCount())
+ continue;
+ }
+
+ ++nPos;
+ xIndex = isUniqueByColumnName(i);
+ aIndexedCols[i] = xIndex;
+ if (xIndex.is())
+ {
+ // first check if the value is different to the old one and when if it conform to the index
+ if(pOrgRow.is() && (rRow[nPos]->getValue().isNull() || rRow[nPos] == (*pOrgRow)[nPos]))
+ continue;
+ else
+ {
+ ODbaseIndex* pIndex = dynamic_cast<ODbaseIndex*>(xIndex.get());
+ assert(pIndex && "ODbaseTable::UpdateBuffer: No Index returned!");
+
+ if (pIndex->Find(0,*rRow[nPos]))
+ {
+ // There is no unique value
+ if ( aColName.isEmpty() )
+ {
+ m_xColumns->getByIndex(i) >>= xCol;
+ OSL_ENSURE(xCol.is(),"ODbaseTable::UpdateBuffer column is null!");
+ xCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME)) >>= aColName;
+ xCol.clear();
+ } // if ( !aColName.getLength() )
+ const OUString sError( getConnection()->getResources().getResourceStringWithSubstitution(
+ STR_DUPLICATE_VALUE_IN_COLUMN
+ ,"$columnname$", aColName
+ ) );
+ ::dbtools::throwGenericSQLException( sError, *this );
+ }
+ }
+ }
+ }
+
+ // when we are here there is no double key in the table
+
+ for (sal_Int32 i = 0; i < nColumnCount && nByteOffset <= m_nBufferSize ; ++i)
+ {
+ // Lengths for each data type:
+ assert(i >= 0);
+ OSL_ENSURE(o3tl::make_unsigned(i) < m_aPrecisions.size(),"Illegal index!");
+ sal_Int32 nLen = 0;
+ sal_Int32 nType = 0;
+ sal_Int32 nScale = 0;
+ if ( o3tl::make_unsigned(i) < m_aPrecisions.size() )
+ {
+ nLen = m_aPrecisions[i];
+ nType = m_aTypes[i];
+ nScale = m_aScales[i];
+ }
+ else
+ {
+ m_xColumns->getByIndex(i) >>= xCol;
+ if ( xCol.is() )
+ {
+ xCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PRECISION)) >>= nLen;
+ xCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE)) >>= nType;
+ xCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCALE)) >>= nScale;
+ }
+ }
+
+ bool bSetZero = false;
+ switch (nType)
+ {
+ case DataType::INTEGER:
+ case DataType::DOUBLE:
+ case DataType::TIMESTAMP:
+ bSetZero = true;
+ [[fallthrough]];
+ case DataType::LONGVARBINARY:
+ case DataType::DATE:
+ case DataType::BIT:
+ case DataType::LONGVARCHAR:
+ nLen = m_aRealFieldLengths[i];
+ break;
+ case DataType::DECIMAL:
+ nLen = SvDbaseConverter::ConvertPrecisionToDbase(nLen,nScale);
+ break; // The sign and the comma
+ default:
+ break;
+
+ } // switch (nType)
+
+ sal_Int32 nPos = i;
+ if(_xCols != xColumns)
+ {
+ m_xColumns->getByIndex(i) >>= xCol;
+ OSL_ENSURE(xCol.is(),"ODbaseTable::UpdateBuffer column is null!");
+ xCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME)) >>= aColName;
+ for(nPos = 0;nPos<_xCols->getCount();++nPos)
+ {
+ Reference<XPropertySet> xFindCol(
+ _xCols->getByIndex(nPos), css::uno::UNO_QUERY);
+ if(aCase(getString(xFindCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME))),aColName))
+ break;
+ }
+ if (nPos >= _xCols->getCount())
+ {
+ nByteOffset += nLen;
+ continue;
+ }
+ }
+
+
+ ++nPos; // the row values start at 1
+ const ORowSetValue &thisColVal = rRow[nPos]->get();
+ const bool thisColIsBound = thisColVal.isBound();
+ const bool thisColIsNull = !thisColIsBound || thisColVal.isNull();
+ // don't overwrite non-bound columns
+ if ( ! (bForceAllFields || thisColIsBound) )
+ {
+ // No - don't overwrite this field, it has not changed.
+ nByteOffset += nLen;
+ continue;
+ }
+ if (aIndexedCols[i].is())
+ {
+ ODbaseIndex* pIndex = dynamic_cast<ODbaseIndex*>(aIndexedCols[i].get());
+ assert(pIndex && "ODbaseTable::UpdateBuffer: No Index returned!");
+ // Update !!
+ if (pOrgRow.is() && !thisColIsNull)
+ pIndex->Update(m_nFilePos, *(*pOrgRow)[nPos], thisColVal);
+ else
+ pIndex->Insert(m_nFilePos, thisColVal);
+ }
+
+ char* pData = reinterpret_cast<char *>(m_pBuffer.get() + nByteOffset);
+ if (thisColIsNull)
+ {
+ if ( bSetZero )
+ memset(pData,0,nLen); // Clear to NULL char ('\0')
+ else
+ memset(pData,' ',nLen); // Clear to space/blank ('\0x20')
+ nByteOffset += nLen;
+ OSL_ENSURE( nByteOffset <= m_nBufferSize ,"ByteOffset > m_nBufferSize!");
+ continue;
+ }
+
+ try
+ {
+ switch (nType)
+ {
+ case DataType::TIMESTAMP:
+ {
+ sal_Int32 nJulianDate = 0, nJulianTime = 0;
+ lcl_CalcJulDate(nJulianDate,nJulianTime, thisColVal.getDateTime());
+ // Exactly 8 bytes to copy:
+ memcpy(pData,&nJulianDate,4);
+ memcpy(pData+4,&nJulianTime,4);
+ }
+ break;
+ case DataType::DATE:
+ {
+ css::util::Date aDate;
+ if(thisColVal.getTypeKind() == DataType::DOUBLE)
+ aDate = ::dbtools::DBTypeConversion::toDate(thisColVal.getDouble());
+ else
+ aDate = thisColVal.getDate();
+ char s[sizeof("-327686553565535")];
+ // reserve enough space for hypothetical max length
+ snprintf(s,
+ sizeof(s),
+ "%04" SAL_PRIdINT32 "%02" SAL_PRIuUINT32 "%02" SAL_PRIuUINT32,
+ static_cast<sal_Int32>(aDate.Year),
+ static_cast<sal_uInt32>(aDate.Month),
+ static_cast<sal_uInt32>(aDate.Day));
+
+ // Exactly 8 bytes to copy (even if s could hypothetically be longer):
+ memcpy(pData,s,8);
+ } break;
+ case DataType::INTEGER:
+ {
+ sal_Int32 nValue = thisColVal.getInt32();
+ if (o3tl::make_unsigned(nLen) > sizeof(nValue))
+ return false;
+ memcpy(pData,&nValue,nLen);
+ }
+ break;
+ case DataType::DOUBLE:
+ {
+ const double d = thisColVal.getDouble();
+ m_xColumns->getByIndex(i) >>= xCol;
+
+ if (getBOOL(xCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISCURRENCY)))) // Currency is treated separately
+ {
+ sal_Int64 nValue = 0;
+ if ( m_aScales[i] )
+ nValue = static_cast<sal_Int64>(d * pow(10.0,static_cast<int>(m_aScales[i])));
+ else
+ nValue = static_cast<sal_Int64>(d);
+ if (o3tl::make_unsigned(nLen) > sizeof(nValue))
+ return false;
+ memcpy(pData,&nValue,nLen);
+ } // if (getBOOL(xCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISCURRENCY)))) // Currency is treated separately
+ else
+ {
+ if (o3tl::make_unsigned(nLen) > sizeof(d))
+ return false;
+ memcpy(pData,&d,nLen);
+ }
+ }
+ break;
+ case DataType::DECIMAL:
+ {
+ memset(pData,' ',nLen); // Clear to NULL
+
+ const double n = thisColVal.getDouble();
+
+ // one, because const_cast GetFormatPrecision on SvNumberFormat is not constant,
+ // even though it really could and should be
+ const OString aDefaultValue( ::rtl::math::doubleToString( n, rtl_math_StringFormat_F, nScale, '.', nullptr, 0));
+ const sal_Int32 nValueLen = aDefaultValue.getLength();
+ if ( nValueLen <= nLen )
+ {
+ // Write value right-justified, padded with blanks to the left.
+ memcpy(pData+nLen-nValueLen,aDefaultValue.getStr(),nValueLen);
+ // write the resulting double back
+ *rRow[nPos] = toDouble(aDefaultValue);
+ }
+ else
+ {
+ m_xColumns->getByIndex(i) >>= xCol;
+ OSL_ENSURE(xCol.is(),"ODbaseTable::UpdateBuffer column is null!");
+ xCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME)) >>= aColName;
+ std::vector< std::pair<const char* , OUString > > aStringToSubstitutes
+ {
+ { "$columnname$", aColName },
+ { "$precision$", OUString::number(nLen) },
+ { "$scale$", OUString::number(nScale) },
+ { "$value$", OStringToOUString(aDefaultValue,RTL_TEXTENCODING_UTF8) }
+ };
+
+ const OUString sError( getConnection()->getResources().getResourceStringWithSubstitution(
+ STR_INVALID_COLUMN_DECIMAL_VALUE
+ ,aStringToSubstitutes
+ ) );
+ ::dbtools::throwGenericSQLException( sError, *this );
+ }
+ } break;
+ case DataType::BIT:
+ *pData = thisColVal.getBool() ? 'T' : 'F';
+ break;
+ case DataType::LONGVARBINARY:
+ case DataType::LONGVARCHAR:
+ {
+ char cNext = pData[nLen]; // Mark's scratch and replaced by 0
+ pData[nLen] = '\0'; // This is because the buffer is always a sign of greater ...
+
+ std::size_t nBlockNo = strtol(pData,nullptr,10); // Block number read
+
+ // Next initial character restore again:
+ pData[nLen] = cNext;
+ if (!m_pMemoStream)
+ break;
+ WriteMemo(thisColVal, nBlockNo);
+
+ OString aBlock(OString::number(nBlockNo));
+ //align aBlock at the right of a nLen sequence, fill to the left with '0'
+ OStringBuffer aStr;
+ comphelper::string::padToLength(aStr, nLen - aBlock.getLength(), '0');
+ aStr.append(aBlock);
+
+ // Copy characters:
+ memcpy(pData, aStr.getStr(), nLen);
+ } break;
+ default:
+ {
+ memset(pData,' ',nLen); // Clear to NULL
+
+ OUString sStringToWrite( thisColVal.getString() );
+
+ // convert the string, using the connection's encoding
+ OString sEncoded;
+
+ DBTypeConversion::convertUnicodeStringToLength( sStringToWrite, sEncoded, nLen, m_eEncoding );
+ memcpy( pData, sEncoded.getStr(), sEncoded.getLength() );
+
+ }
+ break;
+ }
+ }
+ catch( const SQLException& )
+ {
+ throw;
+ }
+ catch ( const Exception& )
+ {
+ m_xColumns->getByIndex(i) >>= xCol;
+ OSL_ENSURE( xCol.is(), "ODbaseTable::UpdateBuffer column is null!" );
+ if ( xCol.is() )
+ xCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME)) >>= aColName;
+
+ const OUString sError( getConnection()->getResources().getResourceStringWithSubstitution(
+ STR_INVALID_COLUMN_VALUE,
+ "$columnname$", aColName
+ ) );
+ ::dbtools::throwGenericSQLException( sError, *this );
+ }
+ // And more ...
+ nByteOffset += nLen;
+ OSL_ENSURE( nByteOffset <= m_nBufferSize ,"ByteOffset > m_nBufferSize!");
+ }
+ return true;
+}
+
+
+void ODbaseTable::WriteMemo(const ORowSetValue& aVariable, std::size_t& rBlockNr)
+{
+ // if the BlockNo 0 is given, the block will be appended at the end
+ std::size_t nSize = 0;
+ OString aStr;
+ css::uno::Sequence<sal_Int8> aValue;
+ sal_uInt8 nHeader[4];
+ const bool bBinary = aVariable.getTypeKind() == DataType::LONGVARBINARY && m_aMemoHeader.db_typ == MemoFoxPro;
+ if ( bBinary )
+ {
+ aValue = aVariable.getSequence();
+ nSize = aValue.getLength();
+ }
+ else
+ {
+ nSize = DBTypeConversion::convertUnicodeString( aVariable.getString(), aStr, m_eEncoding );
+ }
+
+ // append or overwrite
+ bool bAppend = rBlockNr == 0;
+
+ if (!bAppend)
+ {
+ switch (m_aMemoHeader.db_typ)
+ {
+ case MemodBaseIII: // dBase III-Memofield, ends with 2 * Ctrl-Z
+ bAppend = nSize > (512 - 2);
+ break;
+ case MemoFoxPro:
+ case MemodBaseIV: // dBase IV-Memofield with length
+ {
+ char sHeader[4];
+ m_pMemoStream->Seek(rBlockNr * m_aMemoHeader.db_size);
+ m_pMemoStream->SeekRel(4);
+ m_pMemoStream->ReadBytes(sHeader, 4);
+
+ std::size_t nOldSize;
+ if (m_aMemoHeader.db_typ == MemoFoxPro)
+ nOldSize = ((static_cast<unsigned char>(sHeader[0]) * 256 +
+ static_cast<unsigned char>(sHeader[1])) * 256 +
+ static_cast<unsigned char>(sHeader[2])) * 256 +
+ static_cast<unsigned char>(sHeader[3]);
+ else
+ nOldSize = ((static_cast<unsigned char>(sHeader[3]) * 256 +
+ static_cast<unsigned char>(sHeader[2])) * 256 +
+ static_cast<unsigned char>(sHeader[1])) * 256 +
+ static_cast<unsigned char>(sHeader[0]) - 8;
+
+ // fits the new length in the used blocks
+ std::size_t nUsedBlocks = ((nSize + 8) / m_aMemoHeader.db_size) + (((nSize + 8) % m_aMemoHeader.db_size > 0) ? 1 : 0),
+ nOldUsedBlocks = ((nOldSize + 8) / m_aMemoHeader.db_size) + (((nOldSize + 8) % m_aMemoHeader.db_size > 0) ? 1 : 0);
+ bAppend = nUsedBlocks > nOldUsedBlocks;
+ }
+ }
+ }
+
+ if (bAppend)
+ {
+ sal_uInt64 const nStreamSize = m_pMemoStream->TellEnd();
+ // fill last block
+ rBlockNr = (nStreamSize / m_aMemoHeader.db_size) + ((nStreamSize % m_aMemoHeader.db_size) > 0 ? 1 : 0);
+
+ m_pMemoStream->SetStreamSize(rBlockNr * m_aMemoHeader.db_size);
+ m_pMemoStream->Seek(STREAM_SEEK_TO_END);
+ }
+ else
+ {
+ m_pMemoStream->Seek(rBlockNr * m_aMemoHeader.db_size);
+ }
+
+ switch (m_aMemoHeader.db_typ)
+ {
+ case MemodBaseIII: // dBase III-Memofield, ends with Ctrl-Z
+ {
+ const char cEOF = char(DBF_EOL);
+ nSize++;
+ m_pMemoStream->WriteBytes(aStr.getStr(), aStr.getLength());
+ m_pMemoStream->WriteChar( cEOF ).WriteChar( cEOF );
+ } break;
+ case MemoFoxPro:
+ case MemodBaseIV: // dBase IV-Memofield with length
+ {
+ if ( MemodBaseIV == m_aMemoHeader.db_typ )
+ (*m_pMemoStream).WriteUChar( 0xFF )
+ .WriteUChar( 0xFF )
+ .WriteUChar( 0x08 );
+ else
+ (*m_pMemoStream).WriteUChar( 0x00 )
+ .WriteUChar( 0x00 )
+ .WriteUChar( 0x00 );
+
+ sal_uInt32 nWriteSize = nSize;
+ if (m_aMemoHeader.db_typ == MemoFoxPro)
+ {
+ if ( bBinary )
+ (*m_pMemoStream).WriteUChar( 0x00 ); // Picture
+ else
+ (*m_pMemoStream).WriteUChar( 0x01 ); // Memo
+ for (int i = 4; i > 0; nWriteSize >>= 8)
+ nHeader[--i] = static_cast<sal_uInt8>(nWriteSize % 256);
+ }
+ else
+ {
+ (*m_pMemoStream).WriteUChar( 0x00 );
+ nWriteSize += 8;
+ for (int i = 0; i < 4; nWriteSize >>= 8)
+ nHeader[i++] = static_cast<sal_uInt8>(nWriteSize % 256);
+ }
+
+ m_pMemoStream->WriteBytes(nHeader, 4);
+ if ( bBinary )
+ m_pMemoStream->WriteBytes(aValue.getConstArray(), aValue.getLength());
+ else
+ m_pMemoStream->WriteBytes(aStr.getStr(), aStr.getLength());
+ m_pMemoStream->Flush();
+ }
+ }
+
+
+ // Write the new block number
+ if (bAppend)
+ {
+ sal_uInt64 const nStreamSize = m_pMemoStream->TellEnd();
+ m_aMemoHeader.db_next = (nStreamSize / m_aMemoHeader.db_size) + ((nStreamSize % m_aMemoHeader.db_size) > 0 ? 1 : 0);
+
+ // Write the new block number
+ m_pMemoStream->Seek(0);
+ (*m_pMemoStream).WriteUInt32( m_aMemoHeader.db_next );
+ m_pMemoStream->Flush();
+ }
+}
+
+
+// XAlterTable
+void SAL_CALL ODbaseTable::alterColumnByName( const OUString& colName, const Reference< XPropertySet >& descriptor )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(OTableDescriptor_BASE::rBHelper.bDisposed);
+
+
+ Reference<XDataDescriptorFactory> xOldColumn;
+ m_xColumns->getByName(colName) >>= xOldColumn;
+
+ try
+ {
+ alterColumn(m_xColumns->findColumn(colName)-1,descriptor,xOldColumn);
+ }
+ catch (const css::lang::IndexOutOfBoundsException&)
+ {
+ throw NoSuchElementException(colName, *this);
+ }
+}
+
+void SAL_CALL ODbaseTable::alterColumnByIndex( sal_Int32 index, const Reference< XPropertySet >& descriptor )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(OTableDescriptor_BASE::rBHelper.bDisposed);
+
+ if(index < 0 || index >= m_xColumns->getCount())
+ throw IndexOutOfBoundsException(OUString::number(index),*this);
+
+ Reference<XDataDescriptorFactory> xOldColumn;
+ m_xColumns->getByIndex(index) >>= xOldColumn;
+ alterColumn(index,descriptor,xOldColumn);
+}
+
+void ODbaseTable::alterColumn(sal_Int32 index,
+ const Reference< XPropertySet >& descriptor ,
+ const Reference< XDataDescriptorFactory >& xOldColumn )
+{
+ if(index < 0 || index >= m_xColumns->getCount())
+ throw IndexOutOfBoundsException(OUString::number(index),*this);
+
+ try
+ {
+ OSL_ENSURE(descriptor.is(),"ODbaseTable::alterColumn: descriptor can not be null!");
+ // creates a copy of the original column and copy all properties from descriptor in xCopyColumn
+ Reference<XPropertySet> xCopyColumn;
+ if(xOldColumn.is())
+ xCopyColumn = xOldColumn->createDataDescriptor();
+ else
+ xCopyColumn = new OColumn(getConnection()->getMetaData()->supportsMixedCaseQuotedIdentifiers());
+
+ ::comphelper::copyProperties(descriptor,xCopyColumn);
+
+ // creates a temp file
+
+ OUString sTempName = createTempFile();
+
+ rtl::Reference<ODbaseTable> pNewTable = new ODbaseTable(m_pTables,static_cast<ODbaseConnection*>(m_pConnection));
+ Reference<XPropertySet> xHoldTable = pNewTable;
+ pNewTable->setPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME),Any(sTempName));
+ Reference<XAppend> xAppend(pNewTable->getColumns(),UNO_QUERY);
+ OSL_ENSURE(xAppend.is(),"ODbaseTable::alterColumn: No XAppend interface!");
+
+ // copy the structure
+ sal_Int32 i=0;
+ for(;i < index;++i)
+ {
+ Reference<XPropertySet> xProp;
+ m_xColumns->getByIndex(i) >>= xProp;
+ Reference<XDataDescriptorFactory> xColumn(xProp,UNO_QUERY);
+ Reference<XPropertySet> xCpy;
+ if(xColumn.is())
+ xCpy = xColumn->createDataDescriptor();
+ else
+ xCpy = new OColumn(getConnection()->getMetaData()->supportsMixedCaseQuotedIdentifiers());
+ ::comphelper::copyProperties(xProp,xCpy);
+ xAppend->appendByDescriptor(xCpy);
+ }
+ ++i; // now insert our new column
+ xAppend->appendByDescriptor(xCopyColumn);
+
+ for(;i < m_xColumns->getCount();++i)
+ {
+ Reference<XPropertySet> xProp;
+ m_xColumns->getByIndex(i) >>= xProp;
+ Reference<XDataDescriptorFactory> xColumn(xProp,UNO_QUERY);
+ Reference<XPropertySet> xCpy;
+ if(xColumn.is())
+ xCpy = xColumn->createDataDescriptor();
+ else
+ xCpy = new OColumn(getConnection()->getMetaData()->supportsMixedCaseQuotedIdentifiers());
+ ::comphelper::copyProperties(xProp,xCpy);
+ xAppend->appendByDescriptor(xCpy);
+ }
+
+ // construct the new table
+ if(!pNewTable->CreateImpl())
+ {
+ const OUString sError( getConnection()->getResources().getResourceStringWithSubstitution(
+ STR_COLUMN_NOT_ALTERABLE,
+ "$columnname$", ::comphelper::getString(descriptor->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME)))
+ ) );
+ ::dbtools::throwGenericSQLException( sError, *this );
+ }
+
+ pNewTable->construct();
+
+ // copy the data
+ copyData(pNewTable.get(),0);
+
+ // now drop the old one
+ if( DropImpl() ) // we don't want to delete the memo columns too
+ {
+ try
+ {
+ // rename the new one to the old one
+ pNewTable->renameImpl(m_Name);
+ }
+ catch(const css::container::ElementExistException&)
+ {
+ const OUString sError( getConnection()->getResources().getResourceStringWithSubstitution(
+ STR_COULD_NOT_DELETE_FILE,
+ "$filename$", m_Name
+ ) );
+ ::dbtools::throwGenericSQLException( sError, *this );
+ }
+ // release the temp file
+ pNewTable = nullptr;
+ ::comphelper::disposeComponent(xHoldTable);
+ }
+ else
+ {
+ pNewTable = nullptr;
+ }
+ FileClose();
+ construct();
+ if(m_xColumns)
+ m_xColumns->refresh();
+
+ }
+ catch(const SQLException&)
+ {
+ throw;
+ }
+ catch(const Exception&)
+ {
+ TOOLS_WARN_EXCEPTION( "connectivity.drivers","");
+ throw;
+ }
+}
+
+Reference< XDatabaseMetaData> ODbaseTable::getMetaData() const
+{
+ return getConnection()->getMetaData();
+}
+
+void SAL_CALL ODbaseTable::rename( const OUString& newName )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(OTableDescriptor_BASE::rBHelper.bDisposed);
+ if(m_pTables && m_pTables->hasByName(newName))
+ throw ElementExistException(newName,*this);
+
+
+ renameImpl(newName);
+
+ ODbaseTable_BASE::rename(newName);
+
+ construct();
+ if(m_xColumns)
+ m_xColumns->refresh();
+}
+namespace
+{
+ void renameFile(file::OConnection const * _pConnection,std::u16string_view oldName,
+ const OUString& newName, std::u16string_view _sExtension)
+ {
+ OUString aName = ODbaseTable::getEntry(_pConnection,oldName);
+ if(aName.isEmpty())
+ {
+ OUString aIdent = _pConnection->getContent()->getIdentifier()->getContentIdentifier();
+ if ( aIdent.lastIndexOf('/') != (aIdent.getLength()-1) )
+ aIdent += "/";
+ aIdent += oldName;
+ aName = aIdent;
+ }
+ INetURLObject aURL;
+ aURL.SetURL(aName);
+
+ aURL.setExtension( _sExtension );
+ OUString sNewName(newName + "." + _sExtension);
+
+ try
+ {
+ Content aContent(aURL.GetMainURL(INetURLObject::DecodeMechanism::NONE),Reference<XCommandEnvironment>(), comphelper::getProcessComponentContext());
+
+ Sequence< PropertyValue > aProps{ { "Title",
+ -1, // n/a
+ Any(sNewName),
+ css::beans::PropertyState_DIRECT_VALUE } };
+ Sequence< Any > aValues;
+ aContent.executeCommand( "setPropertyValues",Any(aProps) ) >>= aValues;
+ if(aValues.hasElements() && aValues[0].hasValue())
+ throw Exception("setPropertyValues returned non-zero", nullptr);
+ }
+ catch(const Exception&)
+ {
+ throw ElementExistException(newName);
+ }
+ }
+}
+
+void ODbaseTable::renameImpl( const OUString& newName )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+
+ FileClose();
+
+
+ renameFile(m_pConnection,m_Name,newName,m_pConnection->getExtension());
+ if ( HasMemoFields() )
+ { // delete the memo fields
+ renameFile(m_pConnection,m_Name,newName,u"dbt");
+ }
+}
+
+void ODbaseTable::addColumn(const Reference< XPropertySet >& _xNewColumn)
+{
+ OUString sTempName = createTempFile();
+
+ rtl::Reference xNewTable(new ODbaseTable(m_pTables,static_cast<ODbaseConnection*>(m_pConnection)));
+ xNewTable->setPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME),Any(sTempName));
+ {
+ Reference<XAppend> xAppend(xNewTable->getColumns(),UNO_QUERY);
+ bool bCase = getConnection()->getMetaData()->supportsMixedCaseQuotedIdentifiers();
+ // copy the structure
+ for(sal_Int32 i=0;i < m_xColumns->getCount();++i)
+ {
+ Reference<XPropertySet> xProp;
+ m_xColumns->getByIndex(i) >>= xProp;
+ Reference<XDataDescriptorFactory> xColumn(xProp,UNO_QUERY);
+ Reference<XPropertySet> xCpy;
+ if(xColumn.is())
+ xCpy = xColumn->createDataDescriptor();
+ else
+ {
+ xCpy = new OColumn(bCase);
+ ::comphelper::copyProperties(xProp,xCpy);
+ }
+
+ xAppend->appendByDescriptor(xCpy);
+ }
+ Reference<XPropertySet> xCpy = new OColumn(bCase);
+ ::comphelper::copyProperties(_xNewColumn,xCpy);
+ xAppend->appendByDescriptor(xCpy);
+ }
+
+ // construct the new table
+ if(!xNewTable->CreateImpl())
+ {
+ const OUString sError( getConnection()->getResources().getResourceStringWithSubstitution(
+ STR_COLUMN_NOT_ADDABLE,
+ "$columnname$", ::comphelper::getString(_xNewColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME)))
+ ) );
+ ::dbtools::throwGenericSQLException( sError, *this );
+ }
+
+ xNewTable->construct();
+ // copy the data
+ copyData(xNewTable.get(),xNewTable->m_xColumns->getCount());
+ // drop the old table
+ if(DropImpl())
+ {
+ xNewTable->renameImpl(m_Name);
+ // release the temp file
+ }
+ xNewTable.clear();
+
+ FileClose();
+ construct();
+ if(m_xColumns)
+ m_xColumns->refresh();
+}
+
+void ODbaseTable::dropColumn(sal_Int32 _nPos)
+{
+ OUString sTempName = createTempFile();
+
+ rtl::Reference xNewTable(new ODbaseTable(m_pTables,static_cast<ODbaseConnection*>(m_pConnection)));
+ xNewTable->setPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME),Any(sTempName));
+ {
+ Reference<XAppend> xAppend(xNewTable->getColumns(),UNO_QUERY);
+ bool bCase = getConnection()->getMetaData()->supportsMixedCaseQuotedIdentifiers();
+ // copy the structure
+ for(sal_Int32 i=0;i < m_xColumns->getCount();++i)
+ {
+ if(_nPos != i)
+ {
+ Reference<XPropertySet> xProp;
+ m_xColumns->getByIndex(i) >>= xProp;
+ Reference<XDataDescriptorFactory> xColumn(xProp,UNO_QUERY);
+ Reference<XPropertySet> xCpy;
+ if(xColumn.is())
+ xCpy = xColumn->createDataDescriptor();
+ else
+ {
+ xCpy = new OColumn(bCase);
+ ::comphelper::copyProperties(xProp,xCpy);
+ }
+ xAppend->appendByDescriptor(xCpy);
+ }
+ }
+ }
+
+ // construct the new table
+ if(!xNewTable->CreateImpl())
+ {
+ const OUString sError( getConnection()->getResources().getResourceStringWithSubstitution(
+ STR_COLUMN_NOT_DROP,
+ "$position$", OUString::number(_nPos)
+ ) );
+ ::dbtools::throwGenericSQLException( sError, *this );
+ }
+ xNewTable->construct();
+ // copy the data
+ copyData(xNewTable.get(),_nPos);
+ // drop the old table
+ if(DropImpl())
+ xNewTable->renameImpl(m_Name);
+ // release the temp file
+
+ xNewTable.clear();
+
+ FileClose();
+ construct();
+}
+
+OUString ODbaseTable::createTempFile()
+{
+ OUString aIdent = m_pConnection->getContent()->getIdentifier()->getContentIdentifier();
+ if ( aIdent.lastIndexOf('/') != (aIdent.getLength()-1) )
+ aIdent += "/";
+
+ OUString sExt("." + m_pConnection->getExtension());
+ OUString aTempFileURL = utl::CreateTempURL(m_Name, true, sExt, &aIdent);
+ if(aTempFileURL.isEmpty())
+ getConnection()->throwGenericSQLException(STR_COULD_NOT_ALTER_TABLE, *this);
+
+ INetURLObject aURL;
+ aURL.SetSmartProtocol(INetProtocol::File);
+ aURL.SetURL(aTempFileURL);
+
+ OUString sNewName(aURL.getName().copy(0, aURL.getName().getLength() - sExt.getLength()));
+
+ return sNewName;
+}
+
+void ODbaseTable::copyData(ODbaseTable* _pNewTable,sal_Int32 _nPos)
+{
+ sal_Int32 nPos = _nPos + 1; // +1 because we always have the bookmark column as well
+ OValueRefRow aRow = new OValueRefVector(m_xColumns->getCount());
+ OValueRefRow aInsertRow;
+ if(_nPos)
+ {
+ aInsertRow = new OValueRefVector(_pNewTable->m_xColumns->getCount());
+ std::for_each(aInsertRow->begin(),aInsertRow->end(),TSetRefBound(true));
+ }
+ else
+ aInsertRow = aRow;
+
+ // we only have to bind the values which we need to copy into the new table
+ std::for_each(aRow->begin(),aRow->end(),TSetRefBound(true));
+ if(_nPos && (_nPos < static_cast<sal_Int32>(aRow->size())))
+ (*aRow)[nPos]->setBound(false);
+
+
+ sal_Int32 nCurPos;
+ OValueRefVector::const_iterator aIter;
+ for(sal_uInt32 nRowPos = 0; nRowPos < m_aHeader.nbRecords;++nRowPos)
+ {
+ bool bOk = seekRow( IResultSetHelper::BOOKMARK, nRowPos+1, nCurPos );
+ if ( bOk )
+ {
+ bOk = fetchRow( aRow, *m_aColumns, true);
+ if ( bOk && !aRow->isDeleted() ) // copy only not deleted rows
+ {
+ // special handling when pos == 0 then we don't have to distinguish between the two rows
+ if(_nPos)
+ {
+ aIter = aRow->begin()+1;
+ sal_Int32 nCount = 1;
+ for(OValueRefVector::iterator aInsertIter = aInsertRow->begin()+1; aIter != aRow->end() && aInsertIter != aInsertRow->end();++aIter,++nCount)
+ {
+ if(nPos != nCount)
+ {
+ (*aInsertIter)->setValue( (*aIter)->getValue() );
+ ++aInsertIter;
+ }
+ }
+ }
+ bOk = _pNewTable->InsertRow(*aInsertRow, _pNewTable->m_xColumns.get());
+ SAL_WARN_IF(!bOk, "connectivity.drivers", "Row could not be inserted!");
+ }
+ else
+ {
+ SAL_WARN_IF(!bOk, "connectivity.drivers", "Row could not be fetched!");
+ }
+ }
+ else
+ {
+ OSL_ASSERT(false);
+ }
+ } // for(sal_uInt32 nRowPos = 0; nRowPos < m_aHeader.db_anz;++nRowPos)
+}
+
+void ODbaseTable::throwInvalidDbaseFormat()
+{
+ FileClose();
+ // no dbase file
+
+ const OUString sError( getConnection()->getResources().getResourceStringWithSubstitution(
+ STR_INVALID_DBASE_FILE,
+ "$filename$", getEntry(m_pConnection,m_Name)
+ ) );
+ ::dbtools::throwGenericSQLException( sError, *this );
+}
+
+void ODbaseTable::refreshHeader()
+{
+ if ( m_aHeader.nbRecords == 0 )
+ readHeader();
+}
+
+bool ODbaseTable::seekRow(IResultSetHelper::Movement eCursorPosition, sal_Int32 nOffset, sal_Int32& nCurPos)
+{
+ // prepare positioning:
+ OSL_ENSURE(m_pFileStream,"ODbaseTable::seekRow: FileStream is NULL!");
+
+ sal_uInt32 nNumberOfRecords = m_aHeader.nbRecords;
+ sal_uInt32 nTempPos = m_nFilePos;
+ m_nFilePos = nCurPos;
+
+ switch(eCursorPosition)
+ {
+ case IResultSetHelper::NEXT:
+ ++m_nFilePos;
+ break;
+ case IResultSetHelper::PRIOR:
+ if (m_nFilePos > 0)
+ --m_nFilePos;
+ break;
+ case IResultSetHelper::FIRST:
+ m_nFilePos = 1;
+ break;
+ case IResultSetHelper::LAST:
+ m_nFilePos = nNumberOfRecords;
+ break;
+ case IResultSetHelper::RELATIVE1:
+ m_nFilePos = (m_nFilePos + nOffset < 0) ? 0
+ : static_cast<sal_uInt32>(m_nFilePos + nOffset);
+ break;
+ case IResultSetHelper::ABSOLUTE1:
+ case IResultSetHelper::BOOKMARK:
+ m_nFilePos = static_cast<sal_uInt32>(nOffset);
+ break;
+ }
+
+ if (m_nFilePos > static_cast<sal_Int32>(nNumberOfRecords))
+ m_nFilePos = static_cast<sal_Int32>(nNumberOfRecords) + 1;
+
+ if (m_nFilePos == 0 || m_nFilePos == static_cast<sal_Int32>(nNumberOfRecords) + 1)
+ goto Error;
+ else
+ {
+ std::size_t nEntryLen = m_aHeader.recordLength;
+
+ OSL_ENSURE(m_nFilePos >= 1,"SdbDBFCursor::FileFetchRow: invalid record position");
+ std::size_t nPos = m_aHeader.headerLength + static_cast<std::size_t>(m_nFilePos-1) * nEntryLen;
+
+ m_pFileStream->Seek(nPos);
+ if (m_pFileStream->GetError() != ERRCODE_NONE)
+ goto Error;
+
+ std::size_t nRead = m_pFileStream->ReadBytes(m_pBuffer.get(), nEntryLen);
+ if (nRead != nEntryLen)
+ {
+ SAL_WARN("connectivity.drivers", "ODbaseTable::seekRow: short read!");
+ goto Error;
+ }
+ if (m_pFileStream->GetError() != ERRCODE_NONE)
+ goto Error;
+ }
+ goto End;
+
+Error:
+ switch(eCursorPosition)
+ {
+ case IResultSetHelper::PRIOR:
+ case IResultSetHelper::FIRST:
+ m_nFilePos = 0;
+ break;
+ case IResultSetHelper::LAST:
+ case IResultSetHelper::NEXT:
+ case IResultSetHelper::ABSOLUTE1:
+ case IResultSetHelper::RELATIVE1:
+ if (nOffset > 0)
+ m_nFilePos = nNumberOfRecords + 1;
+ else if (nOffset < 0)
+ m_nFilePos = 0;
+ break;
+ case IResultSetHelper::BOOKMARK:
+ m_nFilePos = nTempPos; // last position
+ }
+ return false;
+
+End:
+ nCurPos = m_nFilePos;
+ return true;
+}
+
+bool ODbaseTable::ReadMemo(std::size_t nBlockNo, ORowSetValue& aVariable)
+{
+ m_pMemoStream->Seek(nBlockNo * m_aMemoHeader.db_size);
+ switch (m_aMemoHeader.db_typ)
+ {
+ case MemodBaseIII: // dBase III-Memofield, ends with Ctrl-Z
+ {
+ const char cEOF = char(DBF_EOL);
+ OStringBuffer aBStr;
+ static char aBuf[514];
+ aBuf[512] = 0; // avoid random value
+ bool bReady = false;
+
+ do
+ {
+ m_pMemoStream->ReadBytes(&aBuf, 512);
+
+ sal_uInt16 i = 0;
+ while (aBuf[i] != cEOF && ++i < 512)
+ ;
+ bReady = aBuf[i] == cEOF;
+
+ aBuf[i] = 0;
+ aBStr.append(aBuf);
+
+ } while (!bReady && !m_pMemoStream->eof());
+
+ aVariable = OStringToOUString(aBStr,
+ m_eEncoding);
+
+ } break;
+ case MemoFoxPro:
+ case MemodBaseIV: // dBase IV-Memofield with length
+ {
+ bool bIsText = true;
+ char sHeader[4];
+ m_pMemoStream->ReadBytes(sHeader, 4);
+ // Foxpro stores text and binary data
+ if (m_aMemoHeader.db_typ == MemoFoxPro)
+ {
+ bIsText = sHeader[3] != 0;
+ }
+ else if (static_cast<sal_uInt8>(sHeader[0]) != 0xFF || static_cast<sal_uInt8>(sHeader[1]) != 0xFF || static_cast<sal_uInt8>(sHeader[2]) != 0x08)
+ {
+ return false;
+ }
+
+ sal_uInt32 nLength(0);
+ (*m_pMemoStream).ReadUInt32( nLength );
+
+ if (m_aMemoHeader.db_typ == MemodBaseIV)
+ nLength -= 8;
+
+ if ( nLength )
+ {
+ if ( bIsText )
+ {
+ OStringBuffer aBuffer(read_uInt8s_ToOString(*m_pMemoStream, nLength));
+ //pad it out with ' ' to expected length on short read
+ sal_Int32 nRequested = sal::static_int_cast<sal_Int32>(nLength);
+ comphelper::string::padToLength(aBuffer, nRequested, ' ');
+ aVariable = OStringToOUString(aBuffer, m_eEncoding);
+ } // if ( bIsText )
+ else
+ {
+ css::uno::Sequence< sal_Int8 > aData(nLength);
+ m_pMemoStream->ReadBytes(aData.getArray(), nLength);
+ aVariable = aData;
+ }
+ } // if ( nLength )
+ }
+ }
+ return true;
+}
+
+bool ODbaseTable::AllocBuffer()
+{
+ sal_uInt16 nSize = m_aHeader.recordLength;
+ SAL_WARN_IF(nSize == 0, "connectivity.drivers", "Size too small");
+
+ if (m_nBufferSize != nSize)
+ {
+ m_pBuffer.reset();
+ }
+
+ // if there is no buffer available: allocate:
+ if (!m_pBuffer && nSize > 0)
+ {
+ m_nBufferSize = nSize;
+ m_pBuffer.reset(new sal_uInt8[m_nBufferSize+1]);
+ }
+
+ return m_pBuffer != nullptr;
+}
+
+bool ODbaseTable::WriteBuffer()
+{
+ OSL_ENSURE(m_nFilePos >= 1,"SdbDBFCursor::FileFetchRow: invalid record position");
+
+ // position on desired record:
+ std::size_t nPos = m_aHeader.headerLength + static_cast<tools::Long>(m_nFilePos-1) * m_aHeader.recordLength;
+ m_pFileStream->Seek(nPos);
+ return m_pFileStream->WriteBytes(m_pBuffer.get(), m_aHeader.recordLength) > 0;
+}
+
+sal_Int32 ODbaseTable::getCurrentLastPos() const
+{
+ return m_aHeader.nbRecords;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/dbase/DTables.cxx b/connectivity/source/drivers/dbase/DTables.cxx
new file mode 100644
index 0000000000..81b355f63d
--- /dev/null
+++ b/connectivity/source/drivers/dbase/DTables.cxx
@@ -0,0 +1,127 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <dbase/DConnection.hxx>
+#include <dbase/DTables.hxx>
+#include <dbase/DTable.hxx>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <file/FCatalog.hxx>
+#include <file/FConnection.hxx>
+#include <com/sun/star/lang/XUnoTunnel.hpp>
+#include <dbase/DCatalog.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+#include <strings.hrc>
+#include <connectivity/dbexception.hxx>
+
+using namespace ::comphelper;
+using namespace connectivity;
+using namespace connectivity::dbase;
+using namespace connectivity::file;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::container;
+
+sdbcx::ObjectType ODbaseTables::createObject(const OUString& _rName)
+{
+ rtl::Reference<ODbaseTable> pRet = new ODbaseTable(this, static_cast<ODbaseConnection*>(static_cast<OFileCatalog&>(m_rParent).getConnection()),
+ _rName,"TABLE");
+
+ pRet->construct();
+ return pRet;
+}
+
+void ODbaseTables::impl_refresh( )
+{
+ static_cast<ODbaseCatalog*>(&m_rParent)->refreshTables();
+}
+
+Reference< XPropertySet > ODbaseTables::createDescriptor()
+{
+ return new ODbaseTable(this, static_cast<ODbaseConnection*>(static_cast<OFileCatalog&>(m_rParent).getConnection()));
+}
+
+// XAppend
+sdbcx::ObjectType ODbaseTables::appendObject( const OUString& _rForName, const Reference< XPropertySet >& descriptor )
+{
+ auto pTable = dynamic_cast<ODbaseTable*>(descriptor.get());
+ if(pTable)
+ {
+ pTable->setPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME),Any(_rForName));
+ try
+ {
+ if(!pTable->CreateImpl())
+ throw SQLException();
+ }
+ catch(SQLException&)
+ {
+ throw;
+ }
+ catch(Exception& ex)
+ {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ throw SQLException( ex.Message, nullptr, "", 0, anyEx );
+ }
+ }
+ return createObject( _rForName );
+}
+
+// XDrop
+void ODbaseTables::dropObject(sal_Int32 _nPos, const OUString& _sElementName)
+{
+ Reference< XInterface > xTunnel;
+ try
+ {
+ xTunnel.set(getObject(_nPos),UNO_QUERY);
+ }
+ catch(const Exception&)
+ {
+ if(ODbaseTable::Drop_Static(ODbaseTable::getEntry(static_cast<OFileCatalog&>(m_rParent).getConnection(),_sElementName),false,nullptr))
+ return;
+ }
+
+ if ( xTunnel.is() )
+ {
+ ODbaseTable* pTable = dynamic_cast<ODbaseTable*>(xTunnel.get());
+ if(pTable)
+ pTable->DropImpl();
+ }
+ else
+ {
+ const OUString sError( static_cast<OFileCatalog&>(m_rParent).getConnection()->getResources().getResourceStringWithSubstitution(
+ STR_TABLE_NOT_DROP,
+ "$tablename$", _sElementName
+ ) );
+ ::dbtools::throwGenericSQLException( sError, nullptr );
+ }
+}
+
+Any SAL_CALL ODbaseTables::queryInterface( const Type & rType )
+{
+ typedef sdbcx::OCollection OTables_BASE;
+ return OTables_BASE::queryInterface(rType);
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/dbase/dbase.component b/connectivity/source/drivers/dbase/dbase.component
new file mode 100644
index 0000000000..b078a765d8
--- /dev/null
+++ b/connectivity/source/drivers/dbase/dbase.component
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ -->
+
+<component loader="com.sun.star.loader.SharedLibrary" environment="@CPPU_ENV@"
+ xmlns="http://openoffice.org/2010/uno-components">
+ <implementation name="com.sun.star.comp.sdbc.dbase.ODriver"
+ constructor="connectivity_dbase_ODriver">
+ <service name="com.sun.star.sdbc.Driver"/>
+ <service name="com.sun.star.sdbcx.Driver"/>
+ </implementation>
+</component>
diff --git a/connectivity/source/drivers/dbase/dindexnode.cxx b/connectivity/source/drivers/dbase/dindexnode.cxx
new file mode 100644
index 0000000000..d091335f54
--- /dev/null
+++ b/connectivity/source/drivers/dbase/dindexnode.cxx
@@ -0,0 +1,1047 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <dbase/dindexnode.hxx>
+#include <dbase/DIndex.hxx>
+#include <o3tl/safeint.hxx>
+#include <tools/debug.hxx>
+#include <tools/stream.hxx>
+#include <sal/log.hxx>
+
+#include <algorithm>
+#include <memory>
+#include <utility>
+
+
+using namespace connectivity;
+using namespace connectivity::dbase;
+using namespace connectivity::file;
+using namespace com::sun::star::sdbc;
+
+ONDXKey::ONDXKey()
+ :nRecord(0)
+{
+}
+
+ONDXKey::ONDXKey(ORowSetValue aVal, sal_Int32 eType, sal_uInt32 nRec)
+ : ONDXKey_BASE(eType)
+ , nRecord(nRec)
+ , xValue(std::move(aVal))
+{
+}
+
+ONDXKey::ONDXKey(const OUString& aStr, sal_uInt32 nRec)
+ : ONDXKey_BASE(css::sdbc::DataType::VARCHAR)
+ ,nRecord(nRec)
+{
+ if (!aStr.isEmpty())
+ {
+ xValue = aStr;
+ xValue.setBound(true);
+ }
+}
+
+ONDXKey::ONDXKey(double aVal, sal_uInt32 nRec)
+ : ONDXKey_BASE(css::sdbc::DataType::DOUBLE)
+ ,nRecord(nRec)
+ ,xValue(aVal)
+{
+}
+
+// index page
+ONDXPage::ONDXPage(ODbaseIndex& rInd, sal_uInt32 nPos, ONDXPage* pParent)
+ : nRefCount(0)
+ , bNoDelete(1)
+ , nPagePos(nPos)
+ , bModified(false)
+ , nCount(0)
+ , aParent(pParent)
+ , rIndex(rInd)
+{
+ sal_uInt16 nT = rIndex.getHeader().db_maxkeys;
+ ppNodes.reset( new ONDXNode[nT] );
+}
+
+ONDXPage::~ONDXPage()
+{
+}
+
+void ONDXPage::ReleaseRef()
+{
+ assert( nRefCount >= 1);
+ if(--nRefCount == 0 && !bNoDelete)
+ {
+ QueryDelete();
+ }
+}
+
+void ONDXPage::QueryDelete()
+{
+ // Store in GarbageCollector
+ if (IsModified() && rIndex.m_pFileStream)
+ WriteONDXPage( *rIndex.m_pFileStream, *this );
+
+ bModified = false;
+ if (rIndex.UseCollector())
+ {
+ if (aChild.Is())
+ aChild->Release(false);
+
+ for (sal_uInt16 i = 0; i < rIndex.getHeader().db_maxkeys;i++)
+ {
+ if (ppNodes[i].GetChild().Is())
+ ppNodes[i].GetChild()->Release(false);
+
+ ppNodes[i] = ONDXNode();
+ }
+ bNoDelete = 1;
+
+ nCount = 0;
+ aParent.Clear();
+ rIndex.Collect(this);
+ }
+ else
+ {
+ // I'm not sure about the original purpose of this line, but right now
+ // it serves the purpose that anything that attempts to do an AddFirstRef()
+ // after an object is deleted will trip an assert.
+ nRefCount = 1 << 30;
+ delete this;
+ }
+}
+
+ONDXPagePtr& ONDXPage::GetChild(ODbaseIndex const * pIndex)
+{
+ if (!aChild.Is() && pIndex)
+ {
+ aChild = rIndex.CreatePage(aChild.GetPagePos(),this,aChild.HasPage());
+ }
+ return aChild;
+}
+
+
+sal_uInt16 ONDXPage::FindPos(const ONDXKey& rKey) const
+{
+ // searches the position for the given key in a page
+ sal_uInt16 i = 0;
+ while (i < nCount && rKey > ((*this)[i]).GetKey())
+ i++;
+
+ return i;
+}
+
+
+bool ONDXPage::Find(const ONDXKey& rKey)
+{
+ // searches the given key
+ // Speciality: At the end of the method
+ // the actual page and the position of the node, fulfilling the '<=' condition, are saved
+ // This is considered at insert.
+ sal_uInt16 i = 0;
+ while (i < nCount && rKey > ((*this)[i]).GetKey())
+ i++;
+
+ bool bResult = false;
+
+ if (!IsLeaf())
+ {
+ // descend further
+ ONDXPagePtr aPage = (i==0) ? GetChild(&rIndex) : ((*this)[i-1]).GetChild(&rIndex, this);
+ bResult = aPage.Is() && aPage->Find(rKey);
+ }
+ else if (i == nCount)
+ {
+ rIndex.m_aCurLeaf = this;
+ rIndex.m_nCurNode = i - 1;
+ bResult = false;
+ }
+ else
+ {
+ bResult = rKey == ((*this)[i]).GetKey();
+ rIndex.m_aCurLeaf = this;
+ rIndex.m_nCurNode = bResult ? i : i - 1;
+ }
+ return bResult;
+}
+
+
+bool ONDXPage::Insert(ONDXNode& rNode, sal_uInt32 nRowsLeft)
+{
+ // When creating an index there can be multiple nodes added,
+ // these are sorted ascending
+ bool bAppend = nRowsLeft > 0;
+ if (IsFull())
+ {
+ ONDXNode aSplitNode;
+ if (bAppend)
+ aSplitNode = rNode;
+ else
+ {
+ // Save the last node
+ aSplitNode = (*this)[nCount-1];
+ if(rNode.GetKey() <= aSplitNode.GetKey())
+ {
+ bool bResult = true;
+ // this practically reduces the number of nodes by 1
+ if (IsLeaf() && this == rIndex.m_aCurLeaf)
+ {
+ // assumes, that the node, for which the condition (<=) holds, is stored in m_nCurNode
+ --nCount; // (otherwise we might get Assertions and GPFs - 60593)
+ bResult = Insert(rIndex.m_nCurNode + 1, rNode);
+ }
+ else // position unknown
+ {
+ sal_uInt16 nPos = NODE_NOTFOUND;
+ while (++nPos < nCount && rNode.GetKey() > ((*this)[nPos]).GetKey()) ;
+
+ --nCount; // (otherwise we might get Assertions and GPFs - 60593)
+ bResult = Insert(nPos, rNode);
+ }
+
+ // can the new node be inserted
+ if (!bResult)
+ {
+ nCount++;
+ aSplitNode = rNode;
+ }
+ }
+ else
+ aSplitNode = rNode;
+ }
+
+ sal_uInt32 nNewPagePos = rIndex.GetPageCount();
+ sal_uInt32 nNewPageCount = nNewPagePos + 1;
+
+ // insert extracted node into parent node
+ if (!HasParent())
+ {
+ // No parent, then new root
+ ONDXPagePtr aNewRoot = rIndex.CreatePage(nNewPagePos + 1);
+ aNewRoot->SetChild(this);
+
+ rIndex.m_aRoot = aNewRoot;
+ rIndex.SetRootPos(nNewPagePos + 1);
+ rIndex.SetPageCount(++nNewPageCount);
+ }
+
+ // create new leaf and divide page
+ ONDXPagePtr aNewPage = rIndex.CreatePage(nNewPagePos,aParent);
+ rIndex.SetPageCount(nNewPageCount);
+
+ // How many nodes are being inserted?
+ // Enough, then we can fill the page to the brim
+ ONDXNode aInnerNode;
+ if (!IsLeaf() || nRowsLeft < o3tl::make_unsigned(rIndex.GetMaxNodes() / 2))
+ aInnerNode = Split(*aNewPage);
+ else
+ {
+ aInnerNode = (*this)[nCount - 1];
+
+ // Node points to the new page
+ aInnerNode.SetChild(aNewPage);
+
+ // Inner nodes have no record number
+ if (rIndex.isUnique())
+ aInnerNode.GetKey().ResetRecord();
+
+ // new page points to the page of the extracted node
+ if (!IsLeaf())
+ aNewPage->SetChild(aInnerNode.GetChild());
+ }
+
+ aNewPage->Append(aSplitNode);
+ ONDXPagePtr aTempParent = aParent;
+ if (IsLeaf())
+ {
+ rIndex.m_aCurLeaf = aNewPage;
+ rIndex.m_nCurNode = rIndex.m_aCurLeaf->Count() - 1;
+
+ // free not needed pages, there are no references to those on the page
+ // afterwards 'this' can't be valid anymore!!!
+ ReleaseFull();
+ }
+
+ // Insert extracted node
+ return aTempParent->Insert(aInnerNode);
+ }
+ else // Fill the page up
+ {
+ if (bAppend)
+ {
+ if (IsLeaf())
+ rIndex.m_nCurNode = nCount - 1;
+ return Append(rNode);
+ }
+ else
+ {
+ sal_uInt16 nNodePos = FindPos(rNode.GetKey());
+ if (IsLeaf())
+ rIndex.m_nCurNode = nNodePos;
+
+ return Insert(nNodePos, rNode);
+ }
+ }
+}
+
+
+bool ONDXPage::Insert(sal_uInt16 nPos, ONDXNode& rNode)
+{
+ sal_uInt16 nMaxCount = rIndex.getHeader().db_maxkeys;
+ if (nPos >= nMaxCount)
+ return false;
+
+ if (nCount)
+ {
+ ++nCount;
+ // shift right
+ for (sal_uInt16 i = std::min(static_cast<sal_uInt16>(nMaxCount-1), static_cast<sal_uInt16>(nCount-1)); nPos < i; --i)
+ (*this)[i] = (*this)[i-1];
+ }
+ else
+ if (nCount < nMaxCount)
+ nCount++;
+
+ // insert at the position
+ ONDXNode& rInsertNode = (*this)[nPos];
+ rInsertNode = rNode;
+ if (rInsertNode.GetChild().Is())
+ {
+ rInsertNode.GetChild()->SetParent(this);
+ rNode.GetChild()->SetParent(this);
+ }
+
+ bModified = true;
+
+ return true;
+}
+
+
+bool ONDXPage::Append(ONDXNode& rNode)
+{
+ DBG_ASSERT(!IsFull(), "no Append possible");
+ return Insert(nCount, rNode);
+}
+
+void ONDXPage::Release(bool bSave)
+{
+ // free pages
+ if (aChild.Is())
+ aChild->Release(bSave);
+
+ // free pointer
+ aChild.Clear();
+
+ for (sal_uInt16 i = 0; i < rIndex.getHeader().db_maxkeys;i++)
+ {
+ if (ppNodes[i].GetChild())
+ ppNodes[i].GetChild()->Release(bSave);
+
+ ppNodes[i].GetChild().Clear();
+ }
+ aParent.Clear();
+}
+
+void ONDXPage::ReleaseFull()
+{
+ ONDXPagePtr aTempParent = aParent;
+ Release();
+
+ if (aTempParent.Is())
+ {
+ // Free pages not needed, there will be no reference anymore to the pages
+ // afterwards 'this' can't be valid anymore!!!
+ sal_uInt16 nParentPos = aTempParent->Search(this);
+ if (nParentPos != NODE_NOTFOUND)
+ (*aTempParent)[nParentPos].GetChild().Clear();
+ else
+ aTempParent->GetChild().Clear();
+ }
+}
+
+void ONDXPage::Delete(sal_uInt16 nNodePos)
+{
+ if (IsLeaf())
+ {
+ // The last element will not be deleted
+ if (nNodePos == (nCount - 1))
+ {
+ ONDXNode aNode = (*this)[nNodePos];
+
+ // parent's KeyValue has to be replaced
+ if (HasParent())
+ aParent->SearchAndReplace(aNode.GetKey(),
+ (*this)[nNodePos-1].GetKey());
+ }
+ }
+
+ // Delete the node
+ Remove(nNodePos);
+
+ // Underflow
+ if (HasParent() && nCount < (rIndex.GetMaxNodes() / 2))
+ {
+ // determine, which node points to the page
+ sal_uInt16 nParentNodePos = aParent->Search(this);
+ // last element on parent-page -> merge with secondlast page
+ if (nParentNodePos == (aParent->Count() - 1))
+ {
+ if (!nParentNodePos)
+ // merge with left neighbour
+ Merge(nParentNodePos,aParent->GetChild(&rIndex));
+ else
+ Merge(nParentNodePos,(*aParent)[nParentNodePos-1].GetChild(&rIndex,aParent));
+ }
+ // otherwise merge page with next page
+ else
+ {
+ // merge with right neighbour
+ Merge(nParentNodePos + 1,((*aParent)[nParentNodePos + 1].GetChild(&rIndex,aParent)));
+ nParentNodePos++;
+ }
+ if (HasParent() && !(*aParent)[nParentNodePos].HasChild())
+ aParent->Delete(nParentNodePos);
+ }
+ else if (IsRoot())
+ // make sure that the position of the root is kept
+ rIndex.SetRootPos(nPagePos);
+}
+
+
+ONDXNode ONDXPage::Split(ONDXPage& rPage)
+{
+ DBG_ASSERT(IsFull(), "Incorrect Splitting");
+ /* divide one page into two
+ leaf:
+ Page 1 is (n - (n/2))
+ Page 2 is (n/2)
+ Node n/2 will be duplicated
+ inner node:
+ Page 1 is (n+1)/2
+ Page 2 is (n/2-1)
+ Node ((n+1)/2 + 1) : will be taken out
+ */
+ ONDXNode aResultNode;
+ if (IsLeaf())
+ {
+ for (sal_uInt16 i = nCount - (nCount / 2), j = 0 ; i < nCount; i++)
+ rPage.Insert(j++,(*this)[i]);
+
+ // this node contains a key that already exists in the tree and must be replaced
+ ONDXNode aLastNode = (*this)[nCount - 1];
+ nCount = nCount - (nCount / 2);
+ aResultNode = (*this)[nCount - 1];
+
+ if (HasParent())
+ aParent->SearchAndReplace(aLastNode.GetKey(),
+ aResultNode.GetKey());
+ }
+ else
+ {
+ for (sal_uInt16 i = (nCount + 1) / 2 + 1, j = 0 ; i < nCount; i++)
+ rPage.Insert(j++,(*this)[i]);
+
+ aResultNode = (*this)[(nCount + 1) / 2];
+ nCount = (nCount + 1) / 2;
+
+ // new page points to page with extracted node
+ rPage.SetChild(aResultNode.GetChild());
+ }
+ // node points to new page
+ aResultNode.SetChild(&rPage);
+
+ // inner nodes have no record number
+ if (rIndex.isUnique())
+ aResultNode.GetKey().ResetRecord();
+ bModified = true;
+ return aResultNode;
+}
+
+
+void ONDXPage::Merge(sal_uInt16 nParentNodePos, const ONDXPagePtr& xPage)
+{
+ DBG_ASSERT(HasParent(), "no parent existing");
+ DBG_ASSERT(nParentNodePos != NODE_NOTFOUND, "Wrong index setup");
+
+ /* Merge 2 pages */
+ sal_uInt16 nMaxNodes = rIndex.GetMaxNodes(),
+ nMaxNodes_2 = nMaxNodes / 2;
+
+ // Determine if page is right or left neighbour
+ bool bRight = ((*xPage)[0].GetKey() > (*this)[0].GetKey()); // true when xPage is at the right side
+ sal_uInt16 nNewCount = (*xPage).Count() + Count();
+
+ if (IsLeaf())
+ {
+ // Condition for merge
+ if (nNewCount < (nMaxNodes_2 * 2))
+ {
+ sal_uInt16 nLastNode = bRight ? Count() - 1 : xPage->Count() - 1;
+ if (bRight)
+ {
+ DBG_ASSERT(xPage != this,"xPage and THIS must not be the same: infinite loop");
+ // shift all nodes from xPage to the left node (append)
+ while (xPage->Count())
+ {
+ Append((*xPage)[0]);
+ xPage->Remove(0);
+ }
+ }
+ else
+ {
+ DBG_ASSERT(xPage != this,"xPage and THIS must not be the same: infinite loop");
+ // xPage is the left page and THIS the right one
+ while (xPage->Count())
+ {
+ Insert(0,(*xPage)[xPage->Count()-1]);
+ xPage->Remove(xPage->Count()-1);
+ }
+ // replace old position of xPage in parent with this
+ if (nParentNodePos)
+ (*aParent)[nParentNodePos-1].SetChild(this,aParent);
+ else // or set as right node
+ aParent->SetChild(this);
+ aParent->SetModified(true);
+
+ }
+
+ // cancel Child-relationship at parent node
+ (*aParent)[nParentNodePos].SetChild();
+ // replace the Node-value, only if changed page is the left one, otherwise become
+ if(aParent->IsRoot() && aParent->Count() == 1)
+ {
+ (*aParent)[0].SetChild();
+ aParent->ReleaseFull();
+ aParent.Clear();
+ rIndex.SetRootPos(nPagePos);
+ rIndex.m_aRoot = this;
+ SetModified(true);
+ }
+ else
+ aParent->SearchAndReplace((*this)[nLastNode].GetKey(),(*this)[nCount-1].GetKey());
+
+ xPage->SetModified(false);
+ xPage->ReleaseFull(); // is not needed anymore
+ }
+ // balance the elements nNewCount >= (nMaxNodes_2 * 2)
+ else
+ {
+ if (bRight)
+ {
+ // shift all nodes from xPage to the left node (append)
+ ONDXNode aReplaceNode = (*this)[nCount - 1];
+ while (nCount < nMaxNodes_2)
+ {
+ Append((*xPage)[0]);
+ xPage->Remove(0);
+ }
+ // Replace the node values: replace old last value by the last of xPage
+ aParent->SearchAndReplace(aReplaceNode.GetKey(),(*this)[nCount-1].GetKey());
+ }
+ else
+ {
+ // insert all nodes from this in front of the xPage nodes
+ ONDXNode aReplaceNode = (*this)[nCount - 1];
+ while (xPage->Count() < nMaxNodes_2)
+ {
+ xPage->Insert(0,(*this)[nCount-1]);
+ Remove(nCount-1);
+ }
+ // Replace the node value
+ aParent->SearchAndReplace(aReplaceNode.GetKey(),(*this)[Count()-1].GetKey());
+ }
+ }
+ }
+ else // !IsLeaf()
+ {
+ // Condition for merge
+ if (nNewCount < nMaxNodes_2 * 2)
+ {
+ if (bRight)
+ {
+ DBG_ASSERT(xPage != this,"xPage and THIS must not be the same: infinite loop");
+ // Parent node will be integrated; is initialized with Child from xPage
+ (*aParent)[nParentNodePos].SetChild(xPage->GetChild(),aParent);
+ Append((*aParent)[nParentNodePos]);
+ for (sal_uInt16 i = 0 ; i < xPage->Count(); i++)
+ Append((*xPage)[i]);
+ }
+ else
+ {
+ DBG_ASSERT(xPage != this,"xPage and THIS must not be the same: infinite loop");
+ // Parent-node will be integrated; is initialized with child
+ (*aParent)[nParentNodePos].SetChild(GetChild(),aParent); // Parent memorizes my child
+ Insert(0,(*aParent)[nParentNodePos]); // insert parent node into myself
+ while (xPage->Count())
+ {
+ Insert(0,(*xPage)[xPage->Count()-1]);
+ xPage->Remove(xPage->Count()-1);
+ }
+ SetChild(xPage->GetChild());
+
+ if (nParentNodePos)
+ (*aParent)[nParentNodePos-1].SetChild(this,aParent);
+ else
+ aParent->SetChild(this);
+ }
+
+ // afterwards parent node will be reset
+ (*aParent)[nParentNodePos].SetChild();
+ aParent->SetModified(true);
+
+ if(aParent->IsRoot() && aParent->Count() == 1)
+ {
+ (*aParent).SetChild();
+ aParent->ReleaseFull();
+ aParent.Clear();
+ rIndex.SetRootPos(nPagePos);
+ rIndex.m_aRoot = this;
+ SetModified(true);
+ }
+ else if(nParentNodePos)
+ // replace the node value
+ // for Append the range will be enlarged, for Insert the old node from xPage will reference to this
+ // that's why the node must be updated here
+ aParent->SearchAndReplace((*aParent)[nParentNodePos-1].GetKey(),(*aParent)[nParentNodePos].GetKey());
+
+ xPage->SetModified(false);
+ xPage->ReleaseFull();
+ }
+ // balance the elements
+ else
+ {
+ if (bRight)
+ {
+ while (nCount < nMaxNodes_2)
+ {
+ (*aParent)[nParentNodePos].SetChild(xPage->GetChild(),aParent);
+ Append((*aParent)[nParentNodePos]);
+ (*aParent)[nParentNodePos] = (*xPage)[0];
+ xPage->Remove(0);
+ }
+ xPage->SetChild((*aParent)[nParentNodePos].GetChild());
+ (*aParent)[nParentNodePos].SetChild(xPage,aParent);
+ }
+ else
+ {
+ while (nCount < nMaxNodes_2)
+ {
+ (*aParent)[nParentNodePos].SetChild(GetChild(),aParent);
+ Insert(0,(*aParent)[nParentNodePos]);
+ (*aParent)[nParentNodePos] = (*xPage)[xPage->Count()-1];
+ xPage->Remove(xPage->Count()-1);
+ }
+ SetChild((*aParent)[nParentNodePos].GetChild());
+ (*aParent)[nParentNodePos].SetChild(this,aParent);
+
+ }
+ aParent->SetModified(true);
+ }
+ }
+}
+
+// ONDXNode
+
+
+void ONDXNode::Read(SvStream &rStream, ODbaseIndex const & rIndex)
+{
+ rStream.ReadUInt32( aKey.nRecord ); // key
+
+ if (rIndex.getHeader().db_keytype)
+ {
+ double aDbl;
+ rStream.ReadDouble( aDbl );
+ aKey = ONDXKey(aDbl,aKey.nRecord);
+ }
+ else
+ {
+ sal_uInt16 nLen = rIndex.getHeader().db_keylen;
+ OString aBuf = read_uInt8s_ToOString(rStream, nLen);
+ //get length minus trailing whitespace
+ sal_Int32 nContentLen = aBuf.getLength();
+ while (nContentLen && aBuf[nContentLen-1] == ' ')
+ --nContentLen;
+ aKey = ONDXKey(OUString(aBuf.getStr(), nContentLen, rIndex.m_pTable->getConnection()->getTextEncoding()) ,aKey.nRecord);
+ }
+ rStream >> aChild;
+}
+
+
+void ONDXNode::Write(SvStream &rStream, const ONDXPage& rPage) const
+{
+ const ODbaseIndex& rIndex = rPage.GetIndex();
+ if (!rIndex.isUnique() || rPage.IsLeaf())
+ rStream.WriteUInt32( aKey.nRecord ); // key
+ else
+ rStream.WriteUInt32( 0 ); // key
+
+ if (rIndex.getHeader().db_keytype) // double
+ {
+ if (sizeof(double) != rIndex.getHeader().db_keylen)
+ {
+ SAL_WARN("connectivity.dbase", "this key length cannot possibly be right?");
+ }
+ if (aKey.getValue().isNull())
+ {
+ sal_uInt8 buf[sizeof(double)] = {};
+ rStream.WriteBytes(&buf[0], sizeof(double));
+ }
+ else
+ rStream.WriteDouble( aKey.getValue().getDouble() );
+ }
+ else
+ {
+ sal_uInt16 const nLen(rIndex.getHeader().db_keylen);
+ std::unique_ptr<sal_uInt8[]> pBuf(new sal_uInt8[nLen]);
+ memset(&pBuf[0], 0x20, nLen);
+ if (!aKey.getValue().isNull())
+ {
+ OUString sValue = aKey.getValue().getString();
+ OString aText(OUStringToOString(sValue, rIndex.m_pTable->getConnection()->getTextEncoding()));
+ strncpy(reinterpret_cast<char *>(&pBuf[0]), aText.getStr(),
+ std::min<size_t>(nLen, aText.getLength()));
+ }
+ rStream.WriteBytes(&pBuf[0], nLen);
+ }
+ WriteONDXPagePtr( rStream, aChild );
+}
+
+
+ONDXPagePtr& ONDXNode::GetChild(ODbaseIndex* pIndex, ONDXPage* pParent)
+{
+ if (!aChild.Is() && pIndex)
+ {
+ aChild = pIndex->CreatePage(aChild.GetPagePos(),pParent,aChild.HasPage());
+ }
+ return aChild;
+}
+
+
+// ONDXKey
+
+
+bool ONDXKey::IsText(sal_Int32 eType)
+{
+ return eType == DataType::VARCHAR || eType == DataType::CHAR;
+}
+
+
+int ONDXKey::Compare(const ONDXKey& rKey) const
+{
+ sal_Int32 nRes;
+
+ if (getValue().isNull())
+ {
+ if (rKey.getValue().isNull() || (IsText(getDBType()) && rKey.getValue().getString().isEmpty()))
+ nRes = 0;
+ else
+ nRes = -1;
+ }
+ else if (rKey.getValue().isNull())
+ {
+ if (getValue().isNull() || (IsText(getDBType()) && getValue().getString().isEmpty()))
+ nRes = 0;
+ else
+ nRes = 1;
+ }
+ else if (IsText(getDBType()))
+ {
+ nRes = getValue().getString().compareTo(rKey.getValue().getString());
+ }
+ else
+ {
+ double m = getValue().getDouble();
+ double n = rKey.getValue().getDouble();
+ nRes = (m > n) ? 1 : ( m < n) ? -1 : 0;
+ }
+
+ // compare record, if index !Unique
+ if (nRes == 0 && nRecord && rKey.nRecord)
+ {
+ nRes = (nRecord > rKey.nRecord) ? 1 :
+ (nRecord == rKey.nRecord) ? 0 : -1;
+ }
+ return nRes;
+}
+
+void ONDXKey::setValue(const ORowSetValue& _rVal)
+{
+ xValue = _rVal;
+}
+
+const ORowSetValue& ONDXKey::getValue() const
+{
+ return xValue;
+}
+
+SvStream& connectivity::dbase::operator >> (SvStream &rStream, ONDXPagePtr& rPage)
+{
+ rStream.ReadUInt32( rPage.nPagePos );
+ return rStream;
+}
+
+SvStream& connectivity::dbase::WriteONDXPagePtr(SvStream &rStream, const ONDXPagePtr& rPage)
+{
+ rStream.WriteUInt32( rPage.nPagePos );
+ return rStream;
+}
+
+// ONDXPagePtr
+ONDXPagePtr::ONDXPagePtr()
+ : mpPage(nullptr)
+ , nPagePos(0)
+{
+}
+
+ONDXPagePtr::ONDXPagePtr(ONDXPagePtr&& rRef) noexcept
+{
+ mpPage = rRef.mpPage;
+ rRef.mpPage = nullptr;
+ nPagePos = rRef.nPagePos;
+}
+
+ONDXPagePtr::ONDXPagePtr(ONDXPagePtr const & rRef)
+ : mpPage(rRef.mpPage)
+ , nPagePos(rRef.nPagePos)
+{
+ if (mpPage != nullptr)
+ mpPage->AddNextRef();
+}
+
+ONDXPagePtr::ONDXPagePtr(ONDXPage* pRefPage)
+ : mpPage(pRefPage)
+ , nPagePos(0)
+{
+ if (mpPage != nullptr)
+ mpPage->AddFirstRef();
+ if (pRefPage)
+ nPagePos = pRefPage->GetPagePos();
+}
+
+ONDXPagePtr::~ONDXPagePtr()
+{
+ if (mpPage != nullptr) mpPage->ReleaseRef();
+}
+
+void ONDXPagePtr::Clear()
+{
+ if (mpPage != nullptr) {
+ ONDXPage * pRefObj = mpPage;
+ mpPage = nullptr;
+ pRefObj->ReleaseRef();
+ }
+}
+
+ONDXPagePtr& ONDXPagePtr::operator=(ONDXPagePtr const & rOther)
+{
+ ONDXPagePtr aTemp(rOther);
+ *this = std::move(aTemp);
+ return *this;
+}
+
+ONDXPagePtr& ONDXPagePtr::operator=(ONDXPagePtr && rOther)
+{
+ if (mpPage != nullptr) {
+ mpPage->ReleaseRef();
+ }
+ mpPage = rOther.mpPage;
+ nPagePos = rOther.nPagePos;
+ rOther.mpPage = nullptr;
+ return *this;
+}
+
+static sal_uInt32 nValue;
+
+SvStream& connectivity::dbase::operator >> (SvStream &rStream, ONDXPage& rPage)
+{
+ rStream.Seek(rPage.GetPagePos() * DINDEX_PAGE_SIZE);
+ rStream.ReadUInt32( nValue ) >> rPage.aChild;
+ rPage.nCount = sal_uInt16(nValue);
+
+ for (sal_uInt16 i = 0; i < rPage.nCount; i++)
+ rPage[i].Read(rStream, rPage.GetIndex());
+ return rStream;
+}
+
+
+SvStream& connectivity::dbase::WriteONDXPage(SvStream &rStream, const ONDXPage& rPage)
+{
+ // Page doesn't exist yet
+ std::size_t nSize = rPage.GetPagePos() + 1;
+ nSize *= DINDEX_PAGE_SIZE;
+ if (nSize > rStream.TellEnd())
+ {
+ rStream.SetStreamSize(nSize);
+ rStream.Seek(rPage.GetPagePos() * DINDEX_PAGE_SIZE);
+
+ char aEmptyData[DINDEX_PAGE_SIZE] = {};
+ rStream.WriteBytes(aEmptyData, DINDEX_PAGE_SIZE);
+ }
+ rStream.Seek(rPage.GetPagePos() * DINDEX_PAGE_SIZE);
+
+ nValue = rPage.nCount;
+ rStream.WriteUInt32( nValue );
+ WriteONDXPagePtr( rStream, rPage.aChild );
+
+ sal_uInt16 i = 0;
+ for (; i < rPage.nCount; i++)
+ rPage[i].Write(rStream, rPage);
+
+ // check if we have to fill the stream with '\0'
+ if(i < rPage.rIndex.getHeader().db_maxkeys)
+ {
+ std::size_t nTell = rStream.Tell() % DINDEX_PAGE_SIZE;
+ sal_uInt16 nBufferSize = rStream.GetBufferSize();
+ std::size_t nRemainSize = nBufferSize - nTell;
+ if ( nRemainSize <= nBufferSize )
+ {
+ std::unique_ptr<char[]> pEmptyData( new char[nRemainSize] );
+ memset(pEmptyData.get(), 0x00, nRemainSize);
+ rStream.WriteBytes(pEmptyData.get(), nRemainSize);
+ rStream.Seek(nTell);
+ }
+ }
+ return rStream;
+}
+
+#if OSL_DEBUG_LEVEL > 1
+
+void ONDXPage::PrintPage()
+{
+ SAL_WARN("connectivity.dbase", "SDB: -----------Page: " << nPagePos << " Parent: " << (HasParent() ? aParent->GetPagePos() : 0)
+ << " Count: " << nCount << " Child: " << aChild.GetPagePos() << "-----");
+
+ for (sal_uInt16 i = 0; i < nCount; i++)
+ {
+ ONDXNode rNode = (*this)[i];
+ ONDXKey& rKey = rNode.GetKey();
+ if (!IsLeaf())
+ rNode.GetChild(&rIndex, this);
+
+ if (rKey.getValue().isNull())
+ {
+ SAL_WARN("connectivity.dbase", "SDB: [" << rKey.GetRecord() << ",NULL," << rNode.GetChild().GetPagePos() << "]");
+ }
+ else if (rIndex.getHeader().db_keytype)
+ {
+ SAL_WARN("connectivity.dbase", "SDB: [" << rKey.GetRecord() << "," << rKey.getValue().getDouble()
+ << "," << rNode.GetChild().GetPagePos() << "]");
+ }
+ else
+ {
+ SAL_WARN("connectivity.dbase", "SDB: [" << rKey.GetRecord() << "," << rKey.getValue().getString()
+ << "," << rNode.GetChild().GetPagePos() << "]" );
+ }
+ }
+ SAL_WARN("connectivity.dbase", "SDB: -----------------------------------------------");
+ if (!IsLeaf())
+ {
+#if OSL_DEBUG_LEVEL > 1
+ GetChild(&rIndex)->PrintPage();
+ for (sal_uInt16 i = 0; i < nCount; i++)
+ {
+ ONDXNode rNode = (*this)[i];
+ rNode.GetChild(&rIndex,this)->PrintPage();
+ }
+#endif
+ }
+ SAL_WARN("connectivity.dbase", "SDB: ===============================================");
+}
+#endif
+
+bool ONDXPage::IsFull() const
+{
+ return Count() == rIndex.getHeader().db_maxkeys;
+}
+
+
+sal_uInt16 ONDXPage::Search(const ONDXKey& rSearch)
+{
+ // binary search later
+ sal_uInt16 i = NODE_NOTFOUND;
+ while (++i < Count())
+ if ((*this)[i].GetKey() == rSearch)
+ break;
+
+ return (i < Count()) ? i : NODE_NOTFOUND;
+}
+
+
+sal_uInt16 ONDXPage::Search(const ONDXPage* pPage)
+{
+ sal_uInt16 i = NODE_NOTFOUND;
+ while (++i < Count())
+ if (((*this)[i]).GetChild() == pPage)
+ break;
+
+ // if not found, then we assume, that the page itself points to the page
+ return (i < Count()) ? i : NODE_NOTFOUND;
+}
+
+// runs recursively
+void ONDXPage::SearchAndReplace(const ONDXKey& rSearch,
+ ONDXKey const & rReplace)
+{
+ OSL_ENSURE(rSearch != rReplace,"Invalid here:rSearch == rReplace");
+ if (rSearch == rReplace)
+ return;
+
+ sal_uInt16 nPos = NODE_NOTFOUND;
+ ONDXPage* pPage = this;
+
+ while (pPage)
+ {
+ nPos = pPage->Search(rSearch);
+ if (nPos != NODE_NOTFOUND)
+ break;
+ pPage = pPage->aParent;
+ }
+
+ if (pPage)
+ {
+ (*pPage)[nPos].GetKey() = rReplace;
+ pPage->SetModified(true);
+ }
+}
+
+ONDXNode& ONDXPage::operator[] (sal_uInt16 nPos)
+{
+ DBG_ASSERT(nCount > nPos, "incorrect index access");
+ return ppNodes[nPos];
+}
+
+
+const ONDXNode& ONDXPage::operator[] (sal_uInt16 nPos) const
+{
+ DBG_ASSERT(nCount > nPos, "incorrect index access");
+ return ppNodes[nPos];
+}
+
+void ONDXPage::Remove(sal_uInt16 nPos)
+{
+ DBG_ASSERT(nCount > nPos, "incorrect index access");
+
+ for (sal_uInt16 i = nPos; i < (nCount-1); i++)
+ (*this)[i] = (*this)[i+1];
+
+ nCount--;
+ bModified = true;
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/evoab2/EApi.cxx b/connectivity/source/drivers/evoab2/EApi.cxx
new file mode 100644
index 0000000000..9ec8e0d44e
--- /dev/null
+++ b/connectivity/source/drivers/evoab2/EApi.cxx
@@ -0,0 +1,135 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#include <rtl/ustring.hxx>
+#include <osl/module.hxx>
+#define DECLARE_FN_POINTERS 1
+#include "EApi.h"
+static const char *eBookLibNames[] = {
+ "libebook-1.2.so.21", // evolution-data-server 3.45.2+
+ "libebook-1.2.so.20", // evolution-data-server 3.33.2+
+ "libebook-1.2.so.19", // evolution-data-server 3.24+
+ "libebook-1.2.so.16"
+};
+
+typedef void (*SymbolFunc) ();
+
+namespace {
+
+struct ApiMap
+{
+ const char *sym_name;
+ SymbolFunc *ref_value;
+};
+
+}
+
+const ApiMap aCommonApiMap[] =
+{
+ { "eds_check_version", reinterpret_cast<SymbolFunc *>(&eds_check_version) },
+ { "e_contact_field_name", reinterpret_cast<SymbolFunc *>(&e_contact_field_name) },
+ { "e_contact_get", reinterpret_cast<SymbolFunc *>(&e_contact_get) },
+ { "e_contact_get_type", reinterpret_cast<SymbolFunc *>(&e_contact_get_type) },
+ { "e_contact_field_id", reinterpret_cast<SymbolFunc *>(&e_contact_field_id) },
+ { "e_book_new", reinterpret_cast<SymbolFunc *>(&e_book_new) },
+ { "e_book_open", reinterpret_cast<SymbolFunc *>(&e_book_open) },
+ { "e_book_get_source", reinterpret_cast<SymbolFunc *>(&e_book_get_source) },
+ { "e_book_get_contacts", reinterpret_cast<SymbolFunc *>(&e_book_get_contacts) },
+ { "e_book_query_field_test", reinterpret_cast<SymbolFunc *>(&e_book_query_field_test) },
+ { "e_book_query_and", reinterpret_cast<SymbolFunc *>(&e_book_query_and) },
+ { "e_book_query_or", reinterpret_cast<SymbolFunc *>(&e_book_query_or) },
+ { "e_book_query_not", reinterpret_cast<SymbolFunc *>(&e_book_query_not) },
+ { "e_book_query_ref", reinterpret_cast<SymbolFunc *>(&e_book_query_ref) },
+ { "e_book_query_unref", reinterpret_cast<SymbolFunc *>(&e_book_query_unref) },
+ { "e_book_query_from_string", reinterpret_cast<SymbolFunc *>(&e_book_query_from_string) },
+ { "e_book_query_to_string", reinterpret_cast<SymbolFunc *>(&e_book_query_to_string) },
+ { "e_book_query_field_exists", reinterpret_cast<SymbolFunc *>(&e_book_query_field_exists) }
+};
+
+const ApiMap aNewApiMap[] =
+{
+ { "e_source_registry_list_sources", reinterpret_cast<SymbolFunc *>(&e_source_registry_list_sources) },
+ { "e_source_registry_new_sync", reinterpret_cast<SymbolFunc *>(&e_source_registry_new_sync) },
+ { "e_source_has_extension", reinterpret_cast<SymbolFunc *>(&e_source_has_extension) },
+ { "e_source_get_extension", reinterpret_cast<SymbolFunc *>(&e_source_get_extension) },
+ { "e_source_backend_get_backend_name", reinterpret_cast<SymbolFunc *>(&e_source_backend_get_backend_name) },
+ { "e_source_get_display_name", reinterpret_cast<SymbolFunc *>(&e_source_get_display_name) },
+ { "e_source_get_uid", reinterpret_cast<SymbolFunc *>(&e_source_get_uid) },
+ { "e_source_registry_ref_source", reinterpret_cast<SymbolFunc *>(&e_source_registry_ref_source) },
+ { "e_client_open_sync", reinterpret_cast<SymbolFunc *>(&e_client_open_sync) },
+ { "e_client_get_source", reinterpret_cast<SymbolFunc *>(&e_client_get_source) },
+ { "e_book_client_get_contacts_sync", reinterpret_cast<SymbolFunc *>(&e_book_client_get_contacts_sync) },
+ { "e_client_util_free_object_slist", reinterpret_cast<SymbolFunc *>(&e_client_util_free_object_slist) }
+};
+
+//>= direct read access API (>= 3.8)
+const ApiMap aClientApiMap38[] =
+{
+ { "e_book_client_connect_direct_sync", reinterpret_cast<SymbolFunc *>(&e_book_client_connect_direct_sync) }
+};
+
+template<size_t N> static bool
+tryLink( osl::Module &rModule, const char *pName, const ApiMap (&pMap)[N])
+{
+ for (size_t i = 0; i < N; ++i)
+ {
+ SymbolFunc aMethod = reinterpret_cast<SymbolFunc>(
+ rModule.getFunctionSymbol(OUString::createFromAscii(pMap[i].sym_name)));
+ if( !aMethod )
+ {
+ fprintf( stderr, "Warning: missing symbol '%s' in '%s'\n",
+ pMap[ i ].sym_name, pName );
+ return false;
+ }
+ *pMap[ i ].ref_value = aMethod;
+ }
+ return true;
+}
+
+bool EApiInit()
+{
+ for( guint j = 0; j < G_N_ELEMENTS( eBookLibNames ); j++ )
+ {
+ osl::Module aModule(OUString::createFromAscii(eBookLibNames[j]), SAL_LOADMODULE_DEFAULT);
+
+ if (!aModule.is())
+ continue;
+
+ if (tryLink( aModule, eBookLibNames[ j ], aCommonApiMap))
+ {
+ if (tryLink( aModule, eBookLibNames[ j ], aNewApiMap))
+ {
+ if (tryLink( aModule, eBookLibNames[ j ], aClientApiMap38))
+ {
+ aModule.release();
+ return true;
+ }
+ }
+ }
+ }
+ fprintf( stderr, "Can find no compliant libebook client libraries\n" );
+ return false;
+}
+
+ESourceRegistry *get_e_source_registry()
+{
+ static ESourceRegistry *theInstance = e_source_registry_new_sync(nullptr, nullptr);
+ return theInstance;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/evoab2/EApi.h b/connectivity/source/drivers/evoab2/EApi.h
new file mode 100644
index 0000000000..9a2138eb2a
--- /dev/null
+++ b/connectivity/source/drivers/evoab2/EApi.h
@@ -0,0 +1,160 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+#include <glib-object.h>
+
+// Initializes the API below, returns false if not available
+bool EApiInit();
+
+G_BEGIN_DECLS
+
+// This header defined all the API methods as
+// function pointers instead of real functions
+// this will all evaporate as it is compiled generating
+// no symbol lookups or relocations, but giving code
+// clarity.
+
+// We attempt to define a minimum API that we use:
+
+// e-contact.h
+#ifdef DECLARE_FN_POINTERS
+#define EAPI_EXTERN
+#else
+#define EAPI_EXTERN extern
+#endif
+
+
+typedef void EContact;
+#define E_CONTACT(a) ((EContact *)(a))
+#define E_TYPE_CONTACT (e_contact_get_type())
+typedef int EContactField;
+
+EAPI_EXTERN const char *(*e_contact_field_name) ( EContactField field_id);
+EAPI_EXTERN gpointer (*e_contact_get) (EContact *contact, EContactField field_id);
+EAPI_EXTERN gconstpointer (*e_contact_get_const) (EContact *contact, EContactField field_id);
+// e-source.h
+typedef void ESource;
+#define E_SOURCE(a) ((ESource *)(a))
+EAPI_EXTERN const char *(*e_source_peek_name) (ESource *source);
+EAPI_EXTERN const gchar *(*e_source_get_property) (ESource *source,
+ const gchar *property);
+
+EAPI_EXTERN GType (*e_contact_get_type) (void);
+EAPI_EXTERN EContactField (*e_contact_field_id) (const char *field_name);
+
+// e-source-list.h
+typedef void ESourceList;
+EAPI_EXTERN GSList *(*e_source_list_peek_groups) (ESourceList *list);
+
+// e-source-group.h
+typedef void ESourceGroup;
+#define E_SOURCE_GROUP(a) ((ESourceGroup *)(a))
+
+EAPI_EXTERN GSList *(*e_source_group_peek_sources) (ESourceGroup *group);
+EAPI_EXTERN const char *(*e_source_group_peek_base_uri) (ESourceGroup *group);
+// e-book.h
+typedef enum {
+ E_BOOK_QUERY_IS,
+ E_BOOK_QUERY_CONTAINS,
+ E_BOOK_QUERY_BEGINS_WITH,
+ E_BOOK_QUERY_ENDS_WITH,
+} EBookQueryTest;
+
+typedef void EBook;
+typedef void EBookQuery;
+
+EAPI_EXTERN EBook *(*e_book_new) (ESource *source,
+ GError **error);
+
+EAPI_EXTERN gboolean (*e_book_open) (EBook *book,
+ gboolean only_if_exists,
+ GError **error);
+
+EAPI_EXTERN const char *(*e_book_get_uri) (EBook *book);
+EAPI_EXTERN ESource *(*e_book_get_source)(EBook *book);
+
+EAPI_EXTERN gboolean (*e_book_get_addressbooks) (ESourceList **addressbook_sources,
+ GError **error);
+
+EAPI_EXTERN gboolean (*e_book_get_contacts) (EBook *book,
+ EBookQuery *query,
+ GList **contacts,
+ GError **error);
+
+EAPI_EXTERN gboolean (*e_book_authenticate_user) (EBook *book,
+ const char *user,
+ const char *passwd,
+ const char *auth_method,
+ GError **error);
+
+// e-book-query.h
+EAPI_EXTERN EBookQuery* (*e_book_query_field_exists) (EContactField field);
+EAPI_EXTERN EBookQuery* (*e_book_query_field_test) (EContactField field,
+ EBookQueryTest test,
+ const char *value);
+EAPI_EXTERN EBookQuery* (*e_book_query_and) (int nqs, EBookQuery **qs, gboolean unref);
+EAPI_EXTERN EBookQuery* (*e_book_query_or) (int nqs, EBookQuery **qs, gboolean unref);
+EAPI_EXTERN EBookQuery* (*e_book_query_not) (EBookQuery *q, gboolean unref);
+EAPI_EXTERN EBookQuery* (*e_book_query_ref) (EBookQuery *q);
+EAPI_EXTERN void (*e_book_query_unref) (EBookQuery *q);
+EAPI_EXTERN char* (*e_book_query_to_string) (EBookQuery *q);
+EAPI_EXTERN EBookQuery* (*e_book_query_from_string) (const char *query_string);
+
+typedef struct {
+ char *address_format; /* the two letter country code that
+ determines the format/meaning of the
+ following fields */
+ char *po;
+ char *ext;
+ char *street;
+ char *locality;
+ char *region;
+ char *code;
+ char *country;
+} EContactAddress;
+
+#define E_SOURCE_EXTENSION_ADDRESS_BOOK "Address Book"
+typedef void ESourceRegistry;
+typedef void GCancellable;
+typedef void ESourceBackend;
+typedef void EClient;
+typedef EClient EBookClient;
+EAPI_EXTERN ESourceRegistry* (*e_source_registry_new_sync) (GCancellable *cancellable, GError **error);
+EAPI_EXTERN GList* (*e_source_registry_list_sources) (ESourceRegistry *registry, const gchar *extension_name);
+EAPI_EXTERN gboolean (*e_source_has_extension) (ESource *source, const gchar *extension_name);
+EAPI_EXTERN gpointer (*e_source_get_extension) (ESource *source, const gchar *extension_name);
+EAPI_EXTERN const gchar* (*e_source_backend_get_backend_name) (ESourceBackend *extension);
+EAPI_EXTERN const gchar* (*e_source_get_display_name) (ESource *source);
+EAPI_EXTERN const gchar* (*eds_check_version) (guint required_major, guint required_minor, guint required_micro);
+EAPI_EXTERN const gchar* (*e_source_get_uid) (ESource *source);
+EAPI_EXTERN ESource* (*e_source_registry_ref_source) (ESourceRegistry *registry, const gchar *uid);
+EAPI_EXTERN EBookClient* (*e_book_client_new) (ESource *source, GError **error);
+EAPI_EXTERN EBookClient* (*e_book_client_connect_direct_sync) (ESourceRegistry *registry, ESource *source, guint32 wait_for_connected_seconds, GCancellable *cancellable, GError **error);
+EAPI_EXTERN gboolean (*e_client_open_sync) (EClient *client, gboolean only_if_exists, GCancellable *cancellable, GError **error);
+EAPI_EXTERN ESource* (*e_client_get_source) (EClient *client);
+EAPI_EXTERN gboolean (*e_book_client_get_contacts_sync) (EBookClient *client, const gchar *sexp, GSList **contacts, GCancellable *cancellable, GError **error);
+EAPI_EXTERN void (*e_client_util_free_object_slist) (GSList *objects);
+
+ESourceRegistry *get_e_source_registry();
+bool isSourceBackend(ESource *pSource, const char *backendname);
+
+G_END_DECLS
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/evoab2/NCatalog.cxx b/connectivity/source/drivers/evoab2/NCatalog.cxx
new file mode 100644
index 0000000000..6b409ce66d
--- /dev/null
+++ b/connectivity/source/drivers/evoab2/NCatalog.cxx
@@ -0,0 +1,86 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "NCatalog.hxx"
+#include "NConnection.hxx"
+#include "NTables.hxx"
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XResultSet.hpp>
+
+
+using namespace connectivity::evoab;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+
+OEvoabCatalog::OEvoabCatalog(OEvoabConnection* _pCon) :
+ connectivity::sdbcx::OCatalog(_pCon)
+ ,m_pConnection(_pCon)
+{
+}
+void OEvoabCatalog::refreshTables()
+{
+ ::std::vector< OUString> aVector;
+ Sequence< OUString > aTypes { "TABLE" };
+ Reference< XResultSet > xResult = m_xMetaData->getTables(
+ Any(), "%", "%", aTypes);
+
+ if(xResult.is())
+ {
+ Reference< XRow > xRow(xResult,UNO_QUERY);
+ OUString aName;
+
+ while(xResult->next())
+ {
+ aName = xRow->getString(3);
+ aVector.push_back(aName);
+ }
+ }
+ if(m_pTables)
+ m_pTables->reFill(aVector);
+ else
+ m_pTables.reset( new OEvoabTables(m_xMetaData,*this,m_aMutex,aVector) );
+}
+// XTablesSupplier
+Reference< XNameAccess > SAL_CALL OEvoabCatalog::getTables( )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+
+ try
+ {
+ if (!m_pTables)
+ refreshTables();
+ }
+ catch( const RuntimeException& )
+ {
+ // allowed to leave this method
+ throw;
+ }
+ catch( const Exception& )
+ {
+ // allowed
+ }
+
+ return m_pTables.get();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/evoab2/NCatalog.hxx b/connectivity/source/drivers/evoab2/NCatalog.hxx
new file mode 100644
index 0000000000..b2bd808447
--- /dev/null
+++ b/connectivity/source/drivers/evoab2/NCatalog.hxx
@@ -0,0 +1,43 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sdbcx/VCatalog.hxx>
+
+namespace connectivity::evoab
+{
+ class OEvoabConnection;
+ class OEvoabCatalog : public connectivity::sdbcx::OCatalog
+ {
+ OEvoabConnection *m_pConnection;
+ public:
+ explicit OEvoabCatalog(OEvoabConnection *_pCon);
+ OEvoabConnection* getConnection() const { return m_pConnection; }
+ virtual void refreshTables() override;
+ virtual void refreshViews() override {}
+ virtual void refreshGroups() override {}
+ virtual void refreshUsers() override {}
+ // XTablesSupplier
+ virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getTables(
+ ) override;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/evoab2/NColumns.cxx b/connectivity/source/drivers/evoab2/NColumns.cxx
new file mode 100644
index 0000000000..5b2b64d5d5
--- /dev/null
+++ b/connectivity/source/drivers/evoab2/NColumns.cxx
@@ -0,0 +1,87 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include "NColumns.hxx"
+#include "NTable.hxx"
+#include <connectivity/sdbcx/VColumn.hxx>
+#include <com/sun/star/sdbc/XRow.hpp>
+
+using namespace connectivity::sdbcx;
+using namespace connectivity;
+using namespace ::comphelper;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+using namespace connectivity::evoab;
+
+
+sdbcx::ObjectType OEvoabColumns::createObject(const OUString& _rName)
+{
+ const Any aCatalog;
+ const OUString sCatalogName;
+ const OUString sSchemaName(m_pTable->getSchema());
+ const OUString sTableName(m_pTable->getTableName());
+ Reference< XResultSet > xResult = m_pTable->getConnection()->getMetaData()->getColumns(
+ aCatalog,
+ sSchemaName,
+ sTableName,
+ _rName);
+
+ sdbcx::ObjectType xRet;
+ if (xResult.is())
+ {
+ Reference< XRow > xRow(xResult,UNO_QUERY);
+
+ while (xResult->next())
+ {
+ if (xRow->getString(4) == _rName)
+ {
+ xRet = new OColumn(
+ _rName,
+ xRow->getString(6),
+ xRow->getString(13),
+ xRow->getString(12),
+ xRow->getInt(11),
+ xRow->getInt(7),
+ xRow->getInt(9),
+ xRow->getInt(5),
+ false,
+ false,
+ false,
+ true,
+ sCatalogName,
+ sSchemaName,
+ sTableName);
+ break;
+ }
+ }
+ }
+
+ return xRet;
+}
+
+void OEvoabColumns::impl_refresh()
+{
+ m_pTable->refreshColumns();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/evoab2/NColumns.hxx b/connectivity/source/drivers/evoab2/NColumns.hxx
new file mode 100644
index 0000000000..f768c51bb0
--- /dev/null
+++ b/connectivity/source/drivers/evoab2/NColumns.hxx
@@ -0,0 +1,44 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "NTable.hxx"
+#include <connectivity/sdbcx/VCollection.hxx>
+
+namespace connectivity::evoab
+{
+ class OEvoabColumns final : public sdbcx::OCollection
+ {
+ OEvoabTable* m_pTable;
+
+ virtual sdbcx::ObjectType createObject(const OUString& _rName) override;
+ virtual void impl_refresh() override;
+
+ public:
+ OEvoabColumns( OEvoabTable* _pTable,
+ ::osl::Mutex& _rMutex,
+ const ::std::vector< OUString> &_rVector
+ ) : sdbcx::OCollection(*_pTable,true,_rMutex,_rVector),
+ m_pTable(_pTable)
+ { }
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/evoab2/NConnection.cxx b/connectivity/source/drivers/evoab2/NConnection.cxx
new file mode 100644
index 0000000000..02e8d476dd
--- /dev/null
+++ b/connectivity/source/drivers/evoab2/NConnection.cxx
@@ -0,0 +1,242 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "NConnection.hxx"
+#include "NDatabaseMetaData.hxx"
+#include "NCatalog.hxx"
+#include <com/sun/star/sdbc/TransactionIsolation.hpp>
+#include "NPreparedStatement.hxx"
+#include "NStatement.hxx"
+#include <connectivity/dbexception.hxx>
+#include <rtl/ref.hxx>
+#include <rtl/ustring.hxx>
+#include <sal/log.hxx>
+
+using namespace connectivity::evoab;
+using namespace dbtools;
+
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::lang;
+
+OEvoabConnection::OEvoabConnection(OEvoabDriver const & _rDriver)
+ : m_rDriver(_rDriver)
+ , m_eSDBCAddressType(SDBCAddress::EVO_LOCAL)
+{
+}
+
+OEvoabConnection::~OEvoabConnection()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ if(!isClosed()) {
+ acquire();
+ close();
+ }
+}
+
+
+// XServiceInfo
+
+IMPLEMENT_SERVICE_INFO(OEvoabConnection, "com.sun.star.sdbc.drivers.evoab.Connection", "com.sun.star.sdbc.Connection")
+
+
+void OEvoabConnection::construct(const OUString& url, const Sequence< PropertyValue >& info)
+{
+ osl_atomic_increment( &m_refCount );
+ SAL_INFO("connectivity.evoab2", "OEvoabConnection::construct()::url = " << url );
+
+ OUString sPassword;
+ const char pPwd[] = "password";
+
+ const PropertyValue *pIter = info.getConstArray();
+ const PropertyValue *pEnd = pIter + info.getLength();
+ for(;pIter != pEnd;++pIter)
+ {
+ if(pIter->Name == pPwd)
+ {
+ pIter->Value >>= sPassword;
+ break;
+ }
+ }
+
+ if ( url == "sdbc:address:evolution:groupwise" )
+ setSDBCAddressType(SDBCAddress::EVO_GWISE);
+ else if ( url == "sdbc:address:evolution:ldap" )
+ setSDBCAddressType(SDBCAddress::EVO_LDAP);
+ else
+ setSDBCAddressType(SDBCAddress::EVO_LOCAL);
+ setURL(url);
+ setPassword(OUStringToOString(sPassword,RTL_TEXTENCODING_UTF8));
+ osl_atomic_decrement( &m_refCount );
+}
+
+
+OUString SAL_CALL OEvoabConnection::nativeSQL( const OUString& _sSql )
+{
+ // when you need to transform SQL92 to you driver specific you can do it here
+ return _sSql;
+}
+
+Reference< XDatabaseMetaData > SAL_CALL OEvoabConnection::getMetaData( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OConnection_BASE::rBHelper.bDisposed);
+
+ Reference< XDatabaseMetaData > xMetaData = m_xMetaData;
+ if(!xMetaData.is())
+ {
+ xMetaData = new OEvoabDatabaseMetaData(this);
+ m_xMetaData = xMetaData;
+ }
+
+ return xMetaData;
+}
+
+css::uno::Reference< XTablesSupplier > OEvoabConnection::createCatalog()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ Reference< XTablesSupplier > xTab = m_xCatalog;
+ if(!xTab.is())
+ {
+ xTab = new OEvoabCatalog(this);
+ m_xCatalog = xTab;
+ }
+ return xTab;
+}
+
+Reference< XStatement > SAL_CALL OEvoabConnection::createStatement( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OConnection_BASE::rBHelper.bDisposed);
+
+ Reference< XStatement > xStmt = new OStatement(this);
+ m_aStatements.push_back(WeakReferenceHelper(xStmt));
+ return xStmt;
+}
+
+Reference< XPreparedStatement > SAL_CALL OEvoabConnection::prepareStatement( const OUString& sql )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OConnection_BASE::rBHelper.bDisposed);
+
+ rtl::Reference<OEvoabPreparedStatement> pStmt = new OEvoabPreparedStatement( this );
+ pStmt->construct( sql );
+
+ m_aStatements.push_back(WeakReferenceHelper(*pStmt));
+ return pStmt;
+}
+
+Reference< XPreparedStatement > SAL_CALL OEvoabConnection::prepareCall( const OUString& /*sql*/ )
+{
+ ::dbtools::throwFeatureNotImplementedSQLException( "XConnection::prepareCall", *this );
+ return nullptr;
+}
+sal_Bool SAL_CALL OEvoabConnection::isClosed( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ return OConnection_BASE::rBHelper.bDisposed;
+}
+
+
+// XCloseable
+void SAL_CALL OEvoabConnection::close( )
+{
+ { // we just dispose us
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OConnection_BASE::rBHelper.bDisposed);
+ }
+ dispose();
+}
+
+
+// XWarningsSupplier
+Any SAL_CALL OEvoabConnection::getWarnings( )
+{
+ return m_aWarnings.getWarnings();
+}
+void SAL_CALL OEvoabConnection::clearWarnings( )
+{
+ m_aWarnings.clearWarnings();
+}
+
+
+void OEvoabConnection::disposing()
+{
+ // we noticed that we should be destroyed in near future so we have to dispose our statements
+ ::osl::MutexGuard aGuard(m_aMutex);
+ OConnection_BASE::disposing();
+}
+
+// -------------------------------- stubbed methods ------------------------------------------------
+void SAL_CALL OEvoabConnection::setAutoCommit( sal_Bool /*autoCommit*/ )
+{
+ ::dbtools::throwFeatureNotImplementedSQLException( "XConnection::setAutoCommit", *this );
+}
+sal_Bool SAL_CALL OEvoabConnection::getAutoCommit( )
+{
+ return true;
+}
+void SAL_CALL OEvoabConnection::commit( )
+{
+}
+void SAL_CALL OEvoabConnection::rollback( )
+{
+}
+void SAL_CALL OEvoabConnection::setReadOnly( sal_Bool /*readOnly*/ )
+{
+ ::dbtools::throwFeatureNotImplementedSQLException( "XConnection::setReadOnly", *this );
+}
+sal_Bool SAL_CALL OEvoabConnection::isReadOnly( )
+{
+ return false;
+}
+void SAL_CALL OEvoabConnection::setCatalog( const OUString& /*catalog*/ )
+{
+ ::dbtools::throwFeatureNotImplementedSQLException( "XConnection::setCatalog", *this );
+}
+
+OUString SAL_CALL OEvoabConnection::getCatalog( )
+{
+ return OUString();
+}
+void SAL_CALL OEvoabConnection::setTransactionIsolation( sal_Int32 /*level*/ )
+{
+ ::dbtools::throwFeatureNotImplementedSQLException( "XConnection::setTransactionIsolation", *this );
+}
+
+sal_Int32 SAL_CALL OEvoabConnection::getTransactionIsolation( )
+{
+ return TransactionIsolation::NONE;
+}
+
+Reference< css::container::XNameAccess > SAL_CALL OEvoabConnection::getTypeMap( )
+{
+ ::dbtools::throwFeatureNotImplementedSQLException( "XConnection::getTypeMap", *this );
+ return nullptr;
+}
+void SAL_CALL OEvoabConnection::setTypeMap( const Reference< css::container::XNameAccess >& /*typeMap*/ )
+{
+ ::dbtools::throwFeatureNotImplementedSQLException( "XConnection::setTypeMap", *this );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/evoab2/NConnection.hxx b/connectivity/source/drivers/evoab2/NConnection.hxx
new file mode 100644
index 0000000000..8dd8714bc2
--- /dev/null
+++ b/connectivity/source/drivers/evoab2/NConnection.hxx
@@ -0,0 +1,105 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "NDriver.hxx"
+#include <com/sun/star/sdbc/SQLWarning.hpp>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/sdbcx/XTablesSupplier.hpp>
+#include <connectivity/CommonTools.hxx>
+#include <connectivity/warningscontainer.hxx>
+#include <TConnection.hxx>
+#include <cppuhelper/weakref.hxx>
+#include <osl/module.h>
+#include "EApi.h"
+
+namespace connectivity::evoab {
+
+ namespace SDBCAddress {
+ typedef enum {
+ Unknown = 0,
+ EVO_LOCAL = 1,
+ EVO_LDAP = 2,
+ EVO_GWISE = 3
+ } sdbc_address_type;
+ }
+
+ typedef connectivity::OMetaConnection OConnection_BASE; // implements basics and text encoding
+
+ class OEvoabConnection final :public OConnection_BASE
+ {
+ private:
+ const OEvoabDriver& m_rDriver;
+ SDBCAddress::sdbc_address_type m_eSDBCAddressType;
+ css::uno::Reference< css::sdbcx::XTablesSupplier >
+ m_xCatalog;
+ OString m_aPassword;
+ ::dbtools::WarningsContainer m_aWarnings;
+
+ virtual ~OEvoabConnection() override;
+
+ public:
+ explicit OEvoabConnection( OEvoabDriver const & _rDriver );
+ /// @throws css::sdbc::SQLException
+ void construct(const OUString& _rUrl,const css::uno::Sequence< css::beans::PropertyValue >& _rInfo );
+
+ void setPassword( OString const & aStr ) { m_aPassword = aStr; }
+ // own methods
+ const OEvoabDriver& getDriver() const { return m_rDriver; }
+
+ SDBCAddress::sdbc_address_type getSDBCAddressType() const { return m_eSDBCAddressType;}
+ void setSDBCAddressType(SDBCAddress::sdbc_address_type _eSDBCAddressType) {m_eSDBCAddressType = _eSDBCAddressType;}
+
+ // OComponentHelper
+ virtual void SAL_CALL disposing() override;
+
+ // XServiceInfo
+ DECLARE_SERVICE_INFO();
+
+ // XConnection
+ css::uno::Reference< css::sdbcx::XTablesSupplier > createCatalog();
+ virtual css::uno::Reference< css::sdbc::XStatement > SAL_CALL createStatement( ) override;
+ virtual css::uno::Reference< css::sdbc::XPreparedStatement > SAL_CALL prepareStatement( const OUString& sql ) override;
+ virtual css::uno::Reference< css::sdbc::XPreparedStatement > SAL_CALL prepareCall( const OUString& sql ) override;
+ virtual OUString SAL_CALL nativeSQL( const OUString& sql ) override;
+ virtual void SAL_CALL setAutoCommit( sal_Bool autoCommit ) override;
+ virtual sal_Bool SAL_CALL getAutoCommit( ) override;
+ virtual void SAL_CALL commit( ) override;
+ virtual void SAL_CALL rollback( ) override;
+ virtual sal_Bool SAL_CALL isClosed( ) override;
+ virtual css::uno::Reference< css::sdbc::XDatabaseMetaData > SAL_CALL getMetaData( ) override;
+ virtual void SAL_CALL setReadOnly( sal_Bool readOnly ) override;
+ virtual sal_Bool SAL_CALL isReadOnly( ) override;
+ virtual void SAL_CALL setCatalog( const OUString& catalog ) override;
+ virtual OUString SAL_CALL getCatalog( ) override;
+ virtual void SAL_CALL setTransactionIsolation( sal_Int32 level ) override;
+ virtual sal_Int32 SAL_CALL getTransactionIsolation( ) override;
+ virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getTypeMap( ) override;
+ virtual void SAL_CALL setTypeMap( const css::uno::Reference< css::container::XNameAccess >& typeMap ) override;
+
+ // XCloseable
+ virtual void SAL_CALL close( ) override;
+ // XWarningsSupplier
+ virtual css::uno::Any SAL_CALL getWarnings( ) override;
+ virtual void SAL_CALL clearWarnings( ) override;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/evoab2/NDatabaseMetaData.cxx b/connectivity/source/drivers/evoab2/NDatabaseMetaData.cxx
new file mode 100644
index 0000000000..96a0904efc
--- /dev/null
+++ b/connectivity/source/drivers/evoab2/NDatabaseMetaData.cxx
@@ -0,0 +1,1157 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "NDatabaseMetaData.hxx"
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <com/sun/star/sdbc/TransactionIsolation.hpp>
+#include <connectivity/dbexception.hxx>
+#include <connectivity/FValue.hxx>
+#include <com/sun/star/sdbc/ColumnSearch.hpp>
+#include <rtl/ref.hxx>
+
+#include <cstddef>
+#include <string.h>
+#include <string_view>
+
+#include "EApi.h"
+
+using namespace connectivity::evoab;
+using namespace connectivity;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::sdbc;
+using namespace com::sun::star::sdbcx;
+
+namespace
+{
+ bool equal(const char *str1, const char *str2)
+ {
+ return str1 == nullptr || str2 == nullptr ? str1 == str2 : strcmp(str1, str2) == 0;
+ }
+}
+
+namespace connectivity::evoab
+{
+ sal_Int32 const s_nCOLUMN_SIZE = 256;
+ sal_Int32 const s_nDECIMAL_DIGITS = 0;
+ sal_Int32 const s_nNULLABLE = 1;
+ sal_Int32 const s_nCHAR_OCTET_LENGTH = 65535;
+
+ static ColumnProperty **pFields=nullptr;
+ static guint nFields = 0;
+
+ static const char *pDenyList[] =
+ {
+ "id",
+ "list-show-addresses",
+ "address-label-home",
+ "address-label-work",
+ "address-label-other"
+ };
+
+ const SplitEvoColumns* get_evo_addr()
+ {
+ static const SplitEvoColumns evo_addr[] = {
+ {"addr-line1",DEFAULT_ADDR_LINE1},{"addr-line2",DEFAULT_ADDR_LINE2},{"city",DEFAULT_CITY},{"state",DEFAULT_STATE},{"country",DEFAULT_COUNTRY},{"zip",DEFAULT_ZIP},
+ {"work-addr-line1",WORK_ADDR_LINE1},{"work-addr-line2",WORK_ADDR_LINE2},{"work-city",WORK_CITY},{"work-state",WORK_STATE},{"work-country",WORK_COUNTRY},{"work-zip",WORK_ZIP},
+ {"home-addr-line1",HOME_ADDR_LINE1},{"home-addr-line2",HOME_ADDR_LINE2},{"home-addr-City",HOME_CITY},{"home-state",HOME_STATE},{"home-country",HOME_COUNTRY},{"home-zip",HOME_ZIP},
+ {"other-addr-line1",OTHER_ADDR_LINE1},{"other-addr-line2",OTHER_ADDR_LINE2},{"other-addr-city",OTHER_CITY},{"other-addr-state",OTHER_STATE},{"other-addr-country",OTHER_COUNTRY},{"other-addr-zip",OTHER_ZIP}
+ };
+ return evo_addr;
+ }
+
+ static void
+ splitColumn (ColumnProperty **pToBeFields)
+ {
+ const SplitEvoColumns* evo_addr( get_evo_addr() );
+ for (int i = 0; i < OTHER_ZIP; i++)
+ {
+ pToBeFields[nFields] = g_new0(ColumnProperty,1);
+ pToBeFields[nFields]->bIsSplittedValue = true;
+ pToBeFields[nFields]->pField = g_param_spec_ref(g_param_spec_string (evo_addr[i].pColumnName,evo_addr[i].pColumnName,"",nullptr,G_PARAM_WRITABLE));
+ nFields++;
+ }
+ }
+
+ static void
+ initFields()
+ {
+ if( pFields )
+ return;
+
+ ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() );
+ if( pFields )
+ return;
+
+ guint nProps;
+ ColumnProperty **pToBeFields;
+ GParamSpec **pProps;
+ nFields = 0;
+ pProps = g_object_class_list_properties
+ ( static_cast<GObjectClass *>(g_type_class_ref( E_TYPE_CONTACT )),
+ &nProps );
+ pToBeFields = g_new0(ColumnProperty *, (nProps + OTHER_ZIP)/* new column(s)*/ );
+ for ( guint i = 0; i < nProps; i++ )
+ {
+ switch (pProps[i]->value_type)
+ {
+ case G_TYPE_STRING:
+ case G_TYPE_BOOLEAN:
+ {
+ bool bAdd = true;
+ const char *pName = g_param_spec_get_name( pProps[i] );
+ for (unsigned int j = 0; j < G_N_ELEMENTS( pDenyList ); j++ )
+ {
+ if( !strcmp( pDenyList[j], pName ) )
+ {
+ bAdd = false;
+ break;
+ }
+ }
+ if( bAdd )
+ {
+ pToBeFields[nFields]= g_new0(ColumnProperty,1);
+ pToBeFields[nFields]->bIsSplittedValue=false;
+ pToBeFields[ nFields++ ]->pField = g_param_spec_ref( pProps[i] );
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
+ splitColumn(pToBeFields);
+ pFields = pToBeFields;
+ }
+
+
+ const ColumnProperty *
+ getField(guint n)
+ {
+ initFields();
+ if( n < nFields )
+ return pFields[n];
+ else
+ return nullptr;
+ }
+
+ GType
+ getGFieldType( guint nCol )
+ {
+ initFields();
+
+ if ( nCol < nFields )
+ return pFields[nCol]->pField->value_type;
+ return G_TYPE_STRING;
+ }
+
+ sal_Int32
+ getFieldType( guint nCol )
+ {
+ sal_Int32 nType = getGFieldType( nCol );
+ return nType == G_TYPE_STRING ? DataType::VARCHAR : DataType::BIT;
+ }
+
+ guint findEvoabField(std::u16string_view aColName)
+ {
+ guint nRet = guint(-1);
+ bool bFound = false;
+ initFields();
+ for (guint i=0;(i < nFields) && !bFound;i++)
+ {
+ OUString aName = getFieldName(i);
+ if (aName == aColName)
+ {
+ nRet = i;
+ bFound = true;
+ }
+ }
+ return nRet;
+ }
+
+ OUString
+ getFieldTypeName( guint nCol )
+ {
+ switch( getFieldType( nCol ) )
+ {
+ case DataType::BIT:
+ return "BIT";
+ case DataType::VARCHAR:
+ return "VARCHAR";
+ default:
+ break;
+ }
+ return OUString();
+ }
+
+ OUString
+ getFieldName( guint nCol )
+ {
+ const GParamSpec *pSpec = getField( nCol )->pField;
+ OUString aName;
+ initFields();
+
+ if( pSpec )
+ {
+ aName = OStringToOUString( g_param_spec_get_name( const_cast<GParamSpec *>(pSpec) ),
+ RTL_TEXTENCODING_UTF8 );
+ aName = aName.replace( '-', '_' );
+ }
+ return aName;
+ }
+
+ void
+ free_column_resources()
+ {
+ for (int i=nFields-1;i > 0;i--)
+ {
+ if (pFields && pFields[i] )
+ {
+ if (pFields[i]->pField)
+ g_param_spec_unref(pFields[i]->pField);
+ g_free(pFields[i]);
+ }
+ }
+ if(pFields)
+ {
+ g_free(pFields);
+ pFields=nullptr;
+ }
+
+ }
+
+
+}
+
+
+OEvoabDatabaseMetaData::OEvoabDatabaseMetaData(OEvoabConnection* _pCon)
+ : ::connectivity::ODatabaseMetaDataBase(_pCon, _pCon->getConnectionInfo())
+ ,m_pConnection(_pCon)
+{
+ OSL_ENSURE(m_pConnection,"OEvoabDatabaseMetaData::OEvoabDatabaseMetaData: No connection set!");
+}
+OEvoabDatabaseMetaData::~OEvoabDatabaseMetaData()
+{
+}
+
+
+Reference< XResultSet > SAL_CALL OEvoabDatabaseMetaData::getColumns(
+ const Any& /*catalog*/, const OUString& /*schemaPattern*/, const OUString& /*tableNamePattern*/,
+ const OUString& columnNamePattern )
+{
+ // this returns an empty resultset where the column-names are already set
+ // in special the metadata of the resultset already returns the right columns
+ rtl::Reference<ODatabaseMetaDataResultSet> pResultSet = new ODatabaseMetaDataResultSet( ODatabaseMetaDataResultSet::eColumns );
+
+ ODatabaseMetaDataResultSet::ORows aRows;
+ ODatabaseMetaDataResultSet::ORow aRow(19);
+
+ // ****************************************************
+ // Some entries in a row never change, so set them now
+ // ****************************************************
+
+ // Catalog
+ aRow[1] = new ORowSetValueDecorator(OUString());
+ // Schema
+ aRow[2] = new ORowSetValueDecorator(OUString());
+ // COLUMN_SIZE
+ aRow[7] = new ORowSetValueDecorator(s_nCOLUMN_SIZE);
+ // BUFFER_LENGTH, not used
+ aRow[8] = ODatabaseMetaDataResultSet::getEmptyValue();
+ // DECIMAL_DIGITS.
+ aRow[9] = new ORowSetValueDecorator(s_nDECIMAL_DIGITS);
+ // NUM_PREC_RADIX
+ aRow[10] = new ORowSetValueDecorator(sal_Int32(10));
+ // NULLABLE
+ aRow[11] = new ORowSetValueDecorator(s_nNULLABLE);
+ // REMARKS
+ aRow[12] = ODatabaseMetaDataResultSet::getEmptyValue();
+ // COLUMN_DEF, not used
+ aRow[13] = ODatabaseMetaDataResultSet::getEmptyValue();
+ // SQL_DATA_TYPE, not used
+ aRow[14] = ODatabaseMetaDataResultSet::getEmptyValue();
+ // SQL_DATETIME_SUB, not used
+ aRow[15] = ODatabaseMetaDataResultSet::getEmptyValue();
+ // CHAR_OCTET_LENGTH, refer to [5]
+ aRow[16] = new ORowSetValueDecorator(s_nCHAR_OCTET_LENGTH);
+ // IS_NULLABLE
+ aRow[18] = new ORowSetValueDecorator(OUString("YES"));
+
+
+ aRow[3] = new ORowSetValueDecorator(OUString("TABLE"));
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ initFields();
+ for (guint i = 0; i < nFields; i++)
+ {
+ if( match( columnNamePattern, getFieldName( i ), '\0' ) )
+ {
+ aRow[5] = new ORowSetValueDecorator( static_cast<sal_Int16>( getFieldType( i ) ) );
+ aRow[6] = new ORowSetValueDecorator( getFieldTypeName( i ) );
+
+ // COLUMN_NAME
+ aRow[4] = new ORowSetValueDecorator( getFieldName( i ) );
+ // ORDINAL_POSITION
+ aRow[17] = new ORowSetValueDecorator( sal_Int32(i) );
+ aRows.push_back( aRow );
+ }
+ }
+
+ pResultSet->setRows(std::move(aRows));
+
+ return pResultSet;
+}
+
+OUString OEvoabDatabaseMetaData::impl_getCatalogSeparator_throw( )
+{
+ return OUString();
+}
+
+sal_Int32 SAL_CALL OEvoabDatabaseMetaData::getMaxBinaryLiteralLength( )
+{
+ return 0;// 0 means no limit
+}
+
+sal_Int32 SAL_CALL OEvoabDatabaseMetaData::getMaxRowSize( )
+{
+ return 0;// 0 means no limit
+}
+
+sal_Int32 SAL_CALL OEvoabDatabaseMetaData::getMaxCatalogNameLength( )
+{
+ return 0;// 0 means no limit
+}
+
+sal_Int32 SAL_CALL OEvoabDatabaseMetaData::getMaxCharLiteralLength( )
+{
+ return 0;// 0 means no limit
+}
+
+sal_Int32 SAL_CALL OEvoabDatabaseMetaData::getMaxColumnNameLength( )
+{
+ return 0;// 0 means no limit
+}
+
+sal_Int32 SAL_CALL OEvoabDatabaseMetaData::getMaxColumnsInIndex( )
+{
+ return 0;// 0 means no limit
+}
+
+sal_Int32 SAL_CALL OEvoabDatabaseMetaData::getMaxCursorNameLength( )
+{
+ return 0;// 0 means no limit
+}
+
+sal_Int32 SAL_CALL OEvoabDatabaseMetaData::getMaxConnections( )
+{
+ return 0;// 0 means no limit
+}
+
+sal_Int32 SAL_CALL OEvoabDatabaseMetaData::getMaxColumnsInTable( )
+{
+ return 0;// 0 means no limit
+}
+
+sal_Int32 OEvoabDatabaseMetaData::impl_getMaxStatements_throw( )
+{
+ return 0;// 0 means no limit
+}
+
+sal_Int32 SAL_CALL OEvoabDatabaseMetaData::getMaxTableNameLength( )
+{
+ return 0;// 0 means no limit
+}
+
+sal_Int32 OEvoabDatabaseMetaData::impl_getMaxTablesInSelect_throw( )
+{
+ // We only support a single table
+ return 1;
+}
+
+
+sal_Bool SAL_CALL OEvoabDatabaseMetaData::doesMaxRowSizeIncludeBlobs( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL OEvoabDatabaseMetaData::storesLowerCaseQuotedIdentifiers( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL OEvoabDatabaseMetaData::storesLowerCaseIdentifiers( )
+{
+ return false;
+}
+
+bool OEvoabDatabaseMetaData::impl_storesMixedCaseQuotedIdentifiers_throw( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL OEvoabDatabaseMetaData::storesMixedCaseIdentifiers( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL OEvoabDatabaseMetaData::storesUpperCaseQuotedIdentifiers( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL OEvoabDatabaseMetaData::storesUpperCaseIdentifiers( )
+{
+ return false;
+}
+
+bool OEvoabDatabaseMetaData::impl_supportsAlterTableWithAddColumn_throw( )
+{
+ return false;
+}
+
+bool OEvoabDatabaseMetaData::impl_supportsAlterTableWithDropColumn_throw( )
+{
+ return false;
+}
+
+sal_Int32 SAL_CALL OEvoabDatabaseMetaData::getMaxIndexLength( )
+{
+ return 0;// 0 means no limit
+}
+
+sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsNonNullableColumns( )
+{
+ return false;
+}
+
+OUString SAL_CALL OEvoabDatabaseMetaData::getCatalogTerm( )
+{
+ return OUString();
+}
+
+OUString OEvoabDatabaseMetaData::impl_getIdentifierQuoteString_throw( )
+{
+ // normally this is "
+ return "\"";
+}
+
+OUString SAL_CALL OEvoabDatabaseMetaData::getExtraNameCharacters( )
+{
+ return OUString();
+}
+
+sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsDifferentTableCorrelationNames( )
+{
+ return false;
+}
+
+bool OEvoabDatabaseMetaData::impl_isCatalogAtStart_throw( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL OEvoabDatabaseMetaData::dataDefinitionIgnoredInTransactions( )
+{
+ return true;
+}
+
+sal_Bool SAL_CALL OEvoabDatabaseMetaData::dataDefinitionCausesTransactionCommit( )
+{
+ return true;
+}
+
+sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsDataManipulationTransactionsOnly( )
+{
+ return true;
+}
+
+sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsDataDefinitionAndDataManipulationTransactions( )
+{
+ return true;
+}
+
+sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsPositionedDelete( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsPositionedUpdate( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsOpenStatementsAcrossRollback( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsOpenStatementsAcrossCommit( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsOpenCursorsAcrossCommit( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsOpenCursorsAcrossRollback( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsTransactionIsolationLevel( sal_Int32 /*level*/ )
+{
+ return false;
+}
+
+bool OEvoabDatabaseMetaData::impl_supportsSchemasInDataManipulation_throw( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsANSI92FullSQL( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsANSI92EntryLevelSQL( )
+{
+ return true; // should be supported at least
+}
+
+sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsIntegrityEnhancementFacility( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsSchemasInIndexDefinitions( )
+{
+ return false;
+}
+
+bool OEvoabDatabaseMetaData::impl_supportsSchemasInTableDefinitions_throw( )
+{
+ return false;
+}
+
+bool OEvoabDatabaseMetaData::impl_supportsCatalogsInTableDefinitions_throw( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsCatalogsInIndexDefinitions( )
+{
+ return false;
+}
+
+bool OEvoabDatabaseMetaData::impl_supportsCatalogsInDataManipulation_throw( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsOuterJoins( )
+{
+ return false;
+}
+
+sal_Int32 SAL_CALL OEvoabDatabaseMetaData::getMaxStatementLength( )
+{
+ return 0;// 0 means no limit
+}
+
+sal_Int32 SAL_CALL OEvoabDatabaseMetaData::getMaxProcedureNameLength( )
+{
+ return 0;// 0 means no limit
+}
+
+sal_Int32 SAL_CALL OEvoabDatabaseMetaData::getMaxSchemaNameLength( )
+{
+ return 0;// 0 means no limit
+}
+
+sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsTransactions( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL OEvoabDatabaseMetaData::allProceduresAreCallable( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsStoredProcedures( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsSelectForUpdate( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL OEvoabDatabaseMetaData::allTablesAreSelectable( )
+{
+ // We allow you to select from any table.
+ return true;
+}
+
+sal_Bool SAL_CALL OEvoabDatabaseMetaData::isReadOnly( )
+{
+ // For now definitely read-only, no support for update/delete
+ return true;
+}
+
+sal_Bool SAL_CALL OEvoabDatabaseMetaData::usesLocalFiles( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL OEvoabDatabaseMetaData::usesLocalFilePerTable( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsTypeConversion( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL OEvoabDatabaseMetaData::nullPlusNonNullIsNull( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsColumnAliasing( )
+{
+ // todo add Support for this.
+ return false;
+}
+
+sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsTableCorrelationNames( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsConvert( sal_Int32 /*fromType*/, sal_Int32 /*toType*/ )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsExpressionsInOrderBy( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsGroupBy( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsGroupByBeyondSelect( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsGroupByUnrelated( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsMultipleTransactions( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsMultipleResultSets( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsLikeEscapeClause( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsOrderByUnrelated( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsUnion( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsUnionAll( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsMixedCaseIdentifiers( )
+{
+ return false;
+}
+
+bool OEvoabDatabaseMetaData::impl_supportsMixedCaseQuotedIdentifiers_throw( )
+{
+ // Any case may be used
+ return true;
+}
+
+sal_Bool SAL_CALL OEvoabDatabaseMetaData::nullsAreSortedAtEnd( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL OEvoabDatabaseMetaData::nullsAreSortedAtStart( )
+{
+ return true;
+}
+
+sal_Bool SAL_CALL OEvoabDatabaseMetaData::nullsAreSortedHigh( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL OEvoabDatabaseMetaData::nullsAreSortedLow( )
+{
+ return true;
+}
+
+sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsSchemasInProcedureCalls( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsSchemasInPrivilegeDefinitions( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsCatalogsInProcedureCalls( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsCatalogsInPrivilegeDefinitions( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsCorrelatedSubqueries( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsSubqueriesInComparisons( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsSubqueriesInExists( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsSubqueriesInIns( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsSubqueriesInQuantifieds( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsANSI92IntermediateSQL( )
+{
+ return false;
+}
+
+OUString SAL_CALL OEvoabDatabaseMetaData::getURL( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ return m_pConnection->getURL();
+}
+
+OUString SAL_CALL OEvoabDatabaseMetaData::getUserName( )
+{
+ return OUString();
+}
+
+OUString SAL_CALL OEvoabDatabaseMetaData::getDriverName( )
+{
+ return OUString();
+}
+
+OUString SAL_CALL OEvoabDatabaseMetaData::getDriverVersion()
+{
+ return "1";
+}
+
+OUString SAL_CALL OEvoabDatabaseMetaData::getDatabaseProductVersion( )
+{
+ return "0";
+}
+
+OUString SAL_CALL OEvoabDatabaseMetaData::getDatabaseProductName( )
+{
+ return OUString();
+}
+
+OUString SAL_CALL OEvoabDatabaseMetaData::getProcedureTerm( )
+{
+ return OUString();
+}
+
+OUString SAL_CALL OEvoabDatabaseMetaData::getSchemaTerm( )
+{
+ return OUString();
+}
+
+sal_Int32 SAL_CALL OEvoabDatabaseMetaData::getDriverMajorVersion( )
+{
+ return 1;
+}
+
+sal_Int32 SAL_CALL OEvoabDatabaseMetaData::getDefaultTransactionIsolation( )
+{
+ return TransactionIsolation::NONE;
+}
+
+sal_Int32 SAL_CALL OEvoabDatabaseMetaData::getDriverMinorVersion( )
+{
+ return 0;
+}
+
+OUString SAL_CALL OEvoabDatabaseMetaData::getSQLKeywords( )
+{
+ return OUString();
+}
+
+OUString SAL_CALL OEvoabDatabaseMetaData::getSearchStringEscape( )
+{
+ return OUString();
+}
+
+OUString SAL_CALL OEvoabDatabaseMetaData::getStringFunctions( )
+{
+ return OUString();
+}
+
+OUString SAL_CALL OEvoabDatabaseMetaData::getTimeDateFunctions( )
+{
+ return OUString();
+}
+
+OUString SAL_CALL OEvoabDatabaseMetaData::getSystemFunctions( )
+{
+ return OUString();
+}
+
+OUString SAL_CALL OEvoabDatabaseMetaData::getNumericFunctions( )
+{
+ return OUString();
+}
+
+sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsExtendedSQLGrammar( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsCoreSQLGrammar( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsMinimumSQLGrammar( )
+{
+ return true;
+}
+
+sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsFullOuterJoins( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsLimitedOuterJoins( )
+{
+ return false;
+}
+
+sal_Int32 SAL_CALL OEvoabDatabaseMetaData::getMaxColumnsInGroupBy( )
+{
+ return 0;// 0 means no limit
+}
+
+sal_Int32 SAL_CALL OEvoabDatabaseMetaData::getMaxColumnsInOrderBy( )
+{
+ return 0;// 0 means no limit
+}
+
+sal_Int32 SAL_CALL OEvoabDatabaseMetaData::getMaxColumnsInSelect( )
+{
+ return 0;// 0 means no limit
+}
+
+sal_Int32 SAL_CALL OEvoabDatabaseMetaData::getMaxUserNameLength( )
+{
+ return 0;// 0 means no limit
+}
+
+sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsResultSetType( sal_Int32 /*setType*/ )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsResultSetConcurrency( sal_Int32 /*setType*/, sal_Int32 /*concurrency*/ )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL OEvoabDatabaseMetaData::ownUpdatesAreVisible( sal_Int32 /*setType*/ )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL OEvoabDatabaseMetaData::ownDeletesAreVisible( sal_Int32 /*setType*/ )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL OEvoabDatabaseMetaData::ownInsertsAreVisible( sal_Int32 /*setType*/ )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL OEvoabDatabaseMetaData::othersUpdatesAreVisible( sal_Int32 /*setType*/ )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL OEvoabDatabaseMetaData::othersDeletesAreVisible( sal_Int32 /*setType*/ )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL OEvoabDatabaseMetaData::othersInsertsAreVisible( sal_Int32 /*setType*/ )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL OEvoabDatabaseMetaData::updatesAreDetected( sal_Int32 /*setType*/ )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL OEvoabDatabaseMetaData::deletesAreDetected( sal_Int32 /*setType*/ )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL OEvoabDatabaseMetaData::insertsAreDetected( sal_Int32 /*setType*/ )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsBatchUpdates( )
+{
+ return false;
+}
+
+// here follow all methods which return a resultset
+// the first methods is an example implementation how to use this resultset
+// of course you could implement it on your and you should do this because
+// the general way is more memory expensive
+
+Reference< XResultSet > SAL_CALL OEvoabDatabaseMetaData::getTableTypes( )
+{
+ /* Don't need to change as evoab driver supports only table */
+
+ // there exists no possibility to get table types so we have to check
+ static const std::u16string_view sTableTypes[] =
+ {
+ u"TABLE" // Currently we only support a 'TABLE' nothing more complex
+ };
+ rtl::Reference<::connectivity::ODatabaseMetaDataResultSet> pResult = new ::connectivity::ODatabaseMetaDataResultSet(::connectivity::ODatabaseMetaDataResultSet::eTableTypes);
+
+ // here we fill the rows which should be visible when ask for data from the resultset returned here
+ auto nNbTypes = std::size(sTableTypes);
+ ODatabaseMetaDataResultSet::ORows aRows;
+ for(std::size_t i=0;i < nNbTypes;++i)
+ {
+ // bound row
+ aRows.push_back( { ODatabaseMetaDataResultSet::getEmptyValue(), new ORowSetValueDecorator(OUString(sTableTypes[i])) });
+ }
+ // here we set the rows at the resultset
+ pResult->setRows(std::move(aRows));
+ return pResult;
+}
+
+Reference< XResultSet > OEvoabDatabaseMetaData::impl_getTypeInfo_throw( )
+{
+ /*
+ * Return the proper type information required by evo driver
+ */
+
+ rtl::Reference<ODatabaseMetaDataResultSet> pResultSet = new ODatabaseMetaDataResultSet(ODatabaseMetaDataResultSet::eTypeInfo);
+
+ static ODatabaseMetaDataResultSet::ORows aRows = []()
+ {
+ ODatabaseMetaDataResultSet::ORows tmp;
+ ODatabaseMetaDataResultSet::ORow aRow
+ {
+ ODatabaseMetaDataResultSet::getEmptyValue() ,
+ new ORowSetValueDecorator(OUString("VARCHAR")) ,
+ new ORowSetValueDecorator(DataType::VARCHAR) ,
+ new ORowSetValueDecorator(sal_Int32(s_nCHAR_OCTET_LENGTH)) ,
+ ODatabaseMetaDataResultSet::getQuoteValue() ,
+ ODatabaseMetaDataResultSet::getQuoteValue() ,
+ ODatabaseMetaDataResultSet::getEmptyValue() ,
+ ODatabaseMetaDataResultSet::get1Value() ,
+ ODatabaseMetaDataResultSet::get1Value() ,
+ new ORowSetValueDecorator(sal_Int32(ColumnSearch::FULL)) ,
+ ODatabaseMetaDataResultSet::get1Value() ,
+ ODatabaseMetaDataResultSet::get0Value() ,
+ ODatabaseMetaDataResultSet::get0Value() ,
+ ODatabaseMetaDataResultSet::getEmptyValue() ,
+ ODatabaseMetaDataResultSet::get0Value() ,
+ ODatabaseMetaDataResultSet::get0Value() ,
+ ODatabaseMetaDataResultSet::getEmptyValue() ,
+ ODatabaseMetaDataResultSet::getEmptyValue() ,
+ new ORowSetValueDecorator(sal_Int32(10))
+ };
+
+ tmp.push_back(aRow);
+
+ aRow[1] = new ORowSetValueDecorator(OUString("VARCHAR"));
+ aRow[2] = new ORowSetValueDecorator(DataType::VARCHAR);
+ aRow[3] = new ORowSetValueDecorator(sal_Int32(65535));
+ tmp.push_back(aRow);
+ return tmp;
+ }();
+ pResultSet->setRows(std::move(aRows));
+ return pResultSet;
+}
+
+bool isSourceBackend(ESource *pSource, const char *backendname)
+{
+ if (!pSource || !e_source_has_extension (pSource, E_SOURCE_EXTENSION_ADDRESS_BOOK))
+ return false;
+
+ gpointer extension = e_source_get_extension (pSource, E_SOURCE_EXTENSION_ADDRESS_BOOK);
+ return extension && equal(e_source_backend_get_backend_name (extension), backendname);
+}
+
+Reference< XResultSet > SAL_CALL OEvoabDatabaseMetaData::getTables(
+ const Any& /*catalog*/, const OUString& /*schemaPattern*/,
+ const OUString& /*tableNamePattern*/, const Sequence< OUString >& types )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ rtl::Reference<ODatabaseMetaDataResultSet> pResult = new ODatabaseMetaDataResultSet(ODatabaseMetaDataResultSet::eTables);
+
+ // check if any type is given
+ // when no types are given then we have to return all tables e.g. TABLE
+
+ static constexpr OUString aTable(u"TABLE"_ustr);
+
+ bool bTableFound = true;
+ sal_Int32 nLength = types.getLength();
+ if(nLength)
+ {
+ bTableFound = false;
+
+ const OUString* pBegin = types.getConstArray();
+ const OUString* pEnd = pBegin + nLength;
+ for(;pBegin != pEnd;++pBegin)
+ {
+ if(*pBegin == aTable)
+ {
+ bTableFound = true;
+ break;
+ }
+ }
+ }
+ if(!bTableFound)
+ return pResult;
+
+ ODatabaseMetaDataResultSet::ORows aRows;
+
+ GList *pSources = e_source_registry_list_sources(get_e_source_registry(), E_SOURCE_EXTENSION_ADDRESS_BOOK);
+
+ for (GList* liter = pSources; liter; liter = liter->next)
+ {
+ ESource *pSource = E_SOURCE (liter->data);
+ bool can = false;
+ switch (m_pConnection->getSDBCAddressType())
+ {
+ case SDBCAddress::EVO_GWISE:
+ can = isSourceBackend( pSource, "groupwise"); // not supported in evo/eds 3.6.x+, somehow
+ break;
+ case SDBCAddress::EVO_LOCAL:
+ can = isSourceBackend( pSource, "local");
+ break;
+ case SDBCAddress::EVO_LDAP:
+ can = isSourceBackend( pSource, "ldap");
+ break;
+ case SDBCAddress::Unknown:
+ can = true;
+ break;
+ }
+ if (!can)
+ continue;
+
+ OUString aHumanName = OStringToOUString( e_source_get_display_name( pSource ),
+ RTL_TEXTENCODING_UTF8 );
+ OUString aUID = OStringToOUString( e_source_get_uid( pSource ),
+ RTL_TEXTENCODING_UTF8 );
+ ODatabaseMetaDataResultSet::ORow aRow{
+ ORowSetValueDecoratorRef(),
+ ORowSetValueDecoratorRef(),
+ ORowSetValueDecoratorRef(),
+ new ORowSetValueDecorator(aHumanName), //tablename
+ new ORowSetValueDecorator(ORowSetValue(aTable)),
+ new ORowSetValueDecorator(aUID)}; //comment
+ //I'd prefer to swap the comment and the human name and
+ //just use e_source_registry_ref_source(get_e_source_registry(), aUID);
+ //in open book rather than search for the name again
+ aRows.push_back(aRow);
+ }
+
+ g_list_foreach (pSources, reinterpret_cast<GFunc>(g_object_unref), nullptr);
+ g_list_free (pSources);
+
+ pResult->setRows(std::move(aRows));
+
+ return pResult;
+}
+
+Reference< XResultSet > SAL_CALL OEvoabDatabaseMetaData::getUDTs( const Any& /*catalog*/, const OUString& /*schemaPattern*/, const OUString& /*typeNamePattern*/, const Sequence< sal_Int32 >& /*types*/ )
+{
+ ::dbtools::throwFeatureNotImplementedSQLException( "XDatabaseMetaDaza::getUDTs", *this );
+ return nullptr;
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/evoab2/NDatabaseMetaData.hxx b/connectivity/source/drivers/evoab2/NDatabaseMetaData.hxx
new file mode 100644
index 0000000000..a64c234e6a
--- /dev/null
+++ b/connectivity/source/drivers/evoab2/NDatabaseMetaData.hxx
@@ -0,0 +1,218 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <string_view>
+
+#include "NConnection.hxx"
+#include <TDatabaseMetaDataBase.hxx>
+#include <FDatabaseMetaDataResultSet.hxx>
+
+
+namespace connectivity::evoab
+{
+
+ //************ Class: OEvoabDatabaseMetaData
+
+ typedef struct{
+ gboolean bIsSplittedValue;
+ GParamSpec *pField;
+ }ColumnProperty;
+
+ typedef enum {
+ DEFAULT_ADDR_LINE1=1,DEFAULT_ADDR_LINE2,DEFAULT_CITY,DEFAULT_STATE,DEFAULT_COUNTRY,DEFAULT_ZIP,
+ WORK_ADDR_LINE1,WORK_ADDR_LINE2,WORK_CITY,WORK_STATE,WORK_COUNTRY,WORK_ZIP,
+ HOME_ADDR_LINE1,HOME_ADDR_LINE2,HOME_CITY,HOME_STATE,HOME_COUNTRY,HOME_ZIP,
+ OTHER_ADDR_LINE1,OTHER_ADDR_LINE2,OTHER_CITY,OTHER_STATE,OTHER_COUNTRY,OTHER_ZIP
+ }ColumnNumber;
+
+ typedef struct {
+ const gchar *pColumnName;
+ ColumnNumber value;
+ }SplitEvoColumns;
+
+ const SplitEvoColumns* get_evo_addr();
+
+ const ColumnProperty *getField(guint n);
+ GType getGFieldType(guint nCol) ;
+ sal_Int32 getFieldType(guint nCol) ;
+ OUString getFieldTypeName(guint nCol) ;
+ OUString getFieldName(guint nCol) ;
+ guint findEvoabField(std::u16string_view aColName);
+
+ void free_column_resources();
+
+ class OEvoabDatabaseMetaData : public ODatabaseMetaDataBase
+ {
+ OEvoabConnection* m_pConnection;
+
+ protected:
+ virtual css::uno::Reference< css::sdbc::XResultSet > impl_getTypeInfo_throw() override;
+ // cached database information
+ virtual OUString impl_getIdentifierQuoteString_throw( ) override;
+ virtual bool impl_isCatalogAtStart_throw( ) override;
+ virtual OUString impl_getCatalogSeparator_throw( ) override;
+ virtual bool impl_supportsCatalogsInTableDefinitions_throw( ) override;
+ virtual bool impl_supportsSchemasInTableDefinitions_throw( ) override ;
+ virtual bool impl_supportsCatalogsInDataManipulation_throw( ) override;
+ virtual bool impl_supportsSchemasInDataManipulation_throw( ) override ;
+ virtual bool impl_supportsMixedCaseQuotedIdentifiers_throw( ) override ;
+ virtual bool impl_supportsAlterTableWithAddColumn_throw( ) override;
+ virtual bool impl_supportsAlterTableWithDropColumn_throw( ) override;
+ virtual sal_Int32 impl_getMaxStatements_throw( ) override;
+ virtual sal_Int32 impl_getMaxTablesInSelect_throw( ) override;
+ virtual bool impl_storesMixedCaseQuotedIdentifiers_throw( ) override;
+
+ virtual ~OEvoabDatabaseMetaData() override;
+ public:
+ explicit OEvoabDatabaseMetaData(OEvoabConnection* _pCon);
+
+ // as I mentioned before this interface is really BIG
+ // XDatabaseMetaData
+ virtual sal_Bool SAL_CALL allProceduresAreCallable( ) override;
+ virtual sal_Bool SAL_CALL allTablesAreSelectable( ) override;
+ virtual OUString SAL_CALL getURL( ) override;
+ virtual OUString SAL_CALL getUserName( ) override;
+ virtual sal_Bool SAL_CALL isReadOnly( ) override;
+ virtual sal_Bool SAL_CALL nullsAreSortedHigh( ) override;
+ virtual sal_Bool SAL_CALL nullsAreSortedLow( ) override;
+ virtual sal_Bool SAL_CALL nullsAreSortedAtStart( ) override;
+ virtual sal_Bool SAL_CALL nullsAreSortedAtEnd( ) override;
+ virtual OUString SAL_CALL getDatabaseProductName( ) override;
+ virtual OUString SAL_CALL getDatabaseProductVersion( ) override;
+ virtual OUString SAL_CALL getDriverName( ) override;
+ virtual OUString SAL_CALL getDriverVersion( ) override;
+ virtual sal_Int32 SAL_CALL getDriverMajorVersion( ) override;
+ virtual sal_Int32 SAL_CALL getDriverMinorVersion( ) override;
+ virtual sal_Bool SAL_CALL usesLocalFiles( ) override;
+ virtual sal_Bool SAL_CALL usesLocalFilePerTable( ) override;
+ virtual sal_Bool SAL_CALL supportsMixedCaseIdentifiers( ) override;
+ virtual sal_Bool SAL_CALL storesUpperCaseIdentifiers( ) override;
+ virtual sal_Bool SAL_CALL storesLowerCaseIdentifiers( ) override;
+ virtual sal_Bool SAL_CALL storesMixedCaseIdentifiers( ) override;
+
+ virtual sal_Bool SAL_CALL storesUpperCaseQuotedIdentifiers( ) override;
+ virtual sal_Bool SAL_CALL storesLowerCaseQuotedIdentifiers( ) override;
+
+ virtual OUString SAL_CALL getSQLKeywords( ) override;
+ virtual OUString SAL_CALL getNumericFunctions( ) override;
+ virtual OUString SAL_CALL getStringFunctions( ) override;
+ virtual OUString SAL_CALL getSystemFunctions( ) override;
+ virtual OUString SAL_CALL getTimeDateFunctions( ) override;
+ virtual OUString SAL_CALL getSearchStringEscape( ) override;
+ virtual OUString SAL_CALL getExtraNameCharacters( ) override;
+ virtual sal_Bool SAL_CALL supportsColumnAliasing( ) override;
+ virtual sal_Bool SAL_CALL nullPlusNonNullIsNull( ) override;
+ virtual sal_Bool SAL_CALL supportsTypeConversion( ) override;
+ virtual sal_Bool SAL_CALL supportsConvert( sal_Int32 fromType, sal_Int32 toType ) override;
+ virtual sal_Bool SAL_CALL supportsTableCorrelationNames( ) override;
+ virtual sal_Bool SAL_CALL supportsDifferentTableCorrelationNames( ) override;
+ virtual sal_Bool SAL_CALL supportsExpressionsInOrderBy( ) override;
+ virtual sal_Bool SAL_CALL supportsOrderByUnrelated( ) override;
+ virtual sal_Bool SAL_CALL supportsGroupBy( ) override;
+ virtual sal_Bool SAL_CALL supportsGroupByUnrelated( ) override;
+ virtual sal_Bool SAL_CALL supportsGroupByBeyondSelect( ) override;
+ virtual sal_Bool SAL_CALL supportsLikeEscapeClause( ) override;
+ virtual sal_Bool SAL_CALL supportsMultipleResultSets( ) override;
+ virtual sal_Bool SAL_CALL supportsMultipleTransactions( ) override;
+ virtual sal_Bool SAL_CALL supportsNonNullableColumns( ) override;
+ virtual sal_Bool SAL_CALL supportsMinimumSQLGrammar( ) override;
+ virtual sal_Bool SAL_CALL supportsCoreSQLGrammar( ) override;
+ virtual sal_Bool SAL_CALL supportsExtendedSQLGrammar( ) override;
+ virtual sal_Bool SAL_CALL supportsANSI92EntryLevelSQL( ) override;
+ virtual sal_Bool SAL_CALL supportsANSI92IntermediateSQL( ) override;
+ virtual sal_Bool SAL_CALL supportsANSI92FullSQL( ) override;
+ virtual sal_Bool SAL_CALL supportsIntegrityEnhancementFacility( ) override;
+ virtual sal_Bool SAL_CALL supportsOuterJoins( ) override;
+ virtual sal_Bool SAL_CALL supportsFullOuterJoins( ) override;
+ virtual sal_Bool SAL_CALL supportsLimitedOuterJoins( ) override;
+ virtual OUString SAL_CALL getSchemaTerm( ) override;
+ virtual OUString SAL_CALL getProcedureTerm( ) override;
+ virtual OUString SAL_CALL getCatalogTerm( ) override;
+ virtual sal_Bool SAL_CALL supportsSchemasInProcedureCalls( ) override;
+ virtual sal_Bool SAL_CALL supportsSchemasInIndexDefinitions( ) override;
+ virtual sal_Bool SAL_CALL supportsSchemasInPrivilegeDefinitions( ) override;
+ virtual sal_Bool SAL_CALL supportsCatalogsInProcedureCalls( ) override;
+ virtual sal_Bool SAL_CALL supportsCatalogsInIndexDefinitions( ) override;
+ virtual sal_Bool SAL_CALL supportsCatalogsInPrivilegeDefinitions( ) override;
+ virtual sal_Bool SAL_CALL supportsPositionedDelete( ) override;
+ virtual sal_Bool SAL_CALL supportsPositionedUpdate( ) override;
+ virtual sal_Bool SAL_CALL supportsSelectForUpdate( ) override;
+ virtual sal_Bool SAL_CALL supportsStoredProcedures( ) override;
+ virtual sal_Bool SAL_CALL supportsSubqueriesInComparisons( ) override;
+ virtual sal_Bool SAL_CALL supportsSubqueriesInExists( ) override;
+ virtual sal_Bool SAL_CALL supportsSubqueriesInIns( ) override;
+ virtual sal_Bool SAL_CALL supportsSubqueriesInQuantifieds( ) override;
+ virtual sal_Bool SAL_CALL supportsCorrelatedSubqueries( ) override;
+ virtual sal_Bool SAL_CALL supportsUnion( ) override;
+ virtual sal_Bool SAL_CALL supportsUnionAll( ) override;
+ virtual sal_Bool SAL_CALL supportsOpenCursorsAcrossCommit( ) override;
+ virtual sal_Bool SAL_CALL supportsOpenCursorsAcrossRollback( ) override;
+ virtual sal_Bool SAL_CALL supportsOpenStatementsAcrossCommit( ) override;
+ virtual sal_Bool SAL_CALL supportsOpenStatementsAcrossRollback( ) override;
+ virtual sal_Int32 SAL_CALL getMaxBinaryLiteralLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxCharLiteralLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxColumnNameLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxColumnsInGroupBy( ) override;
+ virtual sal_Int32 SAL_CALL getMaxColumnsInIndex( ) override;
+ virtual sal_Int32 SAL_CALL getMaxColumnsInOrderBy( ) override;
+ virtual sal_Int32 SAL_CALL getMaxColumnsInSelect( ) override;
+ virtual sal_Int32 SAL_CALL getMaxColumnsInTable( ) override;
+ virtual sal_Int32 SAL_CALL getMaxConnections( ) override;
+ virtual sal_Int32 SAL_CALL getMaxCursorNameLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxIndexLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxSchemaNameLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxProcedureNameLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxCatalogNameLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxRowSize( ) override;
+ virtual sal_Bool SAL_CALL doesMaxRowSizeIncludeBlobs( ) override;
+ virtual sal_Int32 SAL_CALL getMaxStatementLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxTableNameLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxUserNameLength( ) override;
+ virtual sal_Int32 SAL_CALL getDefaultTransactionIsolation( ) override;
+ virtual sal_Bool SAL_CALL supportsTransactions( ) override;
+ virtual sal_Bool SAL_CALL supportsTransactionIsolationLevel( sal_Int32 level ) override;
+ virtual sal_Bool SAL_CALL supportsDataDefinitionAndDataManipulationTransactions( ) override;
+ virtual sal_Bool SAL_CALL supportsDataManipulationTransactionsOnly( ) override;
+ virtual sal_Bool SAL_CALL dataDefinitionCausesTransactionCommit( ) override;
+ virtual sal_Bool SAL_CALL dataDefinitionIgnoredInTransactions( ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getTables( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& tableNamePattern, const css::uno::Sequence< OUString >& types ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getTableTypes( ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getColumns( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& tableNamePattern, const OUString& columnNamePattern ) override;
+ virtual sal_Bool SAL_CALL supportsResultSetType( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL supportsResultSetConcurrency( sal_Int32 setType, sal_Int32 concurrency ) override;
+ virtual sal_Bool SAL_CALL ownUpdatesAreVisible( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL ownDeletesAreVisible( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL ownInsertsAreVisible( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL othersUpdatesAreVisible( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL othersDeletesAreVisible( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL othersInsertsAreVisible( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL updatesAreDetected( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL deletesAreDetected( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL insertsAreDetected( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL supportsBatchUpdates( ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getUDTs( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& typeNamePattern, const css::uno::Sequence< sal_Int32 >& types ) override;
+ };
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/evoab2/NDriver.cxx b/connectivity/source/drivers/evoab2/NDriver.cxx
new file mode 100644
index 0000000000..d1b7746f47
--- /dev/null
+++ b/connectivity/source/drivers/evoab2/NDriver.cxx
@@ -0,0 +1,157 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "NDriver.hxx"
+#include "NConnection.hxx"
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <connectivity/dbexception.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <com/sun/star/ucb/XContentAccess.hpp>
+#include <rtl/ref.hxx>
+#include <strings.hrc>
+#include <resource/sharedresources.hxx>
+
+using namespace osl;
+using namespace connectivity::evoab;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::ucb;
+
+
+OEvoabDriver::OEvoabDriver(const Reference< XComponentContext >& _rxContext) :
+ ODriver_BASE( m_aMutex ), m_xContext( _rxContext )
+{
+}
+
+OEvoabDriver::~OEvoabDriver()
+{
+}
+
+void OEvoabDriver::disposing()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+
+ // when driver will be destroyed so all our connections have to be destroyed as well
+ for (const auto& rxConnection : m_xConnections)
+ {
+ Reference< XComponent > xComp(rxConnection.get(), UNO_QUERY);
+ if (xComp.is())
+ {
+ try
+ {
+ xComp->dispose();
+ }
+ catch (const css::lang::DisposedException&)
+ {
+ xComp.clear();
+ }
+ }
+ }
+ m_xConnections.clear();
+ connectivity::OWeakRefArray().swap(m_xConnections); // this really clears
+
+ ODriver_BASE::disposing();
+}
+
+// static ServiceInfo
+
+
+OUString SAL_CALL OEvoabDriver::getImplementationName( )
+{
+ return EVOAB_DRIVER_IMPL_NAME;
+ // this name is referenced in the configuration and in the evoab.xml
+ // Please take care when changing it.
+}
+
+sal_Bool SAL_CALL OEvoabDriver::supportsService( const OUString& _rServiceName )
+{
+ return cppu::supportsService(this, _rServiceName);
+}
+
+Sequence< OUString > SAL_CALL OEvoabDriver::getSupportedServiceNames( )
+{
+ // which service is supported
+ // for more information @see com.sun.star.sdbc.Driver
+ return { "com.sun.star.sdbc.Driver" };
+}
+
+
+Reference< XConnection > SAL_CALL OEvoabDriver::connect( const OUString& url, const Sequence< PropertyValue >& info )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if (ODriver_BASE::rBHelper.bDisposed)
+ throw DisposedException();
+
+ if ( ! acceptsURL(url) )
+ return nullptr;
+
+ rtl::Reference<OEvoabConnection> pCon = new OEvoabConnection( *this );
+ pCon->construct(url,info);
+ m_xConnections.push_back(WeakReferenceHelper(*pCon));
+
+ return pCon;
+}
+
+sal_Bool SAL_CALL OEvoabDriver::acceptsURL( const OUString& url )
+{
+ return acceptsURL_Stat(url);
+}
+
+
+Sequence< DriverPropertyInfo > SAL_CALL OEvoabDriver::getPropertyInfo( const OUString& url, const Sequence< PropertyValue >& /*info*/ )
+{
+ if ( ! acceptsURL(url) )
+ {
+ ::connectivity::SharedResources aResources;
+ const OUString sMessage = aResources.getResourceString(STR_URI_SYNTAX_ERROR);
+ ::dbtools::throwGenericSQLException(sMessage ,*this);
+ } // if ( ! acceptsURL(url) )
+
+ // if you have something special to say return it here :-)
+ return Sequence< DriverPropertyInfo >();
+}
+
+
+sal_Int32 SAL_CALL OEvoabDriver::getMajorVersion( )
+{
+ return 1;
+}
+
+sal_Int32 SAL_CALL OEvoabDriver::getMinorVersion( )
+{
+ return 0;
+}
+
+bool OEvoabDriver::acceptsURL_Stat( std::u16string_view url )
+{
+ return ( url == u"sdbc:address:evolution:local" || url == u"sdbc:address:evolution:groupwise" || url == u"sdbc:address:evolution:ldap" ) && EApiInit();
+}
+
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+connectivity_OEvoabDriver_get_implementation(
+ css::uno::XComponentContext* context , css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new OEvoabDriver(context));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/evoab2/NDriver.hxx b/connectivity/source/drivers/evoab2/NDriver.hxx
new file mode 100644
index 0000000000..b505bb9db5
--- /dev/null
+++ b/connectivity/source/drivers/evoab2/NDriver.hxx
@@ -0,0 +1,74 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <string_view>
+
+#include <com/sun/star/sdbc/XDriver.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <cppuhelper/compbase.hxx>
+#include <connectivity/CommonTools.hxx>
+
+inline constexpr OUString EVOAB_DRIVER_IMPL_NAME = u"com.sun.star.comp.sdbc.evoab.OEvoabDriver"_ustr;
+
+namespace connectivity::evoab
+ {
+ typedef ::cppu::WeakComponentImplHelper< css::sdbc::XDriver,
+ css::lang::XServiceInfo > ODriver_BASE;
+
+
+ class OEvoabDriver final : public ODriver_BASE
+ {
+ ::osl::Mutex m_aMutex;
+ connectivity::OWeakRefArray m_xConnections;
+ css::uno::Reference< css::uno::XComponentContext > m_xContext;
+
+ public:
+ explicit OEvoabDriver(const css::uno::Reference< css::uno::XComponentContext >& );
+ virtual ~OEvoabDriver() override;
+
+ // OComponentHelper
+ virtual void SAL_CALL disposing() override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+
+ // XDriver
+ virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL connect( const OUString& url, const css::uno::Sequence< css::beans::PropertyValue >& info ) override;
+ virtual sal_Bool SAL_CALL acceptsURL( const OUString& url ) override;
+ virtual css::uno::Sequence< css::sdbc::DriverPropertyInfo > SAL_CALL getPropertyInfo( const OUString& url, const css::uno::Sequence< css::beans::PropertyValue >& info ) override;
+ virtual sal_Int32 SAL_CALL getMajorVersion( ) override;
+ virtual sal_Int32 SAL_CALL getMinorVersion( ) override;
+
+ public:
+ const css::uno::Reference< css::uno::XComponentContext >& getComponentContext( ) const { return m_xContext; }
+
+ // static methods
+ static bool acceptsURL_Stat( std::u16string_view url );
+ };
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/evoab2/NPreparedStatement.cxx b/connectivity/source/drivers/evoab2/NPreparedStatement.cxx
new file mode 100644
index 0000000000..7738bfa4a3
--- /dev/null
+++ b/connectivity/source/drivers/evoab2/NPreparedStatement.cxx
@@ -0,0 +1,319 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include "NPreparedStatement.hxx"
+#include <connectivity/dbexception.hxx>
+#include <connectivity/dbtools.hxx>
+#include <rtl/ref.hxx>
+#include <comphelper/diagnose_ex.hxx>
+
+#include <strings.hrc>
+
+using namespace connectivity::evoab;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::sdbc;
+using namespace com::sun::star::container;
+using namespace com::sun::star::io;
+using namespace com::sun::star::util;
+
+IMPLEMENT_SERVICE_INFO(OEvoabPreparedStatement,"com.sun.star.sdbcx.evoab.PreparedStatement","com.sun.star.sdbc.PreparedStatement");
+
+
+OEvoabPreparedStatement::OEvoabPreparedStatement( OEvoabConnection* _pConnection )
+ :OCommonStatement(_pConnection)
+{
+}
+
+
+void OEvoabPreparedStatement::construct( const OUString& _sql )
+{
+ m_sSqlStatement = _sql;
+
+ m_aQueryData = impl_getEBookQuery_throw( m_sSqlStatement );
+ ENSURE_OR_THROW( m_aQueryData.getQuery(), "no EBookQuery" );
+ ENSURE_OR_THROW( m_aQueryData.xSelectColumns.is(), "no SelectColumn" );
+
+ // create our meta data
+ rtl::Reference<OEvoabResultSetMetaData> pMeta
+ = new OEvoabResultSetMetaData( m_aQueryData.sTable );
+ m_xMetaData = pMeta;
+ pMeta->setEvoabFields( m_aQueryData.xSelectColumns );
+}
+
+
+OEvoabPreparedStatement::~OEvoabPreparedStatement()
+{
+}
+
+
+void SAL_CALL OEvoabPreparedStatement::acquire() noexcept
+{
+ OCommonStatement::acquire();
+}
+
+
+void SAL_CALL OEvoabPreparedStatement::release() noexcept
+{
+ OCommonStatement::release();
+}
+
+
+Any SAL_CALL OEvoabPreparedStatement::queryInterface( const Type & rType )
+{
+ Any aRet = OCommonStatement::queryInterface(rType);
+ if(!aRet.hasValue())
+ aRet = OPreparedStatement_BASE::queryInterface(rType);
+ return aRet;
+}
+
+Sequence< Type > SAL_CALL OEvoabPreparedStatement::getTypes( )
+{
+ return ::comphelper::concatSequences(OPreparedStatement_BASE::getTypes(),OCommonStatement::getTypes());
+}
+
+
+Reference< XResultSetMetaData > SAL_CALL OEvoabPreparedStatement::getMetaData( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OCommonStatement_IBase::rBHelper.bDisposed);
+
+ // the meta data should have been created at construction time
+ ENSURE_OR_THROW( m_xMetaData.is(), "internal error: no meta data" );
+ return m_xMetaData;
+}
+
+
+void SAL_CALL OEvoabPreparedStatement::close( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OCommonStatement_IBase::rBHelper.bDisposed);
+
+ free_column_resources();
+ // Reset last warning message
+ try {
+ clearWarnings ();
+ OCommonStatement::close();
+ }
+ catch (SQLException &) {
+ // If we get an error, ignore
+ }
+
+}
+
+
+sal_Bool SAL_CALL OEvoabPreparedStatement::execute( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OCommonStatement_IBase::rBHelper.bDisposed);
+
+ Reference< XResultSet> xRS = impl_executeQuery_throw( m_aQueryData );
+ return xRS.is();
+}
+
+
+sal_Int32 SAL_CALL OEvoabPreparedStatement::executeUpdate( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OCommonStatement_IBase::rBHelper.bDisposed);
+ ::dbtools::throwFeatureNotImplementedSQLException( "XStatement::executeUpdate", *this );
+ return 0;
+}
+
+
+void SAL_CALL OEvoabPreparedStatement::setString( sal_Int32 /*parameterIndex*/, const OUString& /*x*/ )
+{
+ ::dbtools::throwFunctionNotSupportedSQLException( "XParameters::setString", *this );
+}
+
+
+Reference< XConnection > SAL_CALL OEvoabPreparedStatement::getConnection( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OCommonStatement_IBase::rBHelper.bDisposed);
+
+ return impl_getConnection();
+}
+
+
+Reference< XResultSet > SAL_CALL OEvoabPreparedStatement::executeQuery( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OCommonStatement_IBase::rBHelper.bDisposed);
+
+ return impl_executeQuery_throw( m_aQueryData );
+}
+
+
+void SAL_CALL OEvoabPreparedStatement::setBoolean( sal_Int32 /*parameterIndex*/, sal_Bool /*x*/ )
+{
+ ::dbtools::throwFunctionNotSupportedSQLException( "XParameters::setBoolean", *this );
+
+}
+
+void SAL_CALL OEvoabPreparedStatement::setByte( sal_Int32 /*parameterIndex*/, sal_Int8 /*x*/ )
+{
+ ::dbtools::throwFunctionNotSupportedSQLException( "XParameters::setByte", *this );
+}
+
+
+void SAL_CALL OEvoabPreparedStatement::setDate( sal_Int32 /*parameterIndex*/, const Date& /*aData*/ )
+{
+ ::dbtools::throwFunctionNotSupportedSQLException( "XParameters::setDate", *this );
+}
+
+
+void SAL_CALL OEvoabPreparedStatement::setTime( sal_Int32 /*parameterIndex*/, const css::util::Time& /*aVal*/ )
+{
+ ::dbtools::throwFunctionNotSupportedSQLException( "XParameters::setTime", *this );
+}
+
+
+void SAL_CALL OEvoabPreparedStatement::setTimestamp( sal_Int32 /*parameterIndex*/, const DateTime& /*aVal*/ )
+{
+ ::dbtools::throwFunctionNotSupportedSQLException( "XParameters::setTimestamp", *this );
+}
+
+
+void SAL_CALL OEvoabPreparedStatement::setDouble( sal_Int32 /*parameterIndex*/, double /*x*/ )
+{
+ ::dbtools::throwFunctionNotSupportedSQLException( "XParameters::setDouble", *this );
+}
+
+
+void SAL_CALL OEvoabPreparedStatement::setFloat( sal_Int32 /*parameterIndex*/, float /*x*/ )
+{
+ ::dbtools::throwFunctionNotSupportedSQLException( "XParameters::setFloat", *this );
+}
+
+
+void SAL_CALL OEvoabPreparedStatement::setInt( sal_Int32 /*parameterIndex*/, sal_Int32 /*x*/ )
+{
+ ::dbtools::throwFunctionNotSupportedSQLException( "XParameters::setInt", *this );
+}
+
+
+void SAL_CALL OEvoabPreparedStatement::setLong( sal_Int32 /*parameterIndex*/, sal_Int64 /*aVal*/ )
+{
+ ::dbtools::throwFunctionNotSupportedSQLException( "XParameters::setLong", *this );
+}
+
+
+void SAL_CALL OEvoabPreparedStatement::setNull( sal_Int32 /*parameterIndex*/, sal_Int32 /*sqlType*/ )
+{
+ ::dbtools::throwFunctionNotSupportedSQLException( "XParameters::setNull", *this );
+}
+
+
+void SAL_CALL OEvoabPreparedStatement::setClob( sal_Int32 /*parameterIndex*/, const Reference< XClob >& /*x*/ )
+{
+ ::dbtools::throwFunctionNotSupportedSQLException( "XParameters::setClob", *this );
+}
+
+
+void SAL_CALL OEvoabPreparedStatement::setBlob( sal_Int32 /*parameterIndex*/, const Reference< XBlob >& /*x*/ )
+{
+ ::dbtools::throwFunctionNotSupportedSQLException( "XParameters::setBlob", *this );
+}
+
+
+void SAL_CALL OEvoabPreparedStatement::setArray( sal_Int32 /*parameterIndex*/, const Reference< XArray >& /*x*/ )
+{
+ ::dbtools::throwFunctionNotSupportedSQLException( "XParameters::setArray", *this );
+}
+
+
+void SAL_CALL OEvoabPreparedStatement::setRef( sal_Int32 /*parameterIndex*/, const Reference< XRef >& /*x*/ )
+{
+ ::dbtools::throwFunctionNotSupportedSQLException( "XParameters::setRef", *this );
+}
+
+
+void SAL_CALL OEvoabPreparedStatement::setObjectWithInfo( sal_Int32 /*parameterIndex*/, const Any& /*x*/, sal_Int32 /*sqlType*/, sal_Int32 /*scale*/ )
+{
+ ::dbtools::throwFunctionNotSupportedSQLException( "XParameters::setObjectWithInfo", *this );
+}
+
+
+void SAL_CALL OEvoabPreparedStatement::setObjectNull( sal_Int32 /*parameterIndex*/, sal_Int32 /*sqlType*/, const OUString& /*typeName*/ )
+{
+ ::dbtools::throwFunctionNotSupportedSQLException( "XParameters::setObjectNull", *this );
+}
+
+
+void SAL_CALL OEvoabPreparedStatement::setObject( sal_Int32 parameterIndex, const Any& x )
+{
+ if(!::dbtools::implSetObject(this,parameterIndex,x))
+ {
+ const OUString sError( getOwnConnection()->getResources().getResourceStringWithSubstitution(
+ STR_UNKNOWN_PARA_TYPE,
+ "$position$", OUString::number(parameterIndex)
+ ) );
+ ::dbtools::throwGenericSQLException(sError,*this);
+ }
+}
+
+
+void SAL_CALL OEvoabPreparedStatement::setShort( sal_Int32 /*parameterIndex*/, sal_Int16 /*x*/ )
+{
+ ::dbtools::throwFunctionNotSupportedSQLException( "XParameters::setShort", *this );
+}
+
+
+void SAL_CALL OEvoabPreparedStatement::setBytes( sal_Int32 /*parameterIndex*/, const Sequence< sal_Int8 >& /*x*/ )
+{
+ ::dbtools::throwFunctionNotSupportedSQLException( "XParameters::setBytes", *this );
+}
+
+
+void SAL_CALL OEvoabPreparedStatement::setCharacterStream( sal_Int32 /*parameterIndex*/, const Reference< XInputStream >& /*x*/, sal_Int32 /*length*/ )
+{
+ ::dbtools::throwFunctionNotSupportedSQLException( "XParameters::setCharacterStream", *this );
+}
+
+
+void SAL_CALL OEvoabPreparedStatement::setBinaryStream( sal_Int32 /*parameterIndex*/, const Reference< XInputStream >& /*x*/, sal_Int32 /*length*/ )
+{
+ ::dbtools::throwFunctionNotSupportedSQLException( "XParameters::setBinaryStream", *this );
+}
+
+
+void SAL_CALL OEvoabPreparedStatement::clearParameters( )
+{
+}
+
+Reference< XResultSet > SAL_CALL OEvoabPreparedStatement::getResultSet( )
+{
+ return nullptr;
+}
+
+sal_Int32 SAL_CALL OEvoabPreparedStatement::getUpdateCount( )
+{
+ return 0;
+}
+
+sal_Bool SAL_CALL OEvoabPreparedStatement::getMoreResults( )
+{
+ return false;
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/evoab2/NPreparedStatement.hxx b/connectivity/source/drivers/evoab2/NPreparedStatement.hxx
new file mode 100644
index 0000000000..cd42d42d50
--- /dev/null
+++ b/connectivity/source/drivers/evoab2/NPreparedStatement.hxx
@@ -0,0 +1,108 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "NStatement.hxx"
+#include "NConnection.hxx"
+#include "NDatabaseMetaData.hxx"
+#include "NResultSet.hxx"
+#include <com/sun/star/sdbc/XPreparedStatement.hpp>
+#include <com/sun/star/sdbc/XParameters.hpp>
+#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
+#include <com/sun/star/sdbc/XPreparedBatchExecution.hpp>
+#include <com/sun/star/io/XInputStream.hpp>
+#include <cppuhelper/implbase5.hxx>
+
+namespace connectivity::evoab
+{
+
+ typedef ::cppu::ImplHelper5< css::sdbc::XPreparedStatement,
+ css::sdbc::XParameters,
+ css::sdbc::XResultSetMetaDataSupplier,
+ css::sdbc::XMultipleResults,
+ css::lang::XServiceInfo> OPreparedStatement_BASE;
+
+ class OEvoabPreparedStatement final:public OCommonStatement
+ ,public OPreparedStatement_BASE
+ {
+ // our SQL statement
+ OUString m_sSqlStatement;
+ // the EBookQuery we're working with
+ QueryData m_aQueryData;
+ // our meta data
+ css::uno::Reference< css::sdbc::XResultSetMetaData > m_xMetaData;
+
+ virtual ~OEvoabPreparedStatement() override;
+
+ public:
+ explicit OEvoabPreparedStatement( OEvoabConnection* _pConnection );
+
+ void construct( const OUString& _sql );
+
+ DECLARE_SERVICE_INFO();
+ //XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+ //XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override;
+
+ // XPreparedStatement
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL executeQuery( ) override;
+ virtual sal_Int32 SAL_CALL executeUpdate( ) override;
+ virtual sal_Bool SAL_CALL execute( ) override;
+ virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL getConnection( ) override;
+ // XParameters
+ virtual void SAL_CALL setNull( sal_Int32 parameterIndex, sal_Int32 sqlType ) override;
+ virtual void SAL_CALL setObjectNull( sal_Int32 parameterIndex, sal_Int32 sqlType, const OUString& typeName ) override;
+ virtual void SAL_CALL setBoolean( sal_Int32 parameterIndex, sal_Bool x ) override;
+ virtual void SAL_CALL setByte( sal_Int32 parameterIndex, sal_Int8 x ) override;
+ virtual void SAL_CALL setShort( sal_Int32 parameterIndex, sal_Int16 x ) override;
+ virtual void SAL_CALL setInt( sal_Int32 parameterIndex, sal_Int32 x ) override;
+ virtual void SAL_CALL setLong( sal_Int32 parameterIndex, sal_Int64 x ) override;
+ virtual void SAL_CALL setFloat( sal_Int32 parameterIndex, float x ) override;
+ virtual void SAL_CALL setDouble( sal_Int32 parameterIndex, double x ) override;
+ virtual void SAL_CALL setString( sal_Int32 parameterIndex, const OUString& x ) override;
+ virtual void SAL_CALL setBytes( sal_Int32 parameterIndex, const css::uno::Sequence< sal_Int8 >& x ) override;
+ virtual void SAL_CALL setDate( sal_Int32 parameterIndex, const css::util::Date& x ) override;
+ virtual void SAL_CALL setTime( sal_Int32 parameterIndex, const css::util::Time& x ) override;
+ virtual void SAL_CALL setTimestamp( sal_Int32 parameterIndex, const css::util::DateTime& x ) override;
+ virtual void SAL_CALL setBinaryStream( sal_Int32 parameterIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override;
+ virtual void SAL_CALL setCharacterStream( sal_Int32 parameterIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override;
+ virtual void SAL_CALL setObject( sal_Int32 parameterIndex, const css::uno::Any& x ) override;
+ virtual void SAL_CALL setObjectWithInfo( sal_Int32 parameterIndex, const css::uno::Any& x, sal_Int32 targetSqlType, sal_Int32 scale ) override;
+ virtual void SAL_CALL setRef( sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XRef >& x ) override;
+ virtual void SAL_CALL setBlob( sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XBlob >& x ) override;
+ virtual void SAL_CALL setClob( sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XClob >& x ) override;
+ virtual void SAL_CALL setArray( sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XArray >& x ) override;
+ virtual void SAL_CALL clearParameters( ) override;
+ // XCloseable
+ virtual void SAL_CALL close( ) override;
+ // XResultSetMetaDataSupplier
+ virtual css::uno::Reference< css::sdbc::XResultSetMetaData > SAL_CALL getMetaData( ) override;
+ // XMultipleResults
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getResultSet( ) override;
+ virtual sal_Int32 SAL_CALL getUpdateCount( ) override;
+ virtual sal_Bool SAL_CALL getMoreResults( ) override;
+ };
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/evoab2/NResultSet.cxx b/connectivity/source/drivers/evoab2/NResultSet.cxx
new file mode 100644
index 0000000000..043be2553f
--- /dev/null
+++ b/connectivity/source/drivers/evoab2/NResultSet.cxx
@@ -0,0 +1,1036 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include "NDatabaseMetaData.hxx"
+#include "NConnection.hxx"
+#include "NResultSet.hxx"
+#include <propertyids.hxx>
+#include <strings.hrc>
+
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/sdb/ErrorCondition.hpp>
+#include <com/sun/star/sdbc/FetchDirection.hpp>
+#include <com/sun/star/sdbc/ResultSetConcurrency.hpp>
+#include <com/sun/star/sdbc/ResultSetType.hpp>
+
+#include <comphelper/sequence.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <connectivity/dbexception.hxx>
+#include <connectivity/sqlerror.hxx>
+#include <rtl/string.hxx>
+#include <sal/log.hxx>
+#include <comphelper/diagnose_ex.hxx>
+#include <unotools/syslocale.hxx>
+#include <unotools/intlwrapper.hxx>
+#include <unotools/collatorwrapper.hxx>
+
+#include <cstring>
+
+namespace connectivity::evoab {
+
+using namespace ::comphelper;
+using namespace com::sun::star;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::sdbc;
+using namespace com::sun::star::sdbcx;
+using namespace com::sun::star::container;
+using namespace com::sun::star::io;
+namespace ErrorCondition = ::com::sun::star::sdb::ErrorCondition;
+
+
+OUString SAL_CALL OEvoabResultSet::getImplementationName( )
+{
+ return "com.sun.star.sdbcx.evoab.ResultSet";
+}
+
+ Sequence< OUString > SAL_CALL OEvoabResultSet::getSupportedServiceNames( )
+{
+ return { "com.sun.star.sdbc.ResultSet" };
+}
+
+sal_Bool SAL_CALL OEvoabResultSet::supportsService( const OUString& _rServiceName )
+{
+ return cppu::supportsService(this, _rServiceName);
+}
+
+struct ComparisonData
+{
+ const SortDescriptor& rSortOrder;
+ IntlWrapper aIntlWrapper;
+
+ ComparisonData(const SortDescriptor& _rSortOrder)
+ : rSortOrder(_rSortOrder)
+ , aIntlWrapper(SvtSysLocale().GetUILanguageTag())
+ {
+ }
+};
+
+static OUString
+valueToOUString( GValue& _rValue )
+{
+ const char *pStr = g_value_get_string( &_rValue );
+ std::string_view aStr( pStr ? pStr : "" );
+ OUString sResult( OStringToOUString( aStr, RTL_TEXTENCODING_UTF8 ) );
+ g_value_unset( &_rValue );
+ return sResult;
+}
+
+static bool
+valueToBool( GValue& _rValue )
+{
+ bool bResult = g_value_get_boolean( &_rValue );
+ g_value_unset( &_rValue );
+ return bResult;
+}
+
+static int
+whichAddress(int value)
+{
+ int fieldEnum;
+ switch (value)
+ {
+ case HOME_ADDR_LINE1:
+ case HOME_ADDR_LINE2:
+ case HOME_CITY:
+ case HOME_STATE:
+ case HOME_COUNTRY:
+ case HOME_ZIP:
+ fieldEnum = e_contact_field_id("address_home");
+ break;
+
+ case WORK_ADDR_LINE1:
+ case WORK_ADDR_LINE2:
+ case WORK_CITY:
+ case WORK_STATE:
+ case WORK_COUNTRY:
+ case WORK_ZIP:
+ fieldEnum = e_contact_field_id("address_work");
+ break;
+
+ case OTHER_ADDR_LINE1:
+ case OTHER_ADDR_LINE2:
+ case OTHER_CITY:
+ case OTHER_STATE:
+ case OTHER_COUNTRY:
+ case OTHER_ZIP:
+ fieldEnum = e_contact_field_id("address_other");
+ break;
+
+ default: fieldEnum = e_contact_field_id("address_home");
+ }
+ return fieldEnum;
+}
+
+/*
+* This function decides the default column values based on the first field of EContactAddress.
+* The search order is Work->Home->other(defaults).
+*/
+static EContactAddress *
+getDefaultContactAddress( EContact *pContact,int *value )
+{
+ EContactAddress *ec = static_cast<EContactAddress *>(e_contact_get(pContact,whichAddress(WORK_ADDR_LINE1)));
+ if ( ec && (ec->street[0]!='\0') )
+ {
+ *value= *value +WORK_ADDR_LINE1 -1;
+ return ec;
+ }
+ else
+ {
+ ec = static_cast<EContactAddress *>(e_contact_get(pContact,whichAddress(HOME_ADDR_LINE1)));
+ if ( ec && (ec->street[0]!='\0') )
+ {
+ *value=*value+HOME_ADDR_LINE1-1;
+ return ec;
+ }
+ }
+
+ *value=*value+OTHER_ADDR_LINE1-1;
+ return static_cast<EContactAddress *>(e_contact_get(pContact,whichAddress(OTHER_ADDR_LINE1)));
+}
+
+static EContactAddress*
+getContactAddress( EContact *pContact, int * address_enum )
+{
+ EContactAddress *ec = nullptr;
+ switch (*address_enum) {
+
+ case DEFAULT_ADDR_LINE1:
+ case DEFAULT_ADDR_LINE2:
+ case DEFAULT_CITY:
+ case DEFAULT_STATE:
+ case DEFAULT_COUNTRY:
+ case DEFAULT_ZIP:
+ ec = getDefaultContactAddress(pContact,address_enum);break;
+ default:
+ ec = static_cast<EContactAddress *>(e_contact_get(pContact,whichAddress(*address_enum)));
+ }
+ return ec;
+}
+
+static bool
+handleSplitAddress( EContact *pContact,GValue *pStackValue, int value )
+{
+ EContactAddress *ec = getContactAddress(pContact,&value) ;
+
+ if (ec==nullptr)
+ return true;
+
+ switch (value) {
+ case WORK_ADDR_LINE1:
+ g_value_set_string(pStackValue,ec->street ); break;
+ case WORK_ADDR_LINE2:
+ g_value_set_string(pStackValue,ec->po ); break;
+ case WORK_CITY:
+ g_value_set_string(pStackValue,ec->locality ); break;
+ case WORK_STATE:
+ g_value_set_string(pStackValue,ec->region ); break;
+ case WORK_COUNTRY:
+ g_value_set_string(pStackValue,ec->country ); break;
+ case WORK_ZIP:
+ g_value_set_string(pStackValue,ec->code ); break;
+
+ case HOME_ADDR_LINE1:
+ g_value_set_string(pStackValue,ec->street ); break;
+ case HOME_ADDR_LINE2:
+ g_value_set_string(pStackValue,ec->po ); break;
+ case HOME_CITY:
+ g_value_set_string(pStackValue,ec->locality ); break;
+ case HOME_STATE:
+ g_value_set_string(pStackValue,ec->region ); break;
+ case HOME_COUNTRY:
+ g_value_set_string(pStackValue,ec->country ); break;
+ case HOME_ZIP:
+ g_value_set_string(pStackValue,ec->code ); break;
+
+ case OTHER_ADDR_LINE1:
+ g_value_set_string(pStackValue,ec->street ); break;
+ case OTHER_ADDR_LINE2:
+ g_value_set_string(pStackValue,ec->po ); break;
+ case OTHER_CITY:
+ g_value_set_string(pStackValue,ec->locality ); break;
+ case OTHER_STATE:
+ g_value_set_string(pStackValue,ec->region ); break;
+ case OTHER_COUNTRY:
+ g_value_set_string(pStackValue,ec->country ); break;
+ case OTHER_ZIP:
+ g_value_set_string(pStackValue,ec->code ); break;
+
+ }
+
+ return false;
+}
+
+static bool
+getValue( EContact* pContact, sal_Int32 nColumnNum, GType nType, GValue* pStackValue, bool& _out_rWasNull )
+{
+ const ColumnProperty * pSpecs = evoab::getField( nColumnNum );
+ if ( !pSpecs )
+ return false;
+
+ GParamSpec* pSpec = pSpecs->pField;
+ bool bIsSplittedColumn = pSpecs->bIsSplittedValue;
+
+ _out_rWasNull = true;
+ if ( !pSpec || !pContact)
+ return false;
+
+ if ( G_PARAM_SPEC_VALUE_TYPE (pSpec) != nType )
+ {
+ SAL_WARN("connectivity.evoab2", "Wrong type (0x" << std::hex << static_cast<int>(G_PARAM_SPEC_VALUE_TYPE(pSpec)) << ") (0x"
+ << std::hex << static_cast<int>(nType) << ") " << (pSpec->name ? pSpec->name : "<noname>"));
+ return false;
+ }
+
+ g_value_init( pStackValue, nType );
+ if ( bIsSplittedColumn )
+ {
+ const SplitEvoColumns* evo_addr( get_evo_addr() );
+ for (int i=0;i<OTHER_ZIP;i++)
+ {
+ if (0 == strcmp (g_param_spec_get_name (pSpec), evo_addr[i].pColumnName))
+ {
+ _out_rWasNull = handleSplitAddress( pContact, pStackValue, evo_addr[i].value );
+ return true;
+ }
+ }
+ }
+ else
+ {
+ g_object_get_property( G_OBJECT (pContact),
+ g_param_spec_get_name (pSpec),
+ pStackValue );
+ if ( G_VALUE_TYPE( pStackValue ) != nType )
+ {
+ SAL_WARN("connectivity.evoab2", "Fetched type mismatch" );
+ g_value_unset( pStackValue );
+ return false;
+ }
+ }
+ _out_rWasNull = false;
+ return true;
+}
+
+extern "C" {
+
+static int CompareContacts( gconstpointer _lhs, gconstpointer _rhs, gpointer _userData )
+{
+ EContact* lhs = const_cast< gpointer >( _lhs );
+ EContact* rhs = const_cast< gpointer >( _rhs );
+
+ GValue aLhsValue = { 0, { { 0 } } };
+ GValue aRhsValue = { 0, { { 0 } } };
+ bool bLhsNull = true;
+ bool bRhsNull = true;
+
+ OUString sLhs, sRhs;
+ bool bLhs(false), bRhs(false);
+
+ const ComparisonData& rCompData = *static_cast< const ComparisonData* >( _userData );
+ for ( const auto& sortCol : rCompData.rSortOrder )
+ {
+ sal_Int32 nField = sortCol.nField;
+ int nOrder = 1;
+ // if descending sort, reverse order
+ if (!sortCol.bAscending)
+ nOrder = -1;
+ GType eFieldType = evoab::getGFieldType( nField );
+
+ bool success = getValue( lhs, nField, eFieldType, &aLhsValue, bLhsNull )
+ && getValue( rhs, nField, eFieldType, &aRhsValue, bRhsNull );
+ OSL_ENSURE( success, "CompareContacts: could not retrieve both values!" );
+ if ( !success )
+ return 0;
+
+ if ( bLhsNull && !bRhsNull )
+ return -1 * nOrder;
+ if ( !bLhsNull && bRhsNull )
+ return 1 * nOrder;
+ if ( bLhsNull && bRhsNull )
+ continue;
+
+ if ( eFieldType == G_TYPE_STRING )
+ {
+ sLhs = valueToOUString( aLhsValue );
+ sRhs = valueToOUString( aRhsValue );
+ sal_Int32 nCompResult = rCompData.aIntlWrapper.getCaseCollator()->compareString( sLhs, sRhs );
+ if ( nCompResult != 0 )
+ return nCompResult * nOrder;
+ continue;
+ }
+
+ bLhs = valueToBool( aLhsValue );
+ bRhs = valueToBool( aRhsValue );
+ if ( bLhs && !bRhs )
+ return -1 * nOrder;
+ if ( !bLhs && bRhs )
+ return 1 * nOrder;
+ continue;
+ }
+
+ return 0;
+}
+
+}
+
+OString OEvoabVersionHelper::getUserName( EBook *pBook )
+{
+ OString aName;
+ if( isLDAP( pBook ) )
+ aName = e_source_get_property( e_book_get_source( pBook ), "binddn" );
+ else
+ aName = e_source_get_property( e_book_get_source( pBook ), "user" );
+ return aName;
+}
+
+namespace {
+
+bool isBookBackend( EBookClient *pBook, const char *backendname)
+{
+ if (!pBook)
+ return false;
+ ESource *pSource = e_client_get_source (reinterpret_cast<EClient *>(pBook));
+ return isSourceBackend(pSource, backendname);
+}
+
+class OEvoabVersion36Helper : public OEvoabVersionHelper
+{
+private:
+ GSList *m_pContacts;
+public:
+ OEvoabVersion36Helper()
+ : m_pContacts(nullptr)
+ {
+ }
+
+ virtual ~OEvoabVersion36Helper() override
+ {
+ freeContacts();
+ }
+
+ virtual EBook* openBook(const char *abname) override
+ {
+ //It would be better if here we had id to begin with, see
+ //NDatabaseMetaData.cxx
+ const char *id = nullptr;
+ GList *pSources = e_source_registry_list_sources(get_e_source_registry(), E_SOURCE_EXTENSION_ADDRESS_BOOK);
+ for (GList* liter = pSources; liter; liter = liter->next)
+ {
+ ESource *pSource = E_SOURCE (liter->data);
+
+ if (strcmp(abname, e_source_get_display_name( pSource )) == 0)
+ {
+ id = e_source_get_uid( pSource );
+ break;
+ }
+ }
+ g_list_foreach (pSources, reinterpret_cast<GFunc>(g_object_unref), nullptr);
+ g_list_free (pSources);
+ if (!id)
+ return nullptr;
+
+ ESource *pSource = e_source_registry_ref_source(get_e_source_registry(), id);
+ EBookClient *pBook = pSource ? createClient (pSource) : nullptr;
+ if (pBook && !e_client_open_sync (pBook, true, nullptr, nullptr))
+ {
+ g_object_unref (G_OBJECT (pBook));
+ pBook = nullptr;
+ }
+ if (pSource)
+ g_object_unref (pSource);
+ return pBook;
+ }
+
+ virtual bool isLDAP( EBook *pBook ) override
+ {
+ return isBookBackend(pBook, "ldap");
+ }
+
+ virtual bool isLocal( EBook *pBook ) override
+ {
+ return isBookBackend(pBook, "local");
+ }
+
+ virtual void freeContacts() override final
+ {
+ e_client_util_free_object_slist(m_pContacts);
+ m_pContacts = nullptr;
+ }
+
+ virtual void executeQuery (EBook* pBook, EBookQuery* pQuery) override
+ {
+ freeContacts();
+ char *sexp = e_book_query_to_string( pQuery );
+ e_book_client_get_contacts_sync( pBook, sexp, &m_pContacts, nullptr, nullptr );
+ g_free (sexp);
+ }
+
+ virtual EContact *getContact(sal_Int32 nIndex) override
+ {
+ gpointer pData = g_slist_nth_data (m_pContacts, nIndex);
+ return pData ? E_CONTACT (pData) : nullptr;
+ }
+
+ virtual sal_Int32 getNumContacts() override
+ {
+ return g_slist_length( m_pContacts );
+ }
+
+ virtual bool hasContacts() override
+ {
+ return m_pContacts != nullptr;
+ }
+
+ virtual void sortContacts( const ComparisonData& _rCompData ) override
+ {
+ OSL_ENSURE( !_rCompData.rSortOrder.empty(), "sortContacts: no need to call this without any sort order!" );
+ ENSURE_OR_THROW( _rCompData.aIntlWrapper.getCaseCollator(), "no collator for comparing strings" );
+
+ m_pContacts = g_slist_sort_with_data( m_pContacts, &CompareContacts,
+ const_cast< gpointer >( static_cast< gconstpointer >( &_rCompData ) ) );
+ }
+
+protected:
+ virtual EBookClient * createClient( ESource *pSource )
+ {
+ return e_book_client_new (pSource, nullptr);
+ }
+};
+
+class OEvoabVersion38Helper : public OEvoabVersion36Helper
+{
+protected:
+ virtual EBookClient * createClient( ESource *pSource ) override
+ {
+ return e_book_client_connect_direct_sync (get_e_source_registry (), pSource, 10, nullptr, nullptr);
+ }
+};
+
+}
+
+OEvoabResultSet::OEvoabResultSet( OCommonStatement* pStmt, OEvoabConnection *pConnection )
+ :OResultSet_BASE(m_aMutex)
+ ,::comphelper::OPropertyContainer( OResultSet_BASE::rBHelper )
+ ,m_pStatement(pStmt)
+ ,m_pConnection(pConnection)
+ ,m_bWasNull(true)
+ ,m_nFetchSize(0)
+ ,m_nResultSetType(ResultSetType::SCROLL_INSENSITIVE)
+ ,m_nFetchDirection(FetchDirection::FORWARD)
+ ,m_nResultSetConcurrency(ResultSetConcurrency::READ_ONLY)
+ ,m_nIndex(-1)
+ ,m_nLength(0)
+{
+ m_pVersionHelper = std::make_unique<OEvoabVersion38Helper>();
+
+ registerProperty(
+ OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHSIZE),
+ PROPERTY_ID_FETCHSIZE,
+ PropertyAttribute::READONLY,
+ &m_nFetchSize,
+ cppu::UnoType<decltype(m_nFetchSize)>::get()
+ );
+ registerProperty(
+ OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETTYPE),
+ PROPERTY_ID_RESULTSETTYPE,
+ PropertyAttribute::READONLY,
+ &m_nResultSetType,
+ cppu::UnoType<decltype(m_nResultSetType)>::get()
+ );
+ registerProperty(
+ OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHDIRECTION),
+ PROPERTY_ID_FETCHDIRECTION,
+ PropertyAttribute::READONLY,
+ &m_nFetchDirection,
+ cppu::UnoType<decltype(m_nFetchDirection)>::get()
+ );
+ registerProperty(
+ OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETCONCURRENCY),
+ PROPERTY_ID_RESULTSETCONCURRENCY,
+ PropertyAttribute::READONLY,
+ &m_nResultSetConcurrency,
+ cppu::UnoType<decltype(m_nResultSetConcurrency)>::get()
+ );
+}
+
+OEvoabResultSet::~OEvoabResultSet()
+{}
+
+void OEvoabResultSet::construct( const QueryData& _rData )
+{
+ ENSURE_OR_THROW( _rData.getQuery(), "internal error: no EBookQuery" );
+
+ EBook *pBook = m_pVersionHelper->openBook(OUStringToOString(_rData.sTable, RTL_TEXTENCODING_UTF8).getStr());
+ if ( !pBook )
+ m_pConnection->throwGenericSQLException( STR_CANNOT_OPEN_BOOK, *this );
+
+ m_pVersionHelper->freeContacts();
+ bool bExecuteQuery = true;
+ switch ( _rData.eFilterType )
+ {
+ case eFilterNone:
+ if ( !m_pVersionHelper->isLocal( pBook ) )
+ {
+ SQLError aErrorFactory;
+ SQLException aAsException = aErrorFactory.getSQLException( ErrorCondition::DATA_CANNOT_SELECT_UNFILTERED, *this );
+ m_aWarnings.appendWarning( SQLWarning(
+ aAsException.Message,
+ aAsException.Context,
+ aAsException.SQLState,
+ aAsException.ErrorCode,
+ aAsException.NextException
+ ) );
+ bExecuteQuery = false;
+ }
+ break;
+ case eFilterAlwaysFalse:
+ bExecuteQuery = false;
+ break;
+ case eFilterOther:
+ bExecuteQuery = true;
+ break;
+ }
+ if ( bExecuteQuery )
+ {
+ m_pVersionHelper->executeQuery(pBook, _rData.getQuery());
+
+ if ( m_pVersionHelper->hasContacts() && !_rData.aSortOrder.empty() )
+ {
+ ComparisonData aCompData(_rData.aSortOrder);
+ m_pVersionHelper->sortContacts(aCompData);
+ }
+ }
+ m_nLength = m_pVersionHelper->getNumContacts();
+ SAL_INFO("connectivity.evoab2", "Query return " << m_nLength << " records");
+ m_nIndex = -1;
+
+ // create our meta data (need the EBookQuery for this)
+ m_xMetaData = new OEvoabResultSetMetaData( _rData.sTable );
+
+ m_xMetaData->setEvoabFields( _rData.xSelectColumns );
+}
+
+
+void OEvoabResultSet::disposing()
+{
+ ::comphelper::OPropertyContainer::disposing();
+
+ ::osl::MutexGuard aGuard(m_aMutex);
+ m_pVersionHelper.reset();
+ m_pStatement = nullptr;
+ m_xMetaData.clear();
+}
+
+Any SAL_CALL OEvoabResultSet::queryInterface( const Type & rType )
+{
+ Any aRet = ::comphelper::OPropertyContainer::queryInterface(rType);
+ if(!aRet.hasValue())
+ aRet = OResultSet_BASE::queryInterface(rType);
+ return aRet;
+}
+
+Sequence< Type > SAL_CALL OEvoabResultSet::getTypes( )
+{
+ return ::comphelper::concatSequences(
+ OResultSet_BASE::getTypes(),
+ getBaseTypes()
+ );
+}
+
+
+// XRow Interface
+
+/**
+ * getString:
+ * @nColumnNum: The column index from the table.
+ *
+ * If the equivalent NResultSetMetaData.cxx marks the columntype of
+ * nColumnNum as DataType::VARCHAR this accessor is used.
+ */
+OUString SAL_CALL OEvoabResultSet::getString( sal_Int32 nColumnNum )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+ OUString aResult;
+ if ( m_xMetaData.is())
+ {
+ sal_Int32 nFieldNumber = m_xMetaData->fieldAtColumn(nColumnNum);
+ GValue aValue = { 0, { { 0 } } };
+ if ( getValue( getCur(), nFieldNumber, G_TYPE_STRING, &aValue, m_bWasNull ) )
+ aResult = valueToOUString( aValue );
+ }
+ return aResult;
+}
+
+sal_Bool SAL_CALL OEvoabResultSet::getBoolean( sal_Int32 nColumnNum )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+ bool bResult = false;
+
+ if ( m_xMetaData.is())
+ {
+ sal_Int32 nFieldNumber = m_xMetaData->fieldAtColumn(nColumnNum);
+ GValue aValue = { 0, { { 0 } } };
+ if ( getValue( getCur(), nFieldNumber, G_TYPE_BOOLEAN, &aValue, m_bWasNull ) )
+ bResult = valueToBool( aValue );
+ }
+ return bResult;
+}
+
+sal_Int64 SAL_CALL OEvoabResultSet::getLong( sal_Int32 /*nColumnNum*/ )
+{
+ ::dbtools::throwFunctionNotSupportedSQLException( "XRow::getLong", *this );
+ return sal_Int64();
+}
+
+Reference< XArray > SAL_CALL OEvoabResultSet::getArray( sal_Int32 /*nColumnNum*/ )
+{
+ ::dbtools::throwFunctionNotSupportedSQLException( "XRow::getArray", *this );
+ return nullptr;
+}
+
+Reference< XClob > SAL_CALL OEvoabResultSet::getClob( sal_Int32 /*nColumnNum*/ )
+{
+ ::dbtools::throwFunctionNotSupportedSQLException( "XRow::getClob", *this );
+ return nullptr;
+}
+
+Reference< XBlob > SAL_CALL OEvoabResultSet::getBlob( sal_Int32 /*nColumnNum*/ )
+{
+ ::dbtools::throwFunctionNotSupportedSQLException( "XRow::getBlob", *this );
+ return nullptr;
+}
+
+Reference< XRef > SAL_CALL OEvoabResultSet::getRef( sal_Int32 /*nColumnNum*/ )
+{
+ ::dbtools::throwFunctionNotSupportedSQLException( "XRow::getRef", *this );
+ return nullptr;
+}
+
+Any SAL_CALL OEvoabResultSet::getObject( sal_Int32 /*nColumnNum*/, const Reference< css::container::XNameAccess >& /*typeMap*/ )
+{
+ ::dbtools::throwFunctionNotSupportedSQLException( "XRow::getObject", *this );
+ return Any();
+}
+
+sal_Int16 SAL_CALL OEvoabResultSet::getShort( sal_Int32 /*nColumnNum*/ )
+{
+ ::dbtools::throwFunctionNotSupportedSQLException( "XRow::getShort", *this );
+ return 0;
+}
+
+css::util::Time SAL_CALL OEvoabResultSet::getTime( sal_Int32 /*nColumnNum*/ )
+{
+ ::dbtools::throwFunctionNotSupportedSQLException( "XRow::getTime", *this );
+ return css::util::Time();
+}
+
+util::DateTime SAL_CALL OEvoabResultSet::getTimestamp( sal_Int32 /*nColumnNum*/ )
+{
+ ::dbtools::throwFunctionNotSupportedSQLException( "XRow::getTimestamp", *this );
+ return css::util::DateTime();
+}
+
+Reference< XInputStream > SAL_CALL OEvoabResultSet::getBinaryStream( sal_Int32 /*nColumnNum*/ )
+{
+ ::dbtools::throwFunctionNotSupportedSQLException( "XRow::getBinaryStream", *this );
+ return nullptr;
+}
+
+Reference< XInputStream > SAL_CALL OEvoabResultSet::getCharacterStream( sal_Int32 /*nColumnNum*/ )
+{
+ ::dbtools::throwFunctionNotSupportedSQLException( "XRow::getCharacterStream", *this );
+ return nullptr;
+}
+
+sal_Int8 SAL_CALL OEvoabResultSet::getByte( sal_Int32 /*nColumnNum*/ )
+{
+ ::dbtools::throwFunctionNotSupportedSQLException( "XRow::getByte", *this );
+ return 0;
+}
+
+Sequence< sal_Int8 > SAL_CALL OEvoabResultSet::getBytes( sal_Int32 /*nColumnNum*/ )
+{
+ ::dbtools::throwFunctionNotSupportedSQLException( "XRow::getBytes", *this );
+ return Sequence< sal_Int8 >();
+}
+
+css::util::Date SAL_CALL OEvoabResultSet::getDate( sal_Int32 /*nColumnNum*/ )
+{
+ ::dbtools::throwFunctionNotSupportedSQLException( "XRow::getDate", *this );
+ return css::util::Date();
+}
+
+double SAL_CALL OEvoabResultSet::getDouble( sal_Int32 /*nColumnNum*/ )
+{
+ ::dbtools::throwFunctionNotSupportedSQLException( "XRow::getDouble", *this );
+ return 0;
+}
+
+float SAL_CALL OEvoabResultSet::getFloat( sal_Int32 /*nColumnNum*/ )
+{
+ ::dbtools::throwFunctionNotSupportedSQLException( "XRow::getFloat", *this );
+ return 0;
+}
+
+sal_Int32 SAL_CALL OEvoabResultSet::getInt( sal_Int32 /*nColumnNum*/ )
+{
+ ::dbtools::throwFunctionNotSupportedSQLException( "XRow::getInt", *this );
+ return 0;
+}
+// XRow Interface Ends
+
+
+// XResultSetMetaDataSupplier Interface
+Reference< XResultSetMetaData > SAL_CALL OEvoabResultSet::getMetaData( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ // the meta data should have been created at construction time
+ ENSURE_OR_THROW( m_xMetaData.is(), "internal error: no meta data" );
+ return m_xMetaData;
+}
+// XResultSetMetaDataSupplier Interface Ends
+
+
+// XResultSet Interface
+sal_Bool SAL_CALL OEvoabResultSet::next( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+ if (m_nIndex+1 < m_nLength) {
+ ++m_nIndex ;
+ return true;
+ }
+ else
+ return false;
+}
+
+sal_Bool SAL_CALL OEvoabResultSet::wasNull( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ return m_bWasNull;
+}
+
+sal_Bool SAL_CALL OEvoabResultSet::isBeforeFirst( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ return m_nIndex < 0;
+}
+
+sal_Int32 SAL_CALL OEvoabResultSet::getRow( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ return m_nIndex;
+}
+
+sal_Bool SAL_CALL OEvoabResultSet::isAfterLast( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ return m_nIndex >= m_nLength;
+}
+
+sal_Bool SAL_CALL OEvoabResultSet::isFirst( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ return m_nIndex == 0;
+}
+
+sal_Bool SAL_CALL OEvoabResultSet::isLast( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ return m_nIndex == m_nLength - 1;
+}
+
+void SAL_CALL OEvoabResultSet::beforeFirst( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ m_nIndex = -1;
+}
+
+void SAL_CALL OEvoabResultSet::afterLast( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ m_nIndex = m_nLength;
+}
+
+
+sal_Bool SAL_CALL OEvoabResultSet::first( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ m_nIndex = 0;
+ return true;
+}
+
+
+sal_Bool SAL_CALL OEvoabResultSet::last( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ m_nIndex = m_nLength - 1;
+ return true;
+}
+
+sal_Bool SAL_CALL OEvoabResultSet::absolute( sal_Int32 row )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+ if (row < m_nLength) {
+ m_nIndex = row;
+ return true;
+ }
+ else
+ return false;
+}
+
+sal_Bool SAL_CALL OEvoabResultSet::relative( sal_Int32 row )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ if ((m_nIndex+row) < m_nLength) {
+ m_nIndex += row;
+ return true;
+ }
+ else
+ return false;
+}
+
+sal_Bool SAL_CALL OEvoabResultSet::previous( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ if(m_nIndex > 0) {
+ m_nIndex--;
+ return true;
+ }
+ else
+ return false;
+}
+
+Reference< XInterface > SAL_CALL OEvoabResultSet::getStatement( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+ return cppu::getXWeak(m_pStatement);
+}
+
+
+sal_Bool SAL_CALL OEvoabResultSet::rowDeleted( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ return false;
+}
+
+sal_Bool SAL_CALL OEvoabResultSet::rowInserted( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ return false;
+}
+
+sal_Bool SAL_CALL OEvoabResultSet::rowUpdated( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ return false;
+}
+
+void SAL_CALL OEvoabResultSet::refreshRow( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+}
+//XResult Interface ends
+
+// XCancellable
+
+void SAL_CALL OEvoabResultSet::cancel( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+}
+
+//XCloseable
+void SAL_CALL OEvoabResultSet::close( )
+{
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+ }
+ dispose();
+}
+
+// XWarningsSupplier
+
+void SAL_CALL OEvoabResultSet::clearWarnings( )
+{
+ m_aWarnings.clearWarnings();
+}
+
+Any SAL_CALL OEvoabResultSet::getWarnings( )
+{
+ return m_aWarnings.getWarnings();
+}
+
+//XColumnLocate Interface
+sal_Int32 SAL_CALL OEvoabResultSet::findColumn( const OUString& columnName )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ // find the first column with the name columnName
+ Reference< XResultSetMetaData > xMeta = getMetaData();
+ sal_Int32 nLen = xMeta->getColumnCount();
+ sal_Int32 i = 1;
+ for(;i<=nLen;++i)
+ {
+ if(xMeta->isCaseSensitive(i) ? columnName == xMeta->getColumnName(i) :
+ columnName.equalsIgnoreAsciiCase(xMeta->getColumnName(i)))
+ return i;
+ }
+
+ ::dbtools::throwInvalidColumnException( columnName, *this );
+ assert(false);
+ return 0; // Never reached
+}
+
+//XColumnLocate interface ends
+
+
+::cppu::IPropertyArrayHelper* OEvoabResultSet::createArrayHelper( ) const
+{
+ Sequence< Property > aProps;
+ describeProperties( aProps );
+ return new ::cppu::OPropertyArrayHelper( aProps );
+}
+
+::cppu::IPropertyArrayHelper & OEvoabResultSet::getInfoHelper()
+{
+ return *getArrayHelper();
+}
+
+void SAL_CALL OEvoabResultSet::acquire() noexcept
+{
+ OResultSet_BASE::acquire();
+}
+
+void SAL_CALL OEvoabResultSet::release() noexcept
+{
+ OResultSet_BASE::release();
+}
+
+css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL
+OEvoabResultSet::getPropertySetInfo( )
+{
+ return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper());
+}
+
+
+} // connectivity::evoab
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/evoab2/NResultSet.hxx b/connectivity/source/drivers/evoab2/NResultSet.hxx
new file mode 100644
index 0000000000..3eeeab244a
--- /dev/null
+++ b/connectivity/source/drivers/evoab2/NResultSet.hxx
@@ -0,0 +1,182 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <memory>
+
+#include <com/sun/star/sdbc/XResultSet.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
+#include <com/sun/star/sdbc/XCloseable.hpp>
+#include <com/sun/star/sdbc/XColumnLocate.hpp>
+#include <com/sun/star/util/XCancellable.hpp>
+#include <com/sun/star/sdbc/XWarningsSupplier.hpp>
+#include <com/sun/star/sdbc/XResultSetUpdate.hpp>
+#include <com/sun/star/sdbc/XRowUpdate.hpp>
+#include <com/sun/star/sdbcx/XRowLocate.hpp>
+#include <com/sun/star/sdbcx/XDeleteRows.hpp>
+#include <cppuhelper/compbase.hxx>
+#include <comphelper/proparrhlp.hxx>
+#include <comphelper/propertycontainer.hxx>
+#include <connectivity/CommonTools.hxx>
+#include <connectivity/FValue.hxx>
+#include <connectivity/warningscontainer.hxx>
+#include "NStatement.hxx"
+#include "NResultSetMetaData.hxx"
+
+namespace connectivity::evoab
+{
+ struct ComparisonData;
+
+ class OEvoabVersionHelper
+ {
+ public:
+ virtual EBook* openBook(const char *abname) = 0;
+ virtual void executeQuery (EBook* pBook, EBookQuery* pQuery) = 0;
+ virtual void freeContacts() = 0;
+ virtual bool isLDAP( EBook *pBook ) = 0;
+ virtual bool isLocal( EBook *pBook ) = 0;
+ virtual EContact *getContact(sal_Int32 nIndex) = 0;
+ virtual sal_Int32 getNumContacts() = 0;
+ virtual bool hasContacts() = 0;
+ virtual void sortContacts( const ComparisonData& _rCompData ) = 0;
+ OString getUserName( EBook *pBook );
+ virtual ~OEvoabVersionHelper() {}
+ };
+
+ typedef ::cppu::WeakComponentImplHelper< css::sdbc::XResultSet
+ , css::sdbc::XRow
+ , css::sdbc::XResultSetMetaDataSupplier
+ , css::util::XCancellable
+ , css::sdbc::XWarningsSupplier
+ , css::sdbc::XCloseable
+ , css::sdbc::XColumnLocate
+ , css::lang::XServiceInfo
+ > OResultSet_BASE;
+
+
+ class OEvoabResultSet final : public cppu::BaseMutex
+ ,public OResultSet_BASE
+ ,public ::comphelper::OPropertyContainer
+ ,public ::comphelper::OPropertyArrayUsageHelper<OEvoabResultSet>
+ {
+ private:
+ std::unique_ptr<OEvoabVersionHelper> m_pVersionHelper;
+
+ OCommonStatement* m_pStatement;
+ OEvoabConnection* m_pConnection;
+ rtl::Reference<OEvoabResultSetMetaData> m_xMetaData;
+ ::dbtools::WarningsContainer m_aWarnings;
+
+ bool m_bWasNull;
+ // <properties>
+ sal_Int32 m_nFetchSize;
+ sal_Int32 m_nResultSetType;
+ sal_Int32 m_nFetchDirection;
+ sal_Int32 m_nResultSetConcurrency;
+ // </properties>
+
+ // Data & iteration
+ sal_Int32 m_nIndex;
+ sal_Int32 m_nLength;
+ EContact *getCur()
+ {
+ return m_pVersionHelper->getContact(m_nIndex);
+ }
+
+ // OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override;
+ // OPropertySetHelper
+ virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override;
+
+ // you can't delete objects of this type
+ virtual ~OEvoabResultSet() override;
+ public:
+ DECLARE_SERVICE_INFO();
+
+ OEvoabResultSet( OCommonStatement *pStmt, OEvoabConnection *pConnection );
+ void construct( const QueryData& _rData );
+
+ // ::cppu::OComponentHelper
+ virtual void SAL_CALL disposing() override;
+ // XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+ //XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override;
+ // XPropertySet
+ virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override;
+ // XResultSet
+ virtual sal_Bool SAL_CALL next( ) override;
+ virtual sal_Bool SAL_CALL isBeforeFirst( ) override;
+ virtual sal_Bool SAL_CALL isAfterLast( ) override;
+ virtual sal_Bool SAL_CALL isFirst( ) override;
+ virtual sal_Bool SAL_CALL isLast( ) override;
+ virtual void SAL_CALL beforeFirst( ) override;
+ virtual void SAL_CALL afterLast( ) override;
+ virtual sal_Bool SAL_CALL first( ) override;
+ virtual sal_Bool SAL_CALL last( ) override;
+ virtual sal_Int32 SAL_CALL getRow( ) override;
+ virtual sal_Bool SAL_CALL absolute( sal_Int32 row ) override;
+ virtual sal_Bool SAL_CALL relative( sal_Int32 rows ) override;
+ virtual sal_Bool SAL_CALL previous( ) override;
+ virtual void SAL_CALL refreshRow( ) override;
+ virtual sal_Bool SAL_CALL rowUpdated( ) override;
+ virtual sal_Bool SAL_CALL rowInserted( ) override;
+ virtual sal_Bool SAL_CALL rowDeleted( ) override;
+ virtual css::uno::Reference< css::uno::XInterface > SAL_CALL getStatement( ) override;
+ // XRow
+ virtual sal_Bool SAL_CALL wasNull( ) override;
+ virtual OUString SAL_CALL getString( sal_Int32 columnIndex ) override;
+ virtual sal_Bool SAL_CALL getBoolean( sal_Int32 columnIndex ) override;
+ virtual sal_Int8 SAL_CALL getByte( sal_Int32 columnIndex ) override;
+ virtual sal_Int16 SAL_CALL getShort( sal_Int32 columnIndex ) override;
+ virtual sal_Int32 SAL_CALL getInt( sal_Int32 columnIndex ) override;
+ virtual sal_Int64 SAL_CALL getLong( sal_Int32 columnIndex ) override;
+ virtual float SAL_CALL getFloat( sal_Int32 columnIndex ) override;
+ virtual double SAL_CALL getDouble( sal_Int32 columnIndex ) override;
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getBytes( sal_Int32 columnIndex ) override;
+ virtual css::util::Date SAL_CALL getDate( sal_Int32 columnIndex ) override;
+ virtual css::util::Time SAL_CALL getTime( sal_Int32 columnIndex ) override;
+ virtual css::util::DateTime SAL_CALL getTimestamp( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getBinaryStream( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getCharacterStream( sal_Int32 columnIndex ) override;
+ virtual css::uno::Any SAL_CALL getObject( sal_Int32 columnIndex, const css::uno::Reference< css::container::XNameAccess >& typeMap ) override;
+ virtual css::uno::Reference< css::sdbc::XRef > SAL_CALL getRef( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XBlob > SAL_CALL getBlob( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XClob > SAL_CALL getClob( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XArray > SAL_CALL getArray( sal_Int32 columnIndex ) override;
+ // XCancellable
+ virtual void SAL_CALL cancel( ) override;
+ // XCloseable
+ virtual void SAL_CALL close( ) override;
+ // XResultSetMetaDataSupplier
+ virtual css::uno::Reference< css::sdbc::XResultSetMetaData > SAL_CALL getMetaData( ) override;
+ // XWarningsSupplier
+ virtual css::uno::Any SAL_CALL getWarnings( ) override;
+ virtual void SAL_CALL clearWarnings( ) override;
+ // XColumnLocate
+ virtual sal_Int32 SAL_CALL findColumn( const OUString& columnName ) override;
+ };
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/evoab2/NResultSetMetaData.cxx b/connectivity/source/drivers/evoab2/NResultSetMetaData.cxx
new file mode 100644
index 0000000000..338d4e397d
--- /dev/null
+++ b/connectivity/source/drivers/evoab2/NResultSetMetaData.cxx
@@ -0,0 +1,175 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "NResultSetMetaData.hxx"
+#include "NDatabaseMetaData.hxx"
+#include <connectivity/dbexception.hxx>
+#include <strings.hrc>
+#include <utility>
+
+using namespace connectivity::evoab;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::sdbc;
+
+OEvoabResultSetMetaData::OEvoabResultSetMetaData(OUString _aTableName)
+ : m_aTableName(std::move(_aTableName))
+{
+
+}
+
+OEvoabResultSetMetaData::~OEvoabResultSetMetaData()
+{
+}
+
+void OEvoabResultSetMetaData::setEvoabFields(const ::rtl::Reference<connectivity::OSQLColumns> &xColumns)
+{
+ static constexpr OUStringLiteral aName = u"Name";
+
+ for (const auto& rxColumn : *xColumns)
+ {
+ OUString aFieldName;
+
+ rxColumn->getPropertyValue(aName) >>= aFieldName;
+ guint nFieldNumber = findEvoabField(aFieldName);
+ if (nFieldNumber == guint(-1))
+ {
+ connectivity::SharedResources aResource;
+ const OUString sError( aResource.getResourceStringWithSubstitution(
+ STR_INVALID_COLUMNNAME,
+ "$columnname$", aFieldName
+ ) );
+ ::dbtools::throwGenericSQLException( sError, *this );
+ }
+ m_aEvoabFields.push_back(nFieldNumber);
+ }
+}
+
+
+sal_Int32 SAL_CALL OEvoabResultSetMetaData::getColumnDisplaySize( sal_Int32 /*nColumnNum*/ )
+{
+ return 50;
+}
+
+sal_Int32 SAL_CALL OEvoabResultSetMetaData::getColumnType( sal_Int32 nColumnNum )
+{
+ sal_uInt32 nField = m_aEvoabFields[nColumnNum - 1];
+ return evoab::getFieldType (nField);
+}
+
+sal_Int32 SAL_CALL OEvoabResultSetMetaData::getColumnCount( )
+{
+ return m_aEvoabFields.size();
+}
+
+sal_Bool SAL_CALL OEvoabResultSetMetaData::isCaseSensitive( sal_Int32 /*nColumnNum*/ )
+{
+ return true;
+}
+
+OUString SAL_CALL OEvoabResultSetMetaData::getSchemaName( sal_Int32 /*nColumnNum*/ )
+{
+ return OUString();
+}
+
+OUString SAL_CALL OEvoabResultSetMetaData::getColumnName( sal_Int32 nColumnNum )
+{
+ sal_uInt32 nField = m_aEvoabFields[nColumnNum - 1];
+ return evoab::getFieldName( nField );
+}
+
+OUString SAL_CALL OEvoabResultSetMetaData::getColumnTypeName( sal_Int32 nColumnNum )
+{
+ sal_uInt32 nField = m_aEvoabFields[nColumnNum - 1];
+ return evoab::getFieldTypeName( nField );
+}
+
+OUString SAL_CALL OEvoabResultSetMetaData::getColumnLabel( sal_Int32 nColumnNum )
+{
+ return getColumnName(nColumnNum);
+}
+
+OUString SAL_CALL OEvoabResultSetMetaData::getColumnServiceName( sal_Int32 /*nColumnNum*/ )
+{
+ return OUString();
+}
+
+OUString SAL_CALL OEvoabResultSetMetaData::getTableName( sal_Int32 /*nColumnNum*/ )
+{
+ return m_aTableName;//OUString("TABLE");
+}
+
+OUString SAL_CALL OEvoabResultSetMetaData::getCatalogName( sal_Int32 /*nColumnNum*/ )
+{
+ return OUString();
+}
+
+
+sal_Bool SAL_CALL OEvoabResultSetMetaData::isCurrency( sal_Int32 /*nColumnNum*/ )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL OEvoabResultSetMetaData::isAutoIncrement( sal_Int32 /*nColumnNum*/ )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL OEvoabResultSetMetaData::isSigned( sal_Int32 /*nColumnNum*/ )
+{
+ return false;
+}
+
+sal_Int32 SAL_CALL OEvoabResultSetMetaData::getPrecision( sal_Int32 /*nColumnNum*/ )
+{
+ return 0;
+}
+
+sal_Int32 SAL_CALL OEvoabResultSetMetaData::getScale( sal_Int32 /*nColumnNum*/ )
+{
+ return 0;
+}
+
+sal_Int32 SAL_CALL OEvoabResultSetMetaData::isNullable( sal_Int32 /*nColumnNum*/ )
+{
+ return 0;
+}
+
+sal_Bool SAL_CALL OEvoabResultSetMetaData::isSearchable( sal_Int32 /*nColumnNum*/ )
+{
+ return true;
+}
+
+sal_Bool SAL_CALL OEvoabResultSetMetaData::isReadOnly( sal_Int32 /*nColumnNum*/ )
+{
+ return true;
+}
+
+sal_Bool SAL_CALL OEvoabResultSetMetaData::isDefinitelyWritable( sal_Int32 /*nColumnNum*/ )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL OEvoabResultSetMetaData::isWritable( sal_Int32 /*nColumnNum*/ )
+{
+ return false;
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/evoab2/NResultSetMetaData.hxx b/connectivity/source/drivers/evoab2/NResultSetMetaData.hxx
new file mode 100644
index 0000000000..e79d347b1c
--- /dev/null
+++ b/connectivity/source/drivers/evoab2/NResultSetMetaData.hxx
@@ -0,0 +1,77 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/sdbc/XResultSetMetaData.hpp>
+#include <cppuhelper/implbase.hxx>
+#include "NConnection.hxx"
+#include <rtl/ref.hxx>
+#include <com/sun/star/connection/XConnection.hpp>
+
+namespace connectivity::evoab
+{
+
+ //************ Class: ResultSetMetaData
+
+ typedef ::cppu::WeakImplHelper< css::sdbc::XResultSetMetaData> OResultSetMetaData_BASE;
+
+ class OEvoabResultSetMetaData : public OResultSetMetaData_BASE
+ {
+ OUString m_aTableName;
+ std::vector<sal_Int32> m_aEvoabFields;
+
+ protected:
+ virtual ~OEvoabResultSetMetaData() override;
+ public:
+ explicit OEvoabResultSetMetaData(OUString _aTableName);
+ /// @throws css::sdbc::SQLException
+ void setEvoabFields(const ::rtl::Reference<connectivity::OSQLColumns> &xColumns);
+ sal_uInt32 fieldAtColumn(sal_Int32 columnIndex) const
+ { return m_aEvoabFields[columnIndex - 1]; }
+ /// Avoid ambiguous cast error from the compiler.
+ operator css::uno::Reference< css::sdbc::XResultSetMetaData > () noexcept
+ { return this; }
+
+ virtual sal_Int32 SAL_CALL getColumnCount( ) override;
+ virtual sal_Bool SAL_CALL isAutoIncrement( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isCaseSensitive( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isSearchable( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isCurrency( sal_Int32 column ) override;
+ virtual sal_Int32 SAL_CALL isNullable( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isSigned( sal_Int32 column ) override;
+ virtual sal_Int32 SAL_CALL getColumnDisplaySize( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getColumnLabel( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getColumnName( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getSchemaName( sal_Int32 column ) override;
+ virtual sal_Int32 SAL_CALL getPrecision( sal_Int32 column ) override;
+ virtual sal_Int32 SAL_CALL getScale( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getTableName( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getCatalogName( sal_Int32 column ) override;
+ virtual sal_Int32 SAL_CALL getColumnType( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getColumnTypeName( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isReadOnly( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isWritable( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isDefinitelyWritable( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getColumnServiceName( sal_Int32 column ) override;
+ };
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/evoab2/NStatement.cxx b/connectivity/source/drivers/evoab2/NStatement.cxx
new file mode 100644
index 0000000000..2acfd427db
--- /dev/null
+++ b/connectivity/source/drivers/evoab2/NStatement.cxx
@@ -0,0 +1,682 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <string_view>
+
+#include <osl/diagnose.h>
+#include <rtl/ref.hxx>
+#include <rtl/ustring.hxx>
+#include <sal/log.hxx>
+#include <com/sun/star/sdbc/ResultSetConcurrency.hpp>
+#include <com/sun/star/sdbc/ResultSetType.hpp>
+#include <com/sun/star/sdbc/FetchDirection.hpp>
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <cppuhelper/typeprovider.hxx>
+#include <propertyids.hxx>
+#include "NStatement.hxx"
+#include "NConnection.hxx"
+#include "NDatabaseMetaData.hxx"
+#include "NResultSet.hxx"
+#include <sqlbison.hxx>
+#include <strings.hrc>
+#include <connectivity/dbexception.hxx>
+#include <comphelper/diagnose_ex.hxx>
+
+namespace connectivity::evoab {
+
+
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::sdbc;
+using namespace com::sun::star::sdbcx;
+using namespace com::sun::star::container;
+using namespace com::sun::star::io;
+using namespace com::sun::star::util;
+
+namespace {
+
+EBookQuery * createTrue()
+{ // Not the world's most efficient unconditional true but ...
+ return e_book_query_from_string("(exists \"full_name\")");
+}
+
+EBookQuery * createTest( std::u16string_view aColumnName,
+ EBookQueryTest eTest,
+ std::u16string_view aMatch )
+{
+ OString sMatch = OUStringToOString( aMatch, RTL_TEXTENCODING_UTF8 );
+ OString sColumnName = OUStringToOString( aColumnName, RTL_TEXTENCODING_UTF8 );
+
+ return e_book_query_field_test( e_contact_field_id( sColumnName.getStr() ),
+ eTest, sMatch.getStr() );
+}
+
+}
+
+OCommonStatement::OCommonStatement(OEvoabConnection* _pConnection)
+ : OCommonStatement_IBase(m_aMutex)
+ , ::comphelper::OPropertyContainer(OCommonStatement_IBase::rBHelper)
+ , m_xResultSet(nullptr)
+ , m_xConnection(_pConnection)
+ , m_aParser(_pConnection->getDriver().getComponentContext())
+ , m_aSQLIterator( _pConnection, _pConnection->createCatalog()->getTables(), m_aParser )
+ , m_pParseTree(nullptr)
+ , m_nMaxFieldSize(0)
+ , m_nMaxRows(0)
+ , m_nQueryTimeOut(0)
+ , m_nFetchSize(0)
+ , m_nResultSetType(ResultSetType::FORWARD_ONLY)
+ , m_nFetchDirection(FetchDirection::FORWARD)
+ , m_nResultSetConcurrency(ResultSetConcurrency::UPDATABLE)
+ , m_bEscapeProcessing(true)
+{
+ registerProperty(
+ OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_CURSORNAME),
+ PROPERTY_ID_CURSORNAME,
+ 0,
+ &m_aCursorName,
+ cppu::UnoType<decltype(m_aCursorName)>::get()
+ );
+ registerProperty(
+ OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_MAXFIELDSIZE),
+ PROPERTY_ID_MAXFIELDSIZE,
+ 0,
+ &m_nMaxFieldSize,
+ cppu::UnoType<decltype(m_nMaxFieldSize)>::get()
+ );
+ registerProperty(
+ OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_MAXROWS),
+ PROPERTY_ID_MAXROWS,
+ 0,
+ &m_nMaxRows,
+ cppu::UnoType<decltype(m_nMaxRows)>::get()
+ );
+ registerProperty(
+ OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_QUERYTIMEOUT),
+ PROPERTY_ID_QUERYTIMEOUT,
+ 0,
+ &m_nQueryTimeOut,
+ cppu::UnoType<decltype(m_nQueryTimeOut)>::get()
+ );
+ registerProperty(
+ OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHSIZE),
+ PROPERTY_ID_FETCHSIZE,
+ 0,
+ &m_nFetchSize,
+ cppu::UnoType<decltype(m_nFetchSize)>::get()
+ );
+ registerProperty(
+ OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETTYPE),
+ PROPERTY_ID_RESULTSETTYPE,
+ 0,
+ &m_nResultSetType,
+ cppu::UnoType<decltype(m_nResultSetType)>::get()
+ );
+ registerProperty(
+ OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHDIRECTION),
+ PROPERTY_ID_FETCHDIRECTION,
+ 0,
+ &m_nFetchDirection,
+ cppu::UnoType<decltype(m_nFetchDirection)>::get()
+ );
+ registerProperty(
+ OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ESCAPEPROCESSING),
+ PROPERTY_ID_ESCAPEPROCESSING,
+ 0,
+ &m_bEscapeProcessing,
+ cppu::UnoType<decltype(m_bEscapeProcessing)>::get()
+ );
+ registerProperty(
+ OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETCONCURRENCY),
+ PROPERTY_ID_RESULTSETCONCURRENCY,
+ 0,
+ &m_nResultSetConcurrency,
+ cppu::UnoType<decltype(m_nResultSetConcurrency)>::get()
+ );
+}
+
+OCommonStatement::~OCommonStatement()
+{
+}
+
+void OCommonStatement::disposeResultSet()
+{
+ // free the cursor if alive
+ Reference< XComponent > xComp(m_xResultSet.get(), UNO_QUERY);
+ if (xComp.is())
+ xComp->dispose();
+ m_xResultSet.clear();
+}
+
+void OCommonStatement::disposing()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+
+ disposeResultSet();
+
+ m_xConnection.clear();
+
+ OCommonStatement_IBase::disposing();
+}
+
+Any SAL_CALL OCommonStatement::queryInterface( const Type & rType )
+{
+ Any aRet = OCommonStatement_IBase::queryInterface(rType);
+ if(!aRet.hasValue())
+ aRet = ::comphelper::OPropertyContainer::queryInterface(rType);
+ return aRet;
+}
+
+Sequence< Type > SAL_CALL OCommonStatement::getTypes( )
+{
+ ::cppu::OTypeCollection aTypes( cppu::UnoType<XMultiPropertySet>::get(),
+ cppu::UnoType<XFastPropertySet>::get(),
+ cppu::UnoType<XPropertySet>::get());
+
+ return ::comphelper::concatSequences(aTypes.getTypes(),OCommonStatement_IBase::getTypes());
+}
+
+
+//void SAL_CALL OCommonStatement::cancel( ) throw(RuntimeException)
+//{
+//::osl::MutexGuard aGuard( m_aMutex );
+//checkDisposed(OCommonStatement_IBase::rBHelper.bDisposed);
+//// cancel the current sql statement
+//}
+
+
+void SAL_CALL OCommonStatement::close( )
+{
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OCommonStatement_IBase::rBHelper.bDisposed);
+
+ }
+ dispose();
+}
+
+OUString OCommonStatement::impl_getColumnRefColumnName_throw( const OSQLParseNode& _rColumnRef )
+{
+ ENSURE_OR_THROW( SQL_ISRULE( &_rColumnRef, column_ref ), "internal error: only column_refs supported as LHS" );
+
+ OUString sColumnName;
+ switch ( _rColumnRef.count() )
+ {
+ case 3: // SQL_TOKEN_NAME '.' column_val
+ {
+ const OSQLParseNode* pPunct = _rColumnRef.getChild( 1 );
+ const OSQLParseNode* pColVal = _rColumnRef.getChild( 2 );
+ if ( SQL_ISPUNCTUATION( pPunct, "." )
+ && ( pColVal->count() == 1 )
+ )
+ {
+ sColumnName = pColVal->getChild( 0 )->getTokenValue();
+ }
+ }
+ break;
+
+ case 1: // column
+ {
+ sColumnName = _rColumnRef.getChild( 0 )->getTokenValue();
+ }
+ break;
+ }
+
+ if ( !sColumnName.getLength() )
+ m_xConnection->throwGenericSQLException( STR_QUERY_TOO_COMPLEX, *this );
+
+ return sColumnName;
+}
+
+
+void OCommonStatement::orderByAnalysis( const OSQLParseNode* _pOrderByClause, SortDescriptor& _out_rSort )
+{
+ ENSURE_OR_THROW( _pOrderByClause, "NULL node" );
+ ENSURE_OR_THROW( SQL_ISRULE( _pOrderByClause, opt_order_by_clause ), "wrong node type" );
+
+ _out_rSort.clear();
+
+ const OSQLParseNode* pOrderList = _pOrderByClause->getByRule( OSQLParseNode::ordering_spec_commalist );
+ ENSURE_OR_THROW( pOrderList, "unexpected parse tree structure" );
+
+ for ( size_t i=0; i<pOrderList->count(); ++i )
+ {
+ const OSQLParseNode* pOrderBy = pOrderList->getChild(i);
+ if ( !pOrderBy || !SQL_ISRULE( pOrderBy, ordering_spec ) )
+ continue;
+ const OSQLParseNode* pColumnRef = pOrderBy->count() == 2 ? pOrderBy->getChild(0) : nullptr;
+ const OSQLParseNode* pAscDesc = pOrderBy->count() == 2 ? pOrderBy->getChild(1) : nullptr;
+ ENSURE_OR_THROW(
+ ( pColumnRef != nullptr )
+ && ( pAscDesc != nullptr )
+ && ( pAscDesc->isLeaf() )
+ && ( SQL_ISRULE( pAscDesc, opt_asc_desc )
+ || SQL_ISTOKEN(pAscDesc, ASC)
+ || SQL_ISTOKEN(pAscDesc, DESC)
+ ),
+ "ordering_spec structure error" );
+
+ // column name -> column field
+ if ( !SQL_ISRULE( pColumnRef, column_ref ) )
+ m_xConnection->throwGenericSQLException( STR_SORT_BY_COL_ONLY, *this );
+ const OUString sColumnName( impl_getColumnRefColumnName_throw( *pColumnRef ) );
+ guint nField = evoab::findEvoabField( sColumnName );
+ // ascending/descending?
+ bool bAscending = !SQL_ISTOKEN(pAscDesc, DESC);
+
+ _out_rSort.push_back( FieldSort( nField, bAscending ) );
+ }
+}
+
+
+EBookQuery *OCommonStatement::whereAnalysis( const OSQLParseNode* parseTree )
+{
+ EBookQuery *pResult = nullptr;
+
+ ENSURE_OR_THROW( parseTree, "invalid parse tree" );
+
+ // Nested brackets
+ if( parseTree->count() == 3 &&
+ SQL_ISPUNCTUATION( parseTree->getChild( 0 ), "(" ) &&
+ SQL_ISPUNCTUATION( parseTree->getChild( 2 ), ")" ) )
+ {
+ pResult = whereAnalysis( parseTree->getChild( 1 ) );
+ }
+
+ // SQL AND, OR
+ else if( ( SQL_ISRULE( parseTree, search_condition ) ||
+ SQL_ISRULE( parseTree, boolean_term ) ) &&
+ parseTree->count() == 3 )
+ {
+ ENSURE_OR_THROW( SQL_ISTOKEN( parseTree->getChild( 1 ), OR )
+ || SQL_ISTOKEN( parseTree->getChild( 1 ), AND ),
+ "unexpected search_condition structure" );
+
+ EBookQuery *pArgs[2];
+ pArgs[0] = whereAnalysis( parseTree->getChild( 0 ) );
+ pArgs[1] = whereAnalysis( parseTree->getChild( 2 ) );
+
+ if( SQL_ISTOKEN( parseTree->getChild( 1 ), OR ) )
+ pResult = e_book_query_or( 2, pArgs, true );
+ else
+ pResult = e_book_query_and( 2, pArgs, true );
+ }
+ // SQL =, !=
+ else if( SQL_ISRULE( parseTree, comparison_predicate ) )
+ {
+ OSQLParseNode *pPrec = parseTree->getChild( 1 );
+
+ ENSURE_OR_THROW( parseTree->count() == 3, "unexpected comparison_predicate structure" );
+
+ OSQLParseNode* pLHS = parseTree->getChild( 0 );
+ OSQLParseNode* pRHS = parseTree->getChild( 2 );
+
+ if ( ( ! SQL_ISRULE( pLHS, column_ref ) // on the LHS, we accept a column or a constant int value
+ && ( pLHS->getNodeType() != SQLNodeType::IntNum )
+ )
+ || ( ( pRHS->getNodeType() != SQLNodeType::String ) // on the RHS, certain literals are acceptable
+ && ( pRHS->getNodeType() != SQLNodeType::IntNum )
+ && ( pRHS->getNodeType() != SQLNodeType::ApproxNum )
+ && ! SQL_ISTOKEN( pRHS, TRUE )
+ && ! SQL_ISTOKEN( pRHS, FALSE )
+ )
+ || ( ( pLHS->getNodeType() == SQLNodeType::IntNum ) // an int on LHS requires an int on RHS
+ && ( pRHS->getNodeType() != SQLNodeType::IntNum )
+ )
+ )
+ {
+ m_xConnection->throwGenericSQLException( STR_QUERY_TOO_COMPLEX, *this );
+ }
+
+ if ( ( pPrec->getNodeType() != SQLNodeType::Equal )
+ && ( pPrec->getNodeType() != SQLNodeType::NotEqual )
+ )
+ {
+ m_xConnection->throwGenericSQLException( STR_OPERATOR_TOO_COMPLEX, *this );
+ }
+
+ // recognize the special "0 = 1" condition
+ if ( ( pLHS->getNodeType() == SQLNodeType::IntNum )
+ && ( pRHS->getNodeType() == SQLNodeType::IntNum )
+ && ( pPrec->getNodeType() == SQLNodeType::Equal )
+ )
+ {
+ const sal_Int32 nLHS = pLHS->getTokenValue().toInt64();
+ const sal_Int32 nRHS = pRHS->getTokenValue().toInt64();
+ return ( nLHS == nRHS ) ? createTrue() : nullptr;
+ }
+
+ OUString aColumnName( impl_getColumnRefColumnName_throw( *pLHS ) );
+
+ OUString aMatchString;
+ if ( pRHS->isToken() )
+ aMatchString = pRHS->getTokenValue();
+ else
+ aMatchString = pRHS->getChild( 0 )->getTokenValue();
+
+ pResult = createTest( aColumnName, E_BOOK_QUERY_IS, aMatchString );
+
+ if ( pResult && ( pPrec->getNodeType() == SQLNodeType::NotEqual ) )
+ pResult = e_book_query_not( pResult, true );
+ }
+ // SQL like
+ else if( SQL_ISRULE( parseTree, like_predicate ) )
+ {
+ ENSURE_OR_THROW( parseTree->count() == 2, "unexpected like_predicate structure" );
+ const OSQLParseNode* pPart2 = parseTree->getChild(1);
+
+ if( ! SQL_ISRULE( parseTree->getChild( 0 ), column_ref) )
+ m_xConnection->throwGenericSQLException(STR_QUERY_INVALID_LIKE_COLUMN,*this);
+
+ OUString aColumnName( impl_getColumnRefColumnName_throw( *parseTree->getChild( 0 ) ) );
+
+ OSQLParseNode *pAtom = pPart2->getChild( pPart2->count() - 2 ); // Match String
+ bool bNotLike = pPart2->getChild(0)->isToken();
+
+ if( !( pAtom->getNodeType() == SQLNodeType::String ||
+ pAtom->getNodeType() == SQLNodeType::Name ||
+ SQL_ISRULE( pAtom,parameter ) ||
+ ( pAtom->getChild( 0 ) && pAtom->getChild( 0 )->getNodeType() == SQLNodeType::Name ) ||
+ ( pAtom->getChild( 0 ) && pAtom->getChild( 0 )->getNodeType() == SQLNodeType::String ) ) )
+ {
+ SAL_INFO(
+ "connectivity.evoab2",
+ "analyseSQL : pAtom->count() = " << pAtom->count());
+ m_xConnection->throwGenericSQLException(STR_QUERY_INVALID_LIKE_STRING,*this);
+ }
+
+ const sal_Unicode WILDCARD = '%';
+
+ OUString aMatchString = pAtom->getTokenValue();
+
+ // Determine where '%' character is...
+ if( aMatchString == OUStringChar(WILDCARD) )
+ {
+ // String containing only a '%' and nothing else matches everything
+ pResult = createTest( aColumnName, E_BOOK_QUERY_CONTAINS,
+ u"" );
+ }
+ else if( aMatchString.indexOf( WILDCARD ) == -1 )
+ { // Simple string , eg. "to match" "contains in evo"
+ SAL_INFO( "connectivity.evoab2", "Plain contains '" << aMatchString << "'" );
+ pResult = createTest( aColumnName, E_BOOK_QUERY_CONTAINS, aMatchString );
+ if( pResult && bNotLike )
+ pResult = e_book_query_not( pResult, true );
+ }
+ else if( bNotLike )
+ {
+ // We currently can't handle a 'NOT LIKE' when there are '%'
+ m_xConnection->throwGenericSQLException(STR_QUERY_NOT_LIKE_TOO_COMPLEX,*this);
+ }
+ else if( aMatchString.indexOf ( WILDCARD ) == aMatchString.lastIndexOf ( WILDCARD ) )
+ { // One occurrence of '%' matches...
+ if ( aMatchString.startsWith(OUStringChar(WILDCARD)) )
+ pResult = createTest(
+ aColumnName, E_BOOK_QUERY_ENDS_WITH, aMatchString.subView( 1 ) );
+ else if ( aMatchString.indexOf ( WILDCARD ) == aMatchString.getLength() - 1 )
+ pResult = createTest( aColumnName, E_BOOK_QUERY_BEGINS_WITH, aMatchString.subView( 0, aMatchString.getLength() - 1 ) );
+ else
+ m_xConnection->throwGenericSQLException(STR_QUERY_LIKE_WILDCARD,*this);
+ }
+ else if( aMatchString.getLength() >= 3 &&
+ aMatchString.startsWith(OUStringChar(WILDCARD)) &&
+ aMatchString.indexOf ( WILDCARD, 1) == aMatchString.getLength() - 1 ) {
+ // one '%' at the start and another at the end
+ pResult = createTest( aColumnName, E_BOOK_QUERY_CONTAINS, aMatchString.subView (1, aMatchString.getLength() - 2) );
+ }
+ else
+ m_xConnection->throwGenericSQLException(STR_QUERY_LIKE_WILDCARD_MANY,*this);
+ }
+
+ return pResult;
+}
+
+OUString OCommonStatement::getTableName() const
+{
+ OUString aTableName;
+
+ if( m_pParseTree && m_aSQLIterator.getStatementType() == OSQLStatementType::Select )
+ {
+ Any aCatalog;
+ OUString aSchema;
+ const OSQLParseNode *pSelectStmnt = m_aSQLIterator.getParseTree();
+ const OSQLParseNode *pAllTableNames = pSelectStmnt->getChild( 3 )->getChild( 0 )->getChild( 1 );
+
+ if( OSQLParseTreeIterator::isTableNode( pAllTableNames->getChild( 0 ) ) )
+ OSQLParseNode::getTableComponents( pAllTableNames->getChild( 0 ),
+ aCatalog,aSchema, aTableName,nullptr );
+
+ else if( SQL_ISRULE( pAllTableNames->getChild( 0 ), table_ref ) )
+ {
+ OSQLParseNode *pNodeForTableName = pAllTableNames->getChild( 0 )->getChild( 0 );
+ if( OSQLParseTreeIterator::isTableNode( pNodeForTableName ) )
+ {
+ aTableName = OSQLParseNode::getTableRange(pAllTableNames->getChild( 0 ));
+ if( !aTableName.getLength() )
+ OSQLParseNode::getTableComponents( pNodeForTableName, aCatalog, aSchema, aTableName,nullptr);
+ }
+ else
+ OSL_FAIL( "odd table layout" );
+ }
+ else
+ OSL_FAIL( "unusual table layout" );
+ }
+ return aTableName;
+}
+
+void OCommonStatement::parseSql( const OUString& sql, QueryData& _out_rQueryData )
+{
+ SAL_INFO( "connectivity.evoab2", "parsing " << sql );
+
+ _out_rQueryData.eFilterType = eFilterOther;
+
+ OUString aErr;
+ m_pParseTree = m_aParser.parseTree( aErr, sql ).release();
+ m_aSQLIterator.setParseTree( m_pParseTree );
+ m_aSQLIterator.traverseAll();
+
+ _out_rQueryData.sTable = getTableName();
+
+ // to be sorted?
+ const OSQLParseNode* pOrderByClause = m_aSQLIterator.getOrderTree();
+ if ( pOrderByClause )
+ {
+ #if OSL_DEBUG_LEVEL > 1
+ OUString sTreeDebug;
+ pOrderByClause->showParseTree( sTreeDebug );
+ SAL_INFO( "connectivity.evoab2", "found order-by tree:\n" << sTreeDebug );
+ #endif
+
+ orderByAnalysis( pOrderByClause, _out_rQueryData.aSortOrder );
+ }
+
+ const OSQLParseNode* pWhereClause = m_aSQLIterator.getWhereTree();
+ if ( pWhereClause && SQL_ISRULE( pWhereClause, where_clause ) )
+ {
+ #if OSL_DEBUG_LEVEL > 1
+ OUString sTreeDebug;
+ pWhereClause->showParseTree( sTreeDebug );
+ SAL_INFO( "connectivity.evoab2", "found where tree:\n" << sTreeDebug );
+ #endif
+ EBookQuery* pQuery = whereAnalysis( pWhereClause->getChild( 1 ) );
+ if ( !pQuery )
+ {
+ _out_rQueryData.eFilterType = eFilterAlwaysFalse;
+ pQuery = createTrue();
+ }
+ _out_rQueryData.setQuery( pQuery );
+ }
+ else
+ {
+ _out_rQueryData.eFilterType = eFilterNone;
+ _out_rQueryData.setQuery( createTrue() );
+ }
+}
+
+
+Reference< XConnection > SAL_CALL OStatement::getConnection( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OCommonStatement_IBase::rBHelper.bDisposed);
+
+ // just return our connection here
+ return impl_getConnection();
+}
+
+
+Any SAL_CALL OCommonStatement::getWarnings( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OCommonStatement_IBase::rBHelper.bDisposed);
+
+
+ return Any(SQLWarning());
+}
+
+
+void SAL_CALL OCommonStatement::clearWarnings( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OCommonStatement_IBase::rBHelper.bDisposed);
+
+}
+
+::cppu::IPropertyArrayHelper* OCommonStatement::createArrayHelper( ) const
+{
+ Sequence< Property > aProps;
+ describeProperties( aProps );
+ return new ::cppu::OPropertyArrayHelper( aProps );
+}
+
+::cppu::IPropertyArrayHelper & OCommonStatement::getInfoHelper()
+{
+ return *getArrayHelper();
+}
+
+
+void SAL_CALL OCommonStatement::acquire() noexcept
+{
+ OCommonStatement_IBase::acquire();
+}
+
+void SAL_CALL OCommonStatement::release() noexcept
+{
+ OCommonStatement_IBase::release();
+}
+
+
+QueryData OCommonStatement::impl_getEBookQuery_throw( const OUString& _rSql )
+{
+ QueryData aData;
+ parseSql( _rSql, aData );
+
+#if OSL_DEBUG_LEVEL > 1
+ char *pSexpr = aData.getQuery() ? e_book_query_to_string( aData.getQuery() ) : g_strdup( "<map failed>" );
+ g_message( "Parsed SQL to sexpr '%s'\n", pSexpr );
+ g_free( pSexpr );
+#endif
+
+ if ( !aData.getQuery() )
+ m_xConnection->throwGenericSQLException( STR_QUERY_TOO_COMPLEX, *this );
+
+ // a postcondition of this method is that we properly determined the SELECT columns
+ aData.xSelectColumns = m_aSQLIterator.getSelectColumns();
+ if ( !aData.xSelectColumns.is() )
+ m_xConnection->throwGenericSQLException( STR_QUERY_TOO_COMPLEX, *this );
+
+ return aData;
+}
+
+
+Reference< XResultSet > OCommonStatement::impl_executeQuery_throw( const QueryData& _rQueryData )
+{
+ // create result set
+ rtl::Reference<OEvoabResultSet> pResult = new OEvoabResultSet( this, m_xConnection.get() );
+ pResult->construct( _rQueryData );
+
+ // done
+ m_xResultSet = Reference<XWeak>(pResult);
+ return pResult;
+}
+
+
+Reference< XResultSet > OCommonStatement::impl_executeQuery_throw( const OUString& _rSql )
+{
+ SAL_INFO( "connectivity.evoab2", "OCommonStatement::impl_executeQuery_throw " << _rSql );
+
+#if OSL_DEBUG_LEVEL > 1
+ g_message( "Parse SQL '%s'\n",
+ OUStringToOString(_rSql, RTL_TEXTENCODING_UTF8).getStr() );
+#endif
+
+ return impl_executeQuery_throw( impl_getEBookQuery_throw( _rSql ) );
+}
+
+
+Reference< XPropertySetInfo > SAL_CALL OCommonStatement::getPropertySetInfo( )
+{
+ return ::cppu::OPropertySetHelper::createPropertySetInfo( getInfoHelper() );
+}
+
+
+// = OStatement
+
+
+IMPLEMENT_SERVICE_INFO( OStatement, "com.sun.star.comp.sdbcx.evoab.OStatement", "com.sun.star.sdbc.Statement" );
+
+
+IMPLEMENT_FORWARD_XINTERFACE2( OStatement, OCommonStatement, OStatement_IBase )
+
+
+IMPLEMENT_FORWARD_XTYPEPROVIDER2( OStatement, OCommonStatement, OStatement_IBase )
+
+
+sal_Bool SAL_CALL OStatement::execute( const OUString& _sql )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OCommonStatement_IBase::rBHelper.bDisposed);
+
+ Reference< XResultSet > xRS = impl_executeQuery_throw( _sql );
+ return xRS.is();
+}
+
+
+Reference< XResultSet > SAL_CALL OStatement::executeQuery( const OUString& _sql )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OCommonStatement_IBase::rBHelper.bDisposed);
+
+ return impl_executeQuery_throw( _sql );
+}
+
+
+sal_Int32 SAL_CALL OStatement::executeUpdate( const OUString& /*sql*/ )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OCommonStatement_IBase::rBHelper.bDisposed);
+ ::dbtools::throwFeatureNotImplementedSQLException( "XStatement::executeUpdate", *this );
+ return 0;
+}
+
+} // namespace ::connectivity::evoab
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/evoab2/NStatement.hxx b/connectivity/source/drivers/evoab2/NStatement.hxx
new file mode 100644
index 0000000000..a348c5335d
--- /dev/null
+++ b/connectivity/source/drivers/evoab2/NStatement.hxx
@@ -0,0 +1,273 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/sdbc/XStatement.hpp>
+#include <com/sun/star/sdbc/XWarningsSupplier.hpp>
+#include <com/sun/star/sdbc/XMultipleResults.hpp>
+#include <com/sun/star/sdbc/XCloseable.hpp>
+#include <com/sun/star/sdbc/SQLWarning.hpp>
+#include <comphelper/proparrhlp.hxx>
+#include <cppuhelper/implbase2.hxx>
+#include <cppuhelper/basemutex.hxx>
+#include <comphelper/uno3.hxx>
+#include <connectivity/CommonTools.hxx>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <connectivity/sqliterator.hxx>
+#include <connectivity/sqlparse.hxx>
+#include <connectivity/FValue.hxx>
+#include <com/sun/star/util/XCancellable.hpp>
+#include <cppuhelper/compbase.hxx>
+#include <comphelper/propertycontainer.hxx>
+
+#include "EApi.h"
+#include "NConnection.hxx"
+
+#include <vector>
+
+namespace connectivity::evoab
+{
+ typedef ::cppu::WeakComponentImplHelper< css::sdbc::XWarningsSupplier
+ , css::sdbc::XCloseable
+ > OCommonStatement_IBase;
+
+ struct FieldSort
+ {
+ sal_Int32 nField;
+ bool bAscending;
+
+ FieldSort( const sal_Int32 _nField, const bool _bAscending ) : nField( _nField ), bAscending( _bAscending ) { }
+ };
+ typedef std::vector< FieldSort > SortDescriptor;
+
+ enum QueryFilterType
+ {
+ eFilterAlwaysFalse,
+ eFilterNone,
+ eFilterOther
+ };
+
+ class EBookQueryWrapper
+ {
+ private:
+ EBookQuery* mpQuery;
+ public:
+ EBookQueryWrapper()
+ : mpQuery(nullptr)
+ {
+ }
+ EBookQueryWrapper(const EBookQueryWrapper& rhs)
+ : mpQuery(rhs.mpQuery)
+ {
+ if (mpQuery)
+ e_book_query_ref(mpQuery);
+ }
+ EBookQueryWrapper(EBookQueryWrapper&& rhs) noexcept
+ : mpQuery(rhs.mpQuery)
+ {
+ rhs.mpQuery = nullptr;
+ }
+ void reset(EBookQuery* pQuery)
+ {
+ if (mpQuery)
+ e_book_query_unref(mpQuery);
+ mpQuery = pQuery;
+ if (mpQuery)
+ e_book_query_ref(mpQuery);
+ }
+ EBookQueryWrapper& operator=(const EBookQueryWrapper& rhs)
+ {
+ if (this != &rhs)
+ reset(rhs.mpQuery);
+ return *this;
+ }
+ EBookQueryWrapper& operator=(EBookQueryWrapper&& rhs)
+ {
+ if (mpQuery)
+ e_book_query_unref(mpQuery);
+ mpQuery = rhs.mpQuery;
+ rhs.mpQuery = nullptr;
+ return *this;
+ }
+ ~EBookQueryWrapper()
+ {
+ if (mpQuery)
+ e_book_query_unref(mpQuery);
+ }
+ EBookQuery* getQuery() const
+ {
+ return mpQuery;
+ }
+ };
+
+ struct QueryData
+ {
+ private:
+ EBookQueryWrapper aQuery;
+
+ public:
+ OUString sTable;
+ QueryFilterType eFilterType;
+ rtl::Reference<connectivity::OSQLColumns> xSelectColumns;
+ SortDescriptor aSortOrder;
+
+ QueryData()
+ : sTable()
+ , eFilterType( eFilterOther )
+ , xSelectColumns()
+ , aSortOrder()
+ {
+ }
+
+ EBookQuery* getQuery() const { return aQuery.getQuery(); }
+ void setQuery(EBookQuery* pQuery) { aQuery.reset(pQuery); }
+ };
+
+ //************ Class: OCommonStatement
+ // is a base class for the normal statement and for the prepared statement
+
+ class OCommonStatement :public cppu::BaseMutex
+ ,public OCommonStatement_IBase
+ ,public ::comphelper::OPropertyContainer
+ ,public ::comphelper::OPropertyArrayUsageHelper< OCommonStatement >
+ {
+ private:
+ css::uno::WeakReference< css::sdbc::XResultSet> m_xResultSet; // The last ResultSet created
+ rtl::Reference<OEvoabConnection> m_xConnection;
+ connectivity::OSQLParser m_aParser;
+ connectivity::OSQLParseTreeIterator m_aSQLIterator;
+ connectivity::OSQLParseNode *m_pParseTree;
+
+ // <properties>
+ OUString m_aCursorName;
+ sal_Int32 m_nMaxFieldSize;
+ sal_Int32 m_nMaxRows;
+ sal_Int32 m_nQueryTimeOut;
+ sal_Int32 m_nFetchSize;
+ sal_Int32 m_nResultSetType;
+ sal_Int32 m_nFetchDirection;
+ sal_Int32 m_nResultSetConcurrency;
+ bool m_bEscapeProcessing;
+ // </properties>
+
+ protected:
+
+ void disposeResultSet();
+
+ // OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper() const override;
+ // OPropertySetHelper
+ virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override;
+
+ virtual ~OCommonStatement() override;
+
+ protected:
+ void parseSql( const OUString& sql, QueryData& _out_rQueryData );
+ EBookQuery *whereAnalysis( const OSQLParseNode* parseTree );
+ void orderByAnalysis( const OSQLParseNode* _pOrderByClause, SortDescriptor& _out_rSort );
+ OUString getTableName() const;
+
+ public:
+
+ // other methods
+ OEvoabConnection* getOwnConnection() const { return m_xConnection.get(); }
+
+ using OCommonStatement_IBase::operator css::uno::Reference< css::uno::XInterface >;
+
+ protected:
+ explicit OCommonStatement( OEvoabConnection* _pConnection );
+
+ // OComponentHelper
+ virtual void SAL_CALL disposing() override;
+ // XInterface
+ virtual void SAL_CALL release() noexcept override;
+ virtual void SAL_CALL acquire() noexcept override;
+ // XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ //XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override;
+
+ // XPropertySet
+ virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override;
+
+ // XWarningsSupplier
+ virtual css::uno::Any SAL_CALL getWarnings( ) override;
+ virtual void SAL_CALL clearWarnings( ) override;
+
+ // XCloseable
+ virtual void SAL_CALL close( ) override;
+
+ protected:
+ /** will return the EBookQuery representing the statement WHERE condition, or throw
+
+ Also, all statement dependent members (such as the parser/iterator) will be inited afterwards.
+ */
+ QueryData
+ impl_getEBookQuery_throw( const OUString& _rSql );
+
+ css::uno::Reference< css::sdbc::XResultSet >
+ impl_executeQuery_throw( const OUString& _rSql );
+
+ css::uno::Reference< css::sdbc::XResultSet >
+ impl_executeQuery_throw( const QueryData& _rData );
+
+ css::uno::Reference< css::sdbc::XConnection >
+ impl_getConnection() { return css::uno::Reference< css::sdbc::XConnection >( m_xConnection ); }
+
+ OUString
+ impl_getColumnRefColumnName_throw( const ::connectivity::OSQLParseNode& _rColumnRef );
+ };
+
+ typedef ::cppu::ImplHelper2 < css::lang::XServiceInfo
+ , css::sdbc::XStatement
+ > OStatement_IBase;
+ class OStatement :public OCommonStatement
+ ,public OStatement_IBase
+ {
+ protected:
+ virtual ~OStatement() override {}
+
+ public:
+ explicit OStatement( OEvoabConnection* _pConnection)
+ :OCommonStatement( _pConnection)
+ {
+ }
+
+ // XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+
+ // XTypeProvider
+ DECLARE_XTYPEPROVIDER()
+
+ // XServiceInfo
+ DECLARE_SERVICE_INFO();
+
+ // XStatement
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL executeQuery( const OUString& sql ) override ;
+ virtual sal_Int32 SAL_CALL executeUpdate( const OUString& sql ) override ;
+ virtual sal_Bool SAL_CALL execute( const OUString& sql ) override ;
+ virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL getConnection( ) override ;
+ };
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/evoab2/NTable.cxx b/connectivity/source/drivers/evoab2/NTable.cxx
new file mode 100644
index 0000000000..208c527477
--- /dev/null
+++ b/connectivity/source/drivers/evoab2/NTable.cxx
@@ -0,0 +1,76 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include "NTable.hxx"
+#include "NColumns.hxx"
+
+#include <com/sun/star/sdbc/XRow.hpp>
+
+using namespace connectivity;
+using namespace ::comphelper;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+using namespace connectivity::evoab;
+
+OEvoabTable::OEvoabTable( sdbcx::OCollection* _pTables,
+ OEvoabConnection* _pConnection,
+ const OUString& Name,
+ const OUString& Type,
+ const OUString& Description ,
+ const OUString& SchemaName,
+ const OUString& CatalogName
+ ) : OEvoabTable_TYPEDEF(_pTables,true,
+ Name,
+ Type,
+ Description,
+ SchemaName,
+ CatalogName),
+ m_pConnection(_pConnection)
+{
+ construct();
+}
+
+void OEvoabTable::refreshColumns()
+{
+ ::std::vector< OUString> aVector;
+
+ if (!isNew())
+ {
+ Reference< XResultSet > xResult = m_pConnection->getMetaData()->getColumns(
+ Any(), m_SchemaName, m_Name, "%");
+
+ if (xResult.is())
+ {
+ Reference< XRow > xRow(xResult, UNO_QUERY);
+ while (xResult->next())
+ aVector.push_back(xRow->getString(4));
+ }
+ }
+ if (m_xColumns)
+ m_xColumns->reFill(aVector);
+ else
+ m_xColumns.reset(new OEvoabColumns(this,m_aMutex,aVector));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/evoab2/NTable.hxx b/connectivity/source/drivers/evoab2/NTable.hxx
new file mode 100644
index 0000000000..0aa30815b9
--- /dev/null
+++ b/connectivity/source/drivers/evoab2/NTable.hxx
@@ -0,0 +1,53 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "NConnection.hxx"
+#include <connectivity/sdbcx/VTable.hxx>
+
+namespace connectivity::evoab
+{
+ typedef connectivity::sdbcx::OTable OEvoabTable_TYPEDEF;
+
+ class OEvoabTable : public OEvoabTable_TYPEDEF
+ {
+ OEvoabConnection* m_pConnection;
+
+ public:
+ OEvoabTable( sdbcx::OCollection* _pTables,
+ OEvoabConnection* _pConnection,
+ const OUString& Name,
+ const OUString& Type,
+ const OUString& Description,
+ const OUString& SchemaName,
+ const OUString& CatalogName
+ );
+
+ OEvoabConnection* getConnection() { return m_pConnection;}
+
+ virtual void refreshColumns() override;
+
+ OUString const & getTableName() const { return m_Name; }
+ OUString const & getSchema() const { return m_SchemaName; }
+ };
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/evoab2/NTables.cxx b/connectivity/source/drivers/evoab2/NTables.cxx
new file mode 100644
index 0000000000..69b54ba707
--- /dev/null
+++ b/connectivity/source/drivers/evoab2/NTables.cxx
@@ -0,0 +1,79 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "NTables.hxx"
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XResultSet.hpp>
+#include "NCatalog.hxx"
+#include <comphelper/types.hxx>
+#include "NTable.hxx"
+using namespace ::comphelper;
+
+using namespace ::cppu;
+using namespace connectivity::evoab;
+using namespace connectivity::sdbcx;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+using namespace dbtools;
+
+ObjectType OEvoabTables::createObject(const OUString& aName)
+{
+ Sequence< OUString > aTypes { "TABLE" };
+
+ Reference< XResultSet > xResult = m_xMetaData->getTables(Any(),"%",aName,aTypes);
+
+ ObjectType xRet;
+ if(xResult.is())
+ {
+ Reference< XRow > xRow(xResult,UNO_QUERY);
+ if(xResult->next()) // there can be only one table with this name
+ {
+ xRet = new OEvoabTable(
+ this,
+ static_cast<OEvoabCatalog&>(m_rParent).getConnection(),
+ aName,
+ xRow->getString(4),
+ xRow->getString(5),
+ "",
+ "");
+ }
+ }
+
+ ::comphelper::disposeComponent(xResult);
+
+ return xRet;
+}
+
+void OEvoabTables::impl_refresh( )
+{
+ static_cast<OEvoabCatalog&>(m_rParent).refreshTables();
+}
+
+void OEvoabTables::disposing()
+{
+ m_xMetaData.clear();
+ OCollection::disposing();
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/evoab2/NTables.hxx b/connectivity/source/drivers/evoab2/NTables.hxx
new file mode 100644
index 0000000000..e5d4547294
--- /dev/null
+++ b/connectivity/source/drivers/evoab2/NTables.hxx
@@ -0,0 +1,44 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <connectivity/sdbcx/VCollection.hxx>
+#include <com/sun/star/sdbc/XDatabaseMetaData.hpp>
+#include <utility>
+
+namespace connectivity::evoab
+{
+ class OEvoabTables : public sdbcx::OCollection
+ {
+ css::uno::Reference< css::sdbc::XDatabaseMetaData > m_xMetaData;
+ protected:
+ virtual sdbcx::ObjectType createObject(const OUString& _rName) override;
+ virtual void impl_refresh() override;
+ public:
+ OEvoabTables(css::uno::Reference< css::sdbc::XDatabaseMetaData > _xMetaData,
+ ::cppu::OWeakObject& _rParent, ::osl::Mutex& _rMutex,
+ const ::std::vector< OUString> &_rVector) :
+ sdbcx::OCollection(_rParent,true,_rMutex,_rVector),
+ m_xMetaData(std::move(_xMetaData))
+ {}
+ virtual void disposing() override;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/evoab2/evoab.component b/connectivity/source/drivers/evoab2/evoab.component
new file mode 100644
index 0000000000..c0928c178f
--- /dev/null
+++ b/connectivity/source/drivers/evoab2/evoab.component
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ -->
+
+<component loader="com.sun.star.loader.SharedLibrary" environment="@CPPU_ENV@"
+ xmlns="http://openoffice.org/2010/uno-components">
+ <implementation name="com.sun.star.comp.sdbc.evoab.OEvoabDriver"
+ constructor="connectivity_OEvoabDriver_get_implementation">
+ <service name="com.sun.star.sdbc.Driver"/>
+ </implementation>
+</component>
diff --git a/connectivity/source/drivers/file/FCatalog.cxx b/connectivity/source/drivers/file/FCatalog.cxx
new file mode 100644
index 0000000000..eedda26efb
--- /dev/null
+++ b/connectivity/source/drivers/file/FCatalog.cxx
@@ -0,0 +1,103 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <file/FCatalog.hxx>
+#include <file/FConnection.hxx>
+#include <file/FTables.hxx>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XResultSet.hpp>
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::container;
+
+
+using namespace connectivity::file;
+
+OFileCatalog::OFileCatalog(OConnection* _pCon) : connectivity::sdbcx::OCatalog(_pCon)
+ ,m_pConnection(_pCon)
+{
+}
+
+void SAL_CALL OFileCatalog::disposing()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+
+ typedef connectivity::sdbcx::OCatalog OFileCatalog_BASE;
+ m_xMetaData.clear();
+ OFileCatalog_BASE::disposing();
+}
+
+OUString OFileCatalog::buildName(const Reference< XRow >& _xRow)
+{
+ return _xRow->getString(3);
+}
+
+void OFileCatalog::refreshTables()
+{
+ ::std::vector< OUString> aVector;
+ Sequence< OUString > aTypes;
+ Reference< XResultSet > xResult = m_xMetaData->getTables(Any(),
+ "%", "%", aTypes);
+ fillNames(xResult,aVector);
+
+ if(m_pTables)
+ m_pTables->reFill(aVector);
+ else
+ m_pTables.reset( new OTables(m_xMetaData,*this,m_aMutex,aVector) );
+}
+
+
+Any SAL_CALL OFileCatalog::queryInterface( const Type & rType )
+{
+ if( rType == cppu::UnoType<XGroupsSupplier>::get()||
+ rType == cppu::UnoType<XUsersSupplier>::get()||
+ rType == cppu::UnoType<XViewsSupplier>::get())
+ return Any();
+
+
+ typedef sdbcx::OCatalog OFileCatalog_BASE;
+ return OFileCatalog_BASE::queryInterface(rType);
+}
+
+Sequence< Type > SAL_CALL OFileCatalog::getTypes( )
+{
+ typedef sdbcx::OCatalog OFileCatalog_BASE;
+
+ Sequence< Type > aTypes = OFileCatalog_BASE::getTypes();
+ std::vector<Type> aOwnTypes;
+ aOwnTypes.reserve(aTypes.getLength());
+ const Type* pBegin = aTypes.getConstArray();
+ const Type* pEnd = pBegin + aTypes.getLength();
+ for(;pBegin != pEnd;++pBegin)
+ {
+ if(!(*pBegin == cppu::UnoType<XGroupsSupplier>::get()||
+ *pBegin == cppu::UnoType<XUsersSupplier>::get()||
+ *pBegin == cppu::UnoType<XViewsSupplier>::get()))
+ {
+ aOwnTypes.push_back(*pBegin);
+ }
+ }
+ return Sequence< Type >(aOwnTypes.data(), aOwnTypes.size());
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/file/FColumns.cxx b/connectivity/source/drivers/file/FColumns.cxx
new file mode 100644
index 0000000000..1b90385bf9
--- /dev/null
+++ b/connectivity/source/drivers/file/FColumns.cxx
@@ -0,0 +1,80 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <file/FColumns.hxx>
+#include <connectivity/sdbcx/VColumn.hxx>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XResultSet.hpp>
+#include <file/FTable.hxx>
+
+using namespace connectivity::file;
+using namespace connectivity;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+
+sdbcx::ObjectType OColumns::createObject(const OUString& _rName)
+{
+ const OUString sCatalogName;
+ const OUString sSchemaName(m_pTable->getSchema());
+ const OUString sTableName(m_pTable->getName());
+ Reference< XResultSet > xResult = m_pTable->getConnection()->getMetaData()->getColumns(Any(),
+ sSchemaName, sTableName, _rName);
+
+ sdbcx::ObjectType xRet;
+ if(xResult.is())
+ {
+ Reference< XRow > xRow(xResult,UNO_QUERY);
+ while(xResult->next())
+ {
+ if(xRow->getString(4) == _rName)
+ {
+ xRet = new sdbcx::OColumn(_rName,
+ xRow->getString(6),
+ xRow->getString(13),
+ xRow->getString(12),
+ xRow->getInt(11),
+ xRow->getInt(7),
+ xRow->getInt(9),
+ xRow->getInt(5),
+ false,
+ false,
+ false,
+ m_pTable->getConnection()->getMetaData()->supportsMixedCaseQuotedIdentifiers(),
+ sCatalogName,
+ sSchemaName,
+ sTableName);
+ break;
+ }
+ }
+ }
+
+ return xRet;
+}
+
+void OColumns::impl_refresh()
+{
+ m_pTable->refreshColumns();
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/file/FConnection.cxx b/connectivity/source/drivers/file/FConnection.cxx
new file mode 100644
index 0000000000..de93df897b
--- /dev/null
+++ b/connectivity/source/drivers/file/FConnection.cxx
@@ -0,0 +1,428 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <comphelper/processfactory.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <file/FConnection.hxx>
+#include <file/FDatabaseMetaData.hxx>
+#include <file/FDriver.hxx>
+#include <file/FStatement.hxx>
+#include <file/FPreparedStatement.hxx>
+#include <com/sun/star/container/XChild.hpp>
+#include <com/sun/star/ucb/ContentCreationException.hpp>
+#include <com/sun/star/ucb/XContent.hpp>
+#include <com/sun/star/ucb/XContentIdentifier.hpp>
+#include <tools/urlobj.hxx>
+#include <file/FCatalog.hxx>
+#include <unotools/configmgr.hxx>
+#include <unotools/pathoptions.hxx>
+#include <ucbhelper/content.hxx>
+#include <connectivity/dbcharset.hxx>
+#include <connectivity/dbexception.hxx>
+#include <o3tl/any.hxx>
+#include <osl/thread.h>
+#include <strings.hrc>
+
+using namespace connectivity::file;
+using namespace dbtools;
+
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::sdbc;
+using namespace com::sun::star::sdbcx;
+using namespace com::sun::star::container;
+using namespace com::sun::star::ucb;
+using namespace ::ucbhelper;
+typedef connectivity::OMetaConnection OConnection_BASE;
+
+OConnection::OConnection(OFileDriver* _pDriver)
+ : m_pDriver(_pDriver)
+ , m_bAutoCommit(false)
+ , m_bReadOnly(false)
+ , m_bShowDeleted(false)
+ , m_bCaseSensitiveExtension( true )
+ , m_bCheckSQL92(false)
+ , m_bDefaultTextEncoding(false)
+{
+ m_nTextEncoding = RTL_TEXTENCODING_DONTKNOW;
+}
+
+OConnection::~OConnection()
+{
+ if(!isClosed( ))
+ close();
+}
+
+bool OConnection::matchesExtension( const OUString& _rExt ) const
+{
+ if ( isCaseSensitiveExtension() )
+ return ( getExtension() == _rExt );
+
+ OUString sMyExtension( getExtension().toAsciiLowerCase() );
+ OUString sExt( _rExt.toAsciiLowerCase() );
+
+ return sMyExtension == sExt;
+}
+
+
+void OConnection::construct(const OUString& url,const Sequence< PropertyValue >& info)
+{
+ osl_atomic_increment( &m_refCount );
+
+ OUString aExt;
+ const PropertyValue *pIter = info.getConstArray();
+ const PropertyValue *pEnd = pIter + info.getLength();
+ for(;pIter != pEnd;++pIter)
+ {
+ if( pIter->Name == "Extension" )
+ OSL_VERIFY( pIter->Value >>= aExt );
+ else if( pIter->Name == "CharSet" )
+ {
+ if (auto const numeric = o3tl::tryAccess<sal_uInt16>(pIter->Value))
+ {
+ m_nTextEncoding = *numeric;
+ }
+ else
+ {
+ OUString sIanaName;
+ OSL_VERIFY( pIter->Value >>= sIanaName );
+
+ ::dbtools::OCharsetMap aLookupIanaName;
+ ::dbtools::OCharsetMap::const_iterator aLookup = aLookupIanaName.findIanaName(sIanaName);
+ if (aLookup != aLookupIanaName.end())
+ m_nTextEncoding = (*aLookup).getEncoding();
+ else
+ m_nTextEncoding = RTL_TEXTENCODING_DONTKNOW;
+ }
+ }
+ else if( pIter->Name == "ShowDeleted" )
+ {
+ OSL_VERIFY( pIter->Value >>= m_bShowDeleted );
+ }
+ else if( pIter->Name == "EnableSQL92Check" )
+ {
+ pIter->Value >>= m_bCheckSQL92;
+ }
+ } // for(;pIter != pEnd;++pIter)
+
+ {
+ sal_Int32 nLen = url.indexOf(':');
+ nLen = url.indexOf(':',nLen+1);
+ OUString aDSN(url.copy(nLen+1));
+
+ OUString aFileName = aDSN;
+ INetURLObject aURL;
+ aURL.SetSmartProtocol(INetProtocol::File);
+ if (!utl::ConfigManager::IsFuzzing())
+ {
+ SvtPathOptions aPathOptions;
+ aFileName = aPathOptions.SubstituteVariable(aFileName);
+ }
+
+ aURL.SetSmartURL(aFileName);
+
+ setURL(aURL.GetMainURL(INetURLObject::DecodeMechanism::NONE));
+ }
+
+ if ( m_nTextEncoding == RTL_TEXTENCODING_DONTKNOW )
+ {
+ //m_nTextEncoding = osl_getTextEncodingFromLocale(NULL);
+ m_nTextEncoding = osl_getThreadTextEncoding();
+ m_bDefaultTextEncoding = true;
+ }
+
+ if ( !aExt.isEmpty() )
+ m_aFilenameExtension = aExt;
+
+ try
+ {
+ ::ucbhelper::Content aFile;
+ try
+ {
+ aFile = ::ucbhelper::Content(getURL(), Reference< XCommandEnvironment >(), comphelper::getProcessComponentContext());
+ }
+ catch(ContentCreationException& e)
+ {
+ throwUrlNotValid(getURL(),e.Message);
+ }
+
+ // set fields to fetch
+ Sequence< OUString > aProps { "Title" };
+
+ try
+ {
+ if (aFile.isFolder())
+ {
+ m_xDir = aFile.createDynamicCursor(aProps, ::ucbhelper::INCLUDE_DOCUMENTS_ONLY );
+ m_xContent = aFile.get();
+ }
+ else if (aFile.isDocument())
+ {
+ Reference<XContent> xParent(Reference<XChild>(aFile.get(),UNO_QUERY_THROW)->getParent(),UNO_QUERY_THROW);
+ Reference<XContentIdentifier> xIdent = xParent->getIdentifier();
+ m_xContent = xParent;
+
+ ::ucbhelper::Content aParent(xIdent->getContentIdentifier(), Reference< XCommandEnvironment >(), comphelper::getProcessComponentContext());
+ m_xDir = aParent.createDynamicCursor(aProps, ::ucbhelper::INCLUDE_DOCUMENTS_ONLY );
+ }
+ else
+ {
+ OSL_FAIL("OConnection::construct: ::ucbhelper::Content is neither a folder nor a document! How's that?!");
+ throw SQLException();
+ }
+ }
+ catch(Exception& e) // an exception is thrown when no file exists
+ {
+ throwUrlNotValid(getURL(),e.Message);
+ }
+ if(!m_xDir.is() || !m_xContent.is())
+ throwUrlNotValid(getURL(),OUString());
+
+ if (m_aFilenameExtension.indexOf('*') >= 0 || m_aFilenameExtension.indexOf('?') >= 0)
+ throw SQLException();
+ }
+ catch(const Exception&)
+ {
+ osl_atomic_decrement( &m_refCount );
+ throw;
+ }
+
+ osl_atomic_decrement( &m_refCount );
+}
+// XServiceInfo
+
+IMPLEMENT_SERVICE_INFO(OConnection, "com.sun.star.sdbc.drivers.file.Connection", "com.sun.star.sdbc.Connection")
+
+
+Reference< XStatement > SAL_CALL OConnection::createStatement( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OConnection_BASE::rBHelper.bDisposed);
+
+
+ Reference< XStatement > xReturn = new OStatement(this);
+ m_aStatements.push_back(WeakReferenceHelper(xReturn));
+ return xReturn;
+}
+
+Reference< XPreparedStatement > SAL_CALL OConnection::prepareStatement( const OUString& sql )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OConnection_BASE::rBHelper.bDisposed);
+
+
+ rtl::Reference<OPreparedStatement> pStmt = new OPreparedStatement(this);
+ pStmt->construct(sql);
+ m_aStatements.push_back(WeakReferenceHelper(*pStmt));
+ return pStmt;
+}
+
+Reference< XPreparedStatement > SAL_CALL OConnection::prepareCall( const OUString& /*sql*/ )
+{
+ throwFeatureNotImplementedSQLException( "XConnection::prepareCall", *this );
+ return nullptr;
+}
+
+OUString SAL_CALL OConnection::nativeSQL( const OUString& sql )
+{
+ return sql;
+}
+
+void SAL_CALL OConnection::setAutoCommit( sal_Bool autoCommit )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OConnection_BASE::rBHelper.bDisposed);
+
+ m_bAutoCommit = autoCommit;
+}
+
+sal_Bool SAL_CALL OConnection::getAutoCommit( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OConnection_BASE::rBHelper.bDisposed);
+
+ return m_bAutoCommit;
+}
+
+void SAL_CALL OConnection::commit( )
+{
+}
+
+void SAL_CALL OConnection::rollback( )
+{
+}
+
+sal_Bool SAL_CALL OConnection::isClosed( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ return OConnection_BASE::rBHelper.bDisposed;
+}
+
+Reference< XDatabaseMetaData > SAL_CALL OConnection::getMetaData( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OConnection_BASE::rBHelper.bDisposed);
+
+
+ Reference< XDatabaseMetaData > xMetaData = m_xMetaData;
+ if(!xMetaData.is())
+ {
+ xMetaData = new ODatabaseMetaData(this);
+ m_xMetaData = xMetaData;
+ }
+
+ return xMetaData;
+}
+
+void SAL_CALL OConnection::setReadOnly( sal_Bool readOnly )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OConnection_BASE::rBHelper.bDisposed);
+
+
+ m_bReadOnly = readOnly;
+}
+
+sal_Bool SAL_CALL OConnection::isReadOnly( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OConnection_BASE::rBHelper.bDisposed);
+
+
+ return m_bReadOnly;
+}
+
+void SAL_CALL OConnection::setCatalog( const OUString& /*catalog*/ )
+{
+ throwFeatureNotImplementedSQLException( "XConnection::setCatalog", *this );
+}
+
+OUString SAL_CALL OConnection::getCatalog( )
+{
+ return OUString();
+}
+
+void SAL_CALL OConnection::setTransactionIsolation( sal_Int32 /*level*/ )
+{
+ throwFeatureNotImplementedSQLException( "XConnection::setTransactionIsolation", *this );
+}
+
+sal_Int32 SAL_CALL OConnection::getTransactionIsolation( )
+{
+ return 0;
+}
+
+Reference< XNameAccess > SAL_CALL OConnection::getTypeMap( )
+{
+ return nullptr;
+}
+
+void SAL_CALL OConnection::setTypeMap( const Reference< XNameAccess >& /*typeMap*/ )
+{
+}
+
+// XCloseable
+void SAL_CALL OConnection::close( )
+{
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OConnection_BASE::rBHelper.bDisposed);
+
+ }
+ dispose();
+}
+
+// XWarningsSupplier
+Any SAL_CALL OConnection::getWarnings( )
+{
+ return Any();
+}
+
+void SAL_CALL OConnection::clearWarnings( )
+{
+}
+
+void OConnection::disposing()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ OConnection_BASE::disposing();
+
+ m_xDir.clear();
+ m_xContent.clear();
+ m_xCatalog = WeakReference< XTablesSupplier>();
+}
+
+Reference< XTablesSupplier > OConnection::createCatalog()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ Reference< XTablesSupplier > xTab = m_xCatalog;
+ if(!xTab.is())
+ {
+ xTab = new OFileCatalog(this);
+ m_xCatalog = xTab;
+ }
+ return xTab;
+}
+
+Reference< XDynamicResultSet > OConnection::getDir() const
+{
+ Reference<XDynamicResultSet> xContent;
+ Sequence< OUString > aProps { "Title" };
+ try
+ {
+ Reference<XContentIdentifier> xIdent = getContent()->getIdentifier();
+ ::ucbhelper::Content aParent(xIdent->getContentIdentifier(), Reference< XCommandEnvironment >(), comphelper::getProcessComponentContext());
+ xContent = aParent.createDynamicCursor(aProps, ::ucbhelper::INCLUDE_DOCUMENTS_ONLY );
+ }
+ catch(Exception&)
+ {
+ }
+ return xContent;
+}
+
+sal_Int64 SAL_CALL OConnection::getSomething( const Sequence< sal_Int8 >& rId )
+{
+ return comphelper::getSomethingImpl(rId, this);
+}
+
+const Sequence< sal_Int8 > & OConnection::getUnoTunnelId()
+{
+ static const comphelper::UnoIdInit implId;
+ return implId.getSeq();
+}
+
+void OConnection::throwUrlNotValid(const OUString & _rsUrl,const OUString & _rsMessage)
+{
+ XConnection* context = this;
+ css::uno::Any next;
+ if (!_rsMessage.isEmpty())
+ next <<= SQLException(_rsMessage, context, OUString(), 0, Any());
+ SQLException aError(
+ getResources().getResourceStringWithSubstitution(STR_NO_VALID_FILE_URL, "$URL$", _rsUrl),
+ context, "S1000", 0, next);
+
+ throw aError;
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/file/FDatabaseMetaData.cxx b/connectivity/source/drivers/file/FDatabaseMetaData.cxx
new file mode 100644
index 0000000000..b0d7bcd7f8
--- /dev/null
+++ b/connectivity/source/drivers/file/FDatabaseMetaData.cxx
@@ -0,0 +1,1050 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <config_fuzzers.h>
+
+#include <file/FDatabaseMetaData.hxx>
+#include <FDatabaseMetaDataResultSet.hxx>
+#include <com/sun/star/sdbc/ResultSetType.hpp>
+#include <com/sun/star/ucb/UniversalContentBroker.hpp>
+#include <com/sun/star/ucb/SortedDynamicResultSetFactory.hpp>
+#include <tools/urlobj.hxx>
+#include <sal/log.hxx>
+#include <file/FDriver.hxx>
+#include <file/FTable.hxx>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <comphelper/diagnose_ex.hxx>
+#include <ucbhelper/content.hxx>
+
+using namespace com::sun::star::ucb;
+using namespace connectivity::file;
+using namespace connectivity;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::sdbc;
+using namespace com::sun::star::sdbcx;
+using namespace com::sun::star::container;
+
+ODatabaseMetaData::ODatabaseMetaData(OConnection* _pCon) : ::connectivity::ODatabaseMetaDataBase(_pCon,_pCon->getConnectionInfo())
+ ,m_pConnection(_pCon)
+{
+}
+
+ODatabaseMetaData::~ODatabaseMetaData()
+{
+}
+
+Reference< XResultSet > ODatabaseMetaData::impl_getTypeInfo_throw( )
+{
+ return new ODatabaseMetaDataResultSet( ODatabaseMetaDataResultSet::eTypeInfo );
+}
+
+OUString ODatabaseMetaData::impl_getCatalogSeparator_throw( )
+{
+ return OUString();
+}
+
+Reference< XResultSet > SAL_CALL ODatabaseMetaData::getColumns(
+ const Any& /*catalog*/, const OUString& /*schemaPattern*/, const OUString& /*tableNamePattern*/,
+ const OUString& /*columnNamePattern*/ )
+{
+ SAL_WARN("connectivity.drivers", "ODatabaseMetaData::getColumns() should be overridden!");
+ return new ODatabaseMetaDataResultSet( ODatabaseMetaDataResultSet::eColumns );
+}
+
+
+namespace
+{
+#if !ENABLE_FUZZERS
+ sal_Int16 isCaseSensitiveParentFolder( const OUString& _rFolderOrDoc, std::u16string_view _rDocName )
+ {
+ sal_Int16 nIsCS = 1;
+ try
+ {
+ // first get the real content for the URL
+ INetURLObject aContentURL( _rFolderOrDoc );
+ ::ucbhelper::Content aContent1;
+ {
+ ::ucbhelper::Content aFolderOrDoc( _rFolderOrDoc, Reference< XCommandEnvironment >(), comphelper::getProcessComponentContext() );
+ if ( aFolderOrDoc.isDocument() )
+ aContent1 = aFolderOrDoc;
+ else
+ {
+ aContentURL = INetURLObject( _rFolderOrDoc, INetURLObject::EncodeMechanism::WasEncoded );
+ aContentURL.Append( _rDocName );
+ aContent1 = ::ucbhelper::Content( aContentURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), Reference< XCommandEnvironment >(), comphelper::getProcessComponentContext() );
+ }
+ }
+
+ // get two extensions which differ by case only
+ OUString sExtension1(aContentURL.getExtension());
+ OUString sExtension2(sExtension1.toAsciiLowerCase());
+ if (sExtension2 == sExtension1)
+ {
+ // the extension was already in lower case
+ sExtension2 = sExtension2.toAsciiUpperCase();
+ }
+
+ // the complete URL for the second extension
+ INetURLObject aURL2( aContentURL );
+ if (!sExtension2.isEmpty())
+ aURL2.SetExtension( sExtension2 );
+ if ( aURL2.GetMainURL(INetURLObject::DecodeMechanism::NONE) == aContentURL.GetMainURL(INetURLObject::DecodeMechanism::NONE) )
+ return -1;
+
+ // the second context
+ bool bCanAccess = false;
+ ::ucbhelper::Content aContent2;
+ try
+ {
+ aContent2 = ::ucbhelper::Content( aURL2.GetMainURL( INetURLObject::DecodeMechanism::NONE ), Reference< XCommandEnvironment >(), comphelper::getProcessComponentContext() );
+ bCanAccess = aContent2.isDocument();
+ }
+ catch( const Exception& )
+ {
+ }
+
+ if ( bCanAccess )
+ {
+ // here we have two contents whose URLs differ by case only.
+ // Now let's check if both really refer to the same object...
+ Reference< XContent > xContent1 = aContent1.get();
+ Reference< XContent > xContent2 = aContent2.get();
+ OSL_ENSURE( xContent1.is() && xContent2.is(), "isCaseSensitiveParentFolder: invalid content interfaces!" );
+ if ( xContent1.is() && xContent2.is() )
+ {
+ Reference< XContentIdentifier > xID1 = xContent1->getIdentifier();
+ Reference< XContentIdentifier > xID2 = xContent2->getIdentifier();
+ OSL_ENSURE( xID1.is() && xID2.is(), "isCaseSensitiveParentFolder: invalid ID interfaces!" );
+ if ( xID1.is() && xID2.is()
+ && ( UniversalContentBroker::create(
+ comphelper::getProcessComponentContext() )->
+ compareContentIds( xID1, xID2 ) == 0 ) )
+ {
+ // finally, we know that the folder is not case-sensitive...
+ nIsCS = 0;
+ }
+ }
+ }
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "connectivity.drivers", "isCaseSensitiveParentFolder" );
+ }
+
+ return nIsCS;
+ }
+#endif
+}
+
+
+Reference< XResultSet > SAL_CALL ODatabaseMetaData::getTables(
+ const Any& /*catalog*/, const OUString& /*schemaPattern*/,
+ const OUString& tableNamePattern, const Sequence< OUString >& types )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ rtl::Reference<ODatabaseMetaDataResultSet> pResult = new ODatabaseMetaDataResultSet( ODatabaseMetaDataResultSet::eTables );
+
+ // check if any type is given
+ // when no types are given then we have to return all tables e.g. TABLE
+
+ static constexpr OUString aTable = u"TABLE"_ustr;
+
+ bool bTableFound = true;
+ sal_Int32 nLength = types.getLength();
+ if(nLength)
+ {
+ bTableFound = false;
+
+ const OUString* pBegin = types.getConstArray();
+ const OUString* pEnd = pBegin + nLength;
+ for(;pBegin != pEnd;++pBegin)
+ {
+ if(*pBegin == aTable)
+ {
+ bTableFound = true;
+ break;
+ }
+ }
+ }
+ if(!bTableFound)
+ return pResult;
+
+ Reference<XDynamicResultSet> xContent = m_pConnection->getDir();
+ Reference < XSortedDynamicResultSetFactory > xSRSFac =
+ SortedDynamicResultSetFactory::create( m_pConnection->getDriver()->getComponentContext() );
+
+ Sequence< NumberedSortingInfo > aSortInfo( 1 );
+ NumberedSortingInfo* pInfo = aSortInfo.getArray();
+ pInfo[ 0 ].ColumnIndex = 1;
+ pInfo[ 0 ].Ascending = true;
+
+ Reference < XAnyCompareFactory > xFactory;
+ Reference< XDynamicResultSet > xDynamicResultSet = xSRSFac->createSortedDynamicResultSet( xContent, aSortInfo, xFactory );
+ Reference<XResultSet> xResultSet = xDynamicResultSet->getStaticResultSet();
+
+ Reference<XRow> xRow(xResultSet,UNO_QUERY);
+
+ OUString aFilenameExtension = m_pConnection->getExtension();
+ OUString sThisContentExtension;
+ ODatabaseMetaDataResultSet::ORows aRows;
+ // scan the directory for tables
+ OUString aName;
+ INetURLObject aURL;
+ xResultSet->beforeFirst();
+
+ bool bKnowCaseSensitivity = false;
+ bool bCaseSensitiveDir = true;
+ bool bCheckEnabled = m_pConnection->isCheckEnabled();
+
+ while(xResultSet->next())
+ {
+ aName = xRow->getString(1);
+ aURL.SetSmartProtocol(INetProtocol::File);
+ OUString sUrl = m_pConnection->getURL() + "/" + aName;
+ aURL.SetSmartURL( sUrl );
+ sThisContentExtension = aURL.getExtension();
+
+ ODatabaseMetaDataResultSet::ORow aRow { nullptr, nullptr, nullptr };
+ aRow.reserve(6);
+ bool bNewRow = false;
+
+ if ( !bKnowCaseSensitivity )
+ {
+ bKnowCaseSensitivity = true;
+#if ENABLE_FUZZERS
+ sal_Int16 nCase = 1;
+#else
+ sal_Int16 nCase = isCaseSensitiveParentFolder( m_pConnection->getURL(), aURL.getName() );
+#endif
+ switch( nCase )
+ {
+ case 1:
+ bCaseSensitiveDir = true;
+ break;
+ case -1:
+ bKnowCaseSensitivity = false;
+ [[fallthrough]];
+ case 0:
+ bCaseSensitiveDir = false;
+ }
+ if ( bKnowCaseSensitivity )
+ {
+ m_pConnection->setCaseSensitiveExtension( bCaseSensitiveDir, OConnection::GrantAccess() );
+ if ( !bCaseSensitiveDir )
+ {
+ aFilenameExtension = aFilenameExtension.toAsciiLowerCase();
+ }
+ }
+ }
+
+ if (!aFilenameExtension.isEmpty())
+ {
+ if ( !bCaseSensitiveDir )
+ {
+ sThisContentExtension = sThisContentExtension.toAsciiLowerCase();
+ }
+
+ if ( sThisContentExtension == aFilenameExtension )
+ {
+ aName = aName.copy(0, (aName.getLength()-(aFilenameExtension.getLength()+1)));
+ sal_Unicode nChar = aName.toChar();
+ if ( match(tableNamePattern,aName,'\0') && ( !bCheckEnabled || (nChar < '0' || nChar > '9')) )
+ {
+ aRow.push_back(new ORowSetValueDecorator(aName));
+ bNewRow = true;
+ }
+ }
+ }
+ else // no extension, filter myself
+ {
+ for (;;)
+ {
+ if (aURL.getExtension().isEmpty())
+ {
+ sal_Unicode nChar = aURL.getBase()[0];
+ if( match(tableNamePattern,aURL.getBase(),'\0') && ( !bCheckEnabled || nChar < '0' || nChar > '9' ) )
+ {
+ aRow.push_back(new ORowSetValueDecorator(aURL.getBase()));
+ bNewRow = true;
+ }
+ break;
+ }
+ if ( !xResultSet->next() )
+ {
+ break;
+ }
+ aName = xRow->getString(1);
+ aURL.SetSmartURL(aName);
+ }
+ }
+ if(bNewRow)
+ {
+ aRow.push_back(new ORowSetValueDecorator(aTable));
+ aRow.push_back(ODatabaseMetaDataResultSet::getEmptyValue());
+
+ aRows.push_back(aRow);
+ }
+ }
+
+ pResult->setRows(std::move(aRows));
+
+ return pResult;
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxBinaryLiteralLength( )
+{
+ return 0;
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxRowSize( )
+{
+ return 0;
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxCatalogNameLength( )
+{
+ return 0;
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxCharLiteralLength( )
+{
+ return SAL_MAX_INT32;
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxColumnNameLength( )
+{
+ return 0;
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxColumnsInIndex( )
+{
+ return 0;
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxCursorNameLength( )
+{
+ return 0;
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxConnections( )
+{
+ return 0;
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxColumnsInTable( )
+{
+ return 0;
+}
+
+sal_Int32 ODatabaseMetaData::impl_getMaxStatements_throw( )
+{
+ return 0;
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxTableNameLength( )
+{
+ return 0;
+}
+
+sal_Int32 ODatabaseMetaData::impl_getMaxTablesInSelect_throw( )
+{
+ return 1;
+}
+
+Reference< XResultSet > SAL_CALL ODatabaseMetaData::getTablePrivileges(
+ const Any& /*catalog*/, const OUString& /*schemaPattern*/, const OUString& tableNamePattern )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ rtl::Reference<ODatabaseMetaDataResultSet> pResult = new ODatabaseMetaDataResultSet( ODatabaseMetaDataResultSet::eTablePrivileges );
+ ODatabaseMetaDataResultSet::ORows aRows;
+
+ Reference< XTablesSupplier > xTabSup = m_pConnection->createCatalog();
+ if( xTabSup.is())
+ {
+ Reference< XNameAccess> xNames = xTabSup->getTables();
+ Sequence< OUString > aNames = xNames->getElementNames();
+ const OUString* pBegin = aNames.getConstArray();
+ const OUString* pEnd = pBegin + aNames.getLength();
+ for(;pBegin != pEnd;++pBegin)
+ {
+ if(match(tableNamePattern,*pBegin,'\0'))
+ {
+ ODatabaseMetaDataResultSet::ORow aRow(8);
+
+ aRow[2] = new ORowSetValueDecorator(*pBegin);
+ aRow[6] = ODatabaseMetaDataResultSet::getSelectValue();
+ aRow[7] = new ORowSetValueDecorator(OUString("NO"));
+ aRows.push_back(aRow);
+
+ Reference< XPropertySet> xTable(
+ xNames->getByName(*pBegin), css::uno::UNO_QUERY);
+ if(xTable.is())
+ {
+ auto pTable = dynamic_cast<OFileTable*>(xTable.get());
+ if(pTable && !pTable->isReadOnly())
+ {
+ aRow[6] = ODatabaseMetaDataResultSet::getInsertValue();
+ aRows.push_back(aRow);
+ if(!m_pConnection->showDeleted())
+ {
+ aRow[6] = ODatabaseMetaDataResultSet::getDeleteValue();
+ aRows.push_back(aRow);
+ }
+ aRow[6] = ODatabaseMetaDataResultSet::getUpdateValue();
+ aRows.push_back(aRow);
+ aRow[6] = ODatabaseMetaDataResultSet::getCreateValue();
+ aRows.push_back(aRow);
+ aRow[6] = ODatabaseMetaDataResultSet::getReadValue();
+ aRows.push_back(aRow);
+ aRow[6] = ODatabaseMetaDataResultSet::getAlterValue();
+ aRows.push_back(aRow);
+ aRow[6] = ODatabaseMetaDataResultSet::getDropValue();
+ aRows.push_back(aRow);
+ }
+ }
+ }
+ }
+ }
+
+ pResult->setRows(std::move(aRows));
+ return pResult;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::doesMaxRowSizeIncludeBlobs( )
+{
+ return true;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::storesLowerCaseQuotedIdentifiers( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::storesLowerCaseIdentifiers( )
+{
+ return false;
+}
+
+bool ODatabaseMetaData::impl_storesMixedCaseQuotedIdentifiers_throw( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::storesMixedCaseIdentifiers( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::storesUpperCaseQuotedIdentifiers( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::storesUpperCaseIdentifiers( )
+{
+ return false;
+}
+
+bool ODatabaseMetaData::impl_supportsAlterTableWithAddColumn_throw( )
+{
+ return false;
+}
+
+bool ODatabaseMetaData::impl_supportsAlterTableWithDropColumn_throw( )
+{
+ return false;
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxIndexLength( )
+{
+ return 0;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsNonNullableColumns( )
+{
+ return false;
+}
+
+OUString SAL_CALL ODatabaseMetaData::getCatalogTerm( )
+{
+ return OUString();
+}
+
+OUString ODatabaseMetaData::impl_getIdentifierQuoteString_throw( )
+{
+ return "\"";
+}
+
+OUString SAL_CALL ODatabaseMetaData::getExtraNameCharacters( )
+{
+ return OUString();
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsDifferentTableCorrelationNames( )
+{
+ return true;
+}
+
+bool ODatabaseMetaData::impl_isCatalogAtStart_throw( )
+{
+ return true;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::dataDefinitionIgnoredInTransactions( )
+{
+ return true;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::dataDefinitionCausesTransactionCommit( )
+{
+ return true;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsDataManipulationTransactionsOnly( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsDataDefinitionAndDataManipulationTransactions( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsPositionedDelete( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsPositionedUpdate( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsOpenStatementsAcrossRollback( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsOpenStatementsAcrossCommit( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsOpenCursorsAcrossCommit( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsOpenCursorsAcrossRollback( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsTransactionIsolationLevel( sal_Int32 /*level*/ )
+{
+ return false;
+}
+
+bool ODatabaseMetaData::impl_supportsSchemasInDataManipulation_throw( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsANSI92FullSQL( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsANSI92EntryLevelSQL( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsIntegrityEnhancementFacility( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsSchemasInIndexDefinitions( )
+{
+ return false;
+}
+
+bool ODatabaseMetaData::impl_supportsSchemasInTableDefinitions_throw( )
+{
+ return false;
+}
+
+bool ODatabaseMetaData::impl_supportsCatalogsInTableDefinitions_throw( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsCatalogsInIndexDefinitions( )
+{
+ return false;
+}
+
+bool ODatabaseMetaData::impl_supportsCatalogsInDataManipulation_throw( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsOuterJoins( )
+{
+ return false;
+}
+
+Reference< XResultSet > SAL_CALL ODatabaseMetaData::getTableTypes( )
+{
+ rtl::Reference<ODatabaseMetaDataResultSet> pResult = new ODatabaseMetaDataResultSet( ODatabaseMetaDataResultSet::eTableTypes );
+ ODatabaseMetaDataResultSet::ORows aRows;
+ aRows.push_back( { ODatabaseMetaDataResultSet::getEmptyValue(), new ORowSetValueDecorator(OUString("TABLE")) } );
+ pResult->setRows(std::move(aRows));
+ return pResult;
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxStatementLength( )
+{
+ return 0;
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxProcedureNameLength( )
+{
+ return 0;
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxSchemaNameLength( )
+{
+ return 0;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsTransactions( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::allProceduresAreCallable( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsStoredProcedures( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsSelectForUpdate( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::allTablesAreSelectable( )
+{
+ return true;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::isReadOnly( )
+{
+ return true;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::usesLocalFiles( )
+{
+ return true;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::usesLocalFilePerTable( )
+{
+ return true;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsTypeConversion( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::nullPlusNonNullIsNull( )
+{
+ return true;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsColumnAliasing( )
+{
+ return true;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsTableCorrelationNames( )
+{
+ return true;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsConvert( sal_Int32 /*fromType*/, sal_Int32 /*toType*/ )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsExpressionsInOrderBy( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsGroupBy( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsGroupByBeyondSelect( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsGroupByUnrelated( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsMultipleTransactions( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsMultipleResultSets( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsLikeEscapeClause( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsOrderByUnrelated( )
+{
+ return true;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsUnion( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsUnionAll( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsMixedCaseIdentifiers( )
+{
+ return true;
+}
+
+bool ODatabaseMetaData::impl_supportsMixedCaseQuotedIdentifiers_throw( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::nullsAreSortedAtEnd( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::nullsAreSortedAtStart( )
+{
+ return true;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::nullsAreSortedHigh( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::nullsAreSortedLow( )
+{
+ return true;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsSchemasInProcedureCalls( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsSchemasInPrivilegeDefinitions( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsCatalogsInProcedureCalls( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsCatalogsInPrivilegeDefinitions( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsCorrelatedSubqueries( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsSubqueriesInComparisons( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsSubqueriesInExists( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsSubqueriesInIns( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsSubqueriesInQuantifieds( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsANSI92IntermediateSQL( )
+{
+ return false;
+}
+
+OUString SAL_CALL ODatabaseMetaData::getURL( )
+{
+ return "sdbc:file:";
+}
+
+OUString SAL_CALL ODatabaseMetaData::getUserName( )
+{
+ return OUString();
+}
+
+OUString SAL_CALL ODatabaseMetaData::getDriverName( )
+{
+ return OUString();
+}
+
+OUString SAL_CALL ODatabaseMetaData::getDriverVersion( )
+{
+ return OUString::number(1);
+}
+
+OUString SAL_CALL ODatabaseMetaData::getDatabaseProductVersion( )
+{
+ return OUString::number(0);
+}
+
+OUString SAL_CALL ODatabaseMetaData::getDatabaseProductName( )
+{
+ return OUString();
+}
+
+OUString SAL_CALL ODatabaseMetaData::getProcedureTerm( )
+{
+ return OUString();
+}
+
+OUString SAL_CALL ODatabaseMetaData::getSchemaTerm( )
+{
+ return OUString();
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getDriverMajorVersion( )
+{
+ return 0;
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getDefaultTransactionIsolation( )
+{
+ return 0;
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getDriverMinorVersion( )
+{
+ return 0;
+}
+
+OUString SAL_CALL ODatabaseMetaData::getSQLKeywords( )
+{
+ return OUString();
+}
+
+OUString SAL_CALL ODatabaseMetaData::getSearchStringEscape( )
+{
+ return OUString();
+}
+
+OUString SAL_CALL ODatabaseMetaData::getStringFunctions( )
+{
+ return "UCASE,LCASE,ASCII,LENGTH,OCTET_LENGTH,CHAR_LENGTH,CHARACTER_LENGTH,CHAR,CONCAT,LOCATE,SUBSTRING,LTRIM,RTRIM,SPACE,REPLACE,REPEAT,INSERT,LEFT,RIGHT";
+}
+
+OUString SAL_CALL ODatabaseMetaData::getTimeDateFunctions( )
+{
+ return "DAYOFWEEK,DAYOFMONTH,DAYOFYEAR,MONTH,DAYNAME,MONTHNAME,QUARTER,WEEK,YEAR,HOUR,MINUTE,SECOND,CURDATE,CURTIME,NOW";
+}
+
+OUString SAL_CALL ODatabaseMetaData::getSystemFunctions( )
+{
+ return OUString();
+}
+
+OUString SAL_CALL ODatabaseMetaData::getNumericFunctions( )
+{
+ return "ABS,SIGN,MOD,FLOOR,CEILING,ROUND,EXP,LN,LOG,LOG10,POWER,SQRT,PI,COS,SIN,TAN,ACOS,ASIN,ATAN,ATAN2,DEGREES,RADIANS";
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsExtendedSQLGrammar( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsCoreSQLGrammar( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsMinimumSQLGrammar( )
+{
+ return true;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsFullOuterJoins( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsLimitedOuterJoins( )
+{
+ return false;
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxColumnsInGroupBy( )
+{
+ return 0;
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxColumnsInOrderBy( )
+{
+ return 0;
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxColumnsInSelect( )
+{
+ return 0;
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxUserNameLength( )
+{
+ return 0;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsResultSetType( sal_Int32 setType )
+{
+ switch(setType)
+ {
+ case ResultSetType::FORWARD_ONLY:
+ return true;
+ case ResultSetType::SCROLL_INSENSITIVE:
+ case ResultSetType::SCROLL_SENSITIVE:
+ break;
+ }
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsResultSetConcurrency( sal_Int32 setType, sal_Int32 /*concurrency*/ )
+{
+ switch(setType)
+ {
+ case ResultSetType::FORWARD_ONLY:
+ return true;
+ case ResultSetType::SCROLL_INSENSITIVE:
+ case ResultSetType::SCROLL_SENSITIVE:
+ break;
+ }
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::ownUpdatesAreVisible( sal_Int32 /*setType*/ )
+{
+ return true;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::ownDeletesAreVisible( sal_Int32 /*setType*/ )
+{
+ return true;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::ownInsertsAreVisible( sal_Int32 /*setType*/ )
+{
+ return true;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::othersUpdatesAreVisible( sal_Int32 /*setType*/ )
+{
+ return true;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::othersDeletesAreVisible( sal_Int32 /*setType*/ )
+{
+ return true;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::othersInsertsAreVisible( sal_Int32 /*setType*/ )
+{
+ return true;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::updatesAreDetected( sal_Int32 /*setType*/ )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::deletesAreDetected( sal_Int32 /*setType*/ )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::insertsAreDetected( sal_Int32 /*setType*/ )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsBatchUpdates( )
+{
+ return false;
+}
+
+Reference< XResultSet > SAL_CALL ODatabaseMetaData::getUDTs( const Any& /*catalog*/, const OUString& /*schemaPattern*/, const OUString& /*typeNamePattern*/, const Sequence< sal_Int32 >& /*types*/ )
+{
+ return nullptr;
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/file/FDateFunctions.cxx b/connectivity/source/drivers/file/FDateFunctions.cxx
new file mode 100644
index 0000000000..1be992d4b6
--- /dev/null
+++ b/connectivity/source/drivers/file/FDateFunctions.cxx
@@ -0,0 +1,278 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <file/FDateFunctions.hxx>
+#include <tools/date.hxx>
+#include <tools/time.hxx>
+#include <tools/datetime.hxx>
+#include <osl/diagnose.h>
+
+using namespace connectivity;
+using namespace connectivity::file;
+
+ORowSetValue OOp_DayOfWeek::operate(const ORowSetValue& lhs) const
+{
+ if (lhs.isNull())
+ return lhs;
+
+ sal_Int32 nRet = 0;
+ css::util::Date aD = lhs.getDate();
+ Date aDate(aD.Day, aD.Month, aD.Year);
+ DayOfWeek eDayOfWeek = aDate.GetDayOfWeek();
+ switch (eDayOfWeek)
+ {
+ case MONDAY:
+ nRet = 2;
+ break;
+ case TUESDAY:
+ nRet = 3;
+ break;
+ case WEDNESDAY:
+ nRet = 4;
+ break;
+ case THURSDAY:
+ nRet = 5;
+ break;
+ case FRIDAY:
+ nRet = 6;
+ break;
+ case SATURDAY:
+ nRet = 7;
+ break;
+ case SUNDAY:
+ nRet = 1;
+ break;
+ default:
+ OSL_FAIL("Error in enum values for date");
+ }
+ return nRet;
+}
+
+ORowSetValue OOp_DayOfMonth::operate(const ORowSetValue& lhs) const
+{
+ if (lhs.isNull())
+ return lhs;
+
+ css::util::Date aD = lhs.getDate();
+ return static_cast<sal_Int16>(aD.Day);
+}
+
+ORowSetValue OOp_DayOfYear::operate(const ORowSetValue& lhs) const
+{
+ if (lhs.isNull())
+ return lhs;
+
+ css::util::Date aD = lhs.getDate();
+ Date aDate(aD.Day, aD.Month, aD.Year);
+ return static_cast<sal_Int16>(aDate.GetDayOfYear());
+}
+
+ORowSetValue OOp_Month::operate(const ORowSetValue& lhs) const
+{
+ if (lhs.isNull())
+ return lhs;
+
+ css::util::Date aD = lhs.getDate();
+ return static_cast<sal_Int16>(aD.Month);
+}
+
+ORowSetValue OOp_DayName::operate(const ORowSetValue& lhs) const
+{
+ if (lhs.isNull())
+ return lhs;
+
+ OUString sRet;
+ css::util::Date aD = lhs.getDate();
+ Date aDate(aD.Day, aD.Month, aD.Year);
+ DayOfWeek eDayOfWeek = aDate.GetDayOfWeek();
+ switch (eDayOfWeek)
+ {
+ case MONDAY:
+ sRet = "Monday";
+ break;
+ case TUESDAY:
+ sRet = "Tuesday";
+ break;
+ case WEDNESDAY:
+ sRet = "Wednesday";
+ break;
+ case THURSDAY:
+ sRet = "Thursday";
+ break;
+ case FRIDAY:
+ sRet = "Friday";
+ break;
+ case SATURDAY:
+ sRet = "Saturday";
+ break;
+ case SUNDAY:
+ sRet = "Sunday";
+ break;
+ default:
+ OSL_FAIL("Error in enum values for date");
+ }
+ return sRet;
+}
+
+ORowSetValue OOp_MonthName::operate(const ORowSetValue& lhs) const
+{
+ if (lhs.isNull())
+ return lhs;
+
+ OUString sRet;
+ css::util::Date aD = lhs.getDate();
+ switch (aD.Month)
+ {
+ case 1:
+ sRet = "January";
+ break;
+ case 2:
+ sRet = "February";
+ break;
+ case 3:
+ sRet = "March";
+ break;
+ case 4:
+ sRet = "April";
+ break;
+ case 5:
+ sRet = "May";
+ break;
+ case 6:
+ sRet = "June";
+ break;
+ case 7:
+ sRet = "July";
+ break;
+ case 8:
+ sRet = "August";
+ break;
+ case 9:
+ sRet = "September";
+ break;
+ case 10:
+ sRet = "October";
+ break;
+ case 11:
+ sRet = "November";
+ break;
+ case 12:
+ sRet = "December";
+ break;
+ }
+ return sRet;
+}
+
+ORowSetValue OOp_Quarter::operate(const ORowSetValue& lhs) const
+{
+ if (lhs.isNull())
+ return lhs;
+
+ sal_Int32 nRet = 1;
+ css::util::Date aD = lhs.getDate();
+ if (aD.Month >= 4 && aD.Month < 7)
+ nRet = 2;
+ else if (aD.Month >= 7 && aD.Month < 10)
+ nRet = 3;
+ else if (aD.Month >= 10 && aD.Month <= 12)
+ nRet = 4;
+ return nRet;
+}
+
+ORowSetValue OOp_Week::operate(const std::vector<ORowSetValue>& lhs) const
+{
+ if (lhs.empty() || lhs.size() > 2)
+ return ORowSetValue();
+
+ size_t nSize = lhs.size();
+
+ css::util::Date aD = lhs[nSize - 1].getDate();
+ Date aDate(aD.Day, aD.Month, aD.Year);
+
+ sal_Int16 nStartDay = SUNDAY;
+ if (nSize == 2 && !lhs[0].isNull())
+ nStartDay = lhs[0].getInt16();
+
+ return static_cast<sal_Int16>(aDate.GetWeekOfYear(static_cast<DayOfWeek>(nStartDay)));
+}
+
+ORowSetValue OOp_Year::operate(const ORowSetValue& lhs) const
+{
+ if (lhs.isNull())
+ return lhs;
+
+ css::util::Date aD = lhs.getDate();
+ return aD.Year;
+}
+
+ORowSetValue OOp_Hour::operate(const ORowSetValue& lhs) const
+{
+ if (lhs.isNull())
+ return lhs;
+
+ css::util::Time aT = lhs.getTime();
+ return static_cast<sal_Int16>(aT.Hours);
+}
+
+ORowSetValue OOp_Minute::operate(const ORowSetValue& lhs) const
+{
+ if (lhs.isNull())
+ return lhs;
+
+ css::util::Time aT = lhs.getTime();
+ return static_cast<sal_Int16>(aT.Minutes);
+}
+
+ORowSetValue OOp_Second::operate(const ORowSetValue& lhs) const
+{
+ if (lhs.isNull())
+ return lhs;
+
+ css::util::Time aT = lhs.getTime();
+ return static_cast<sal_Int16>(aT.Seconds);
+}
+
+ORowSetValue OOp_CurDate::operate(const std::vector<ORowSetValue>& lhs) const
+{
+ if (!lhs.empty())
+ return ORowSetValue();
+
+ Date aCurDate(Date::SYSTEM);
+ return aCurDate.GetUNODate();
+}
+
+ORowSetValue OOp_CurTime::operate(const std::vector<ORowSetValue>& lhs) const
+{
+ if (!lhs.empty())
+ return ORowSetValue();
+
+ tools::Time aCurTime(tools::Time::SYSTEM);
+ return aCurTime.GetUNOTime();
+}
+
+ORowSetValue OOp_Now::operate(const std::vector<ORowSetValue>& lhs) const
+{
+ if (!lhs.empty())
+ return ORowSetValue();
+
+ DateTime aCurTime(DateTime::SYSTEM);
+ return aCurTime.GetUNODateTime();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/file/FDriver.cxx b/connectivity/source/drivers/file/FDriver.cxx
new file mode 100644
index 0000000000..b24c4e67a5
--- /dev/null
+++ b/connectivity/source/drivers/file/FDriver.cxx
@@ -0,0 +1,206 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <file/FDriver.hxx>
+#include <file/FConnection.hxx>
+#include <file/fcode.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <comphelper/types.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <connectivity/dbexception.hxx>
+#include <strings.hrc>
+#include <resource/sharedresources.hxx>
+#include <utility>
+
+
+using namespace connectivity::file;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::sdbc;
+using namespace com::sun::star::sdbcx;
+using namespace com::sun::star::container;
+
+OFileDriver::OFileDriver(css::uno::Reference< css::uno::XComponentContext > _xContext)
+ : ODriver_BASE(m_aMutex)
+ ,m_xContext(std::move(_xContext))
+{
+}
+
+void OFileDriver::disposing()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+
+
+ for (auto const& connection : m_xConnections)
+ {
+ Reference< XComponent > xComp(connection.get(), UNO_QUERY);
+ if (xComp.is())
+ xComp->dispose();
+ }
+ m_xConnections.clear();
+
+ ODriver_BASE::disposing();
+}
+
+// XServiceInfo
+
+OUString SAL_CALL OFileDriver::getImplementationName( )
+{
+ return "com.sun.star.sdbc.driver.file.Driver";
+}
+
+sal_Bool SAL_CALL OFileDriver::supportsService( const OUString& _rServiceName )
+{
+ return cppu::supportsService(this, _rServiceName);
+}
+
+
+Sequence< OUString > SAL_CALL OFileDriver::getSupportedServiceNames( )
+{
+ return { "com.sun.star.sdbc.Driver", "com.sun.star.sdbcx.Driver" };
+}
+
+
+Reference< XConnection > SAL_CALL OFileDriver::connect( const OUString& url, const Sequence< PropertyValue >& info )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(ODriver_BASE::rBHelper.bDisposed);
+
+ rtl::Reference<OConnection> pCon = new OConnection(this);
+ pCon->construct(url,info);
+ m_xConnections.push_back(WeakReferenceHelper(*pCon));
+
+ return pCon;
+}
+
+sal_Bool SAL_CALL OFileDriver::acceptsURL( const OUString& url )
+{
+ return url.startsWith("sdbc:file:");
+}
+
+Sequence< DriverPropertyInfo > SAL_CALL OFileDriver::getPropertyInfo( const OUString& url, const Sequence< PropertyValue >& /*info*/ )
+{
+ if ( acceptsURL(url) )
+ {
+
+ Sequence< OUString > aBoolean { "0", "1" };
+
+ return
+ {
+ {
+ "CharSet"
+ ,"CharSet of the database."
+ ,false
+ ,{}
+ ,{}
+ },
+ {
+ "Extension"
+ ,"Extension of the file format."
+ ,false
+ ,".*"
+ ,{}
+ },
+ {
+ "ShowDeleted"
+ ,"Display inactive records."
+ ,false
+ ,"0"
+ ,aBoolean
+ },
+ {
+ "EnableSQL92Check"
+ ,"Use SQL92 naming constraints."
+ ,false
+ ,"0"
+ ,aBoolean
+ },
+ {
+ "UseRelativePath"
+ ,"Handle the connection url as relative path."
+ ,false
+ ,"0"
+ ,aBoolean
+ },
+ {
+ "URL"
+ ,"The URL of the database document which is used to create an absolute path."
+ ,false
+ ,{}
+ ,{}
+ }
+ };
+ } // if ( acceptsURL(url) )
+ {
+ ::connectivity::SharedResources aResources;
+ const OUString sMessage = aResources.getResourceString(STR_URI_SYNTAX_ERROR);
+ ::dbtools::throwGenericSQLException(sMessage ,*this);
+ } // if ( ! acceptsURL(url) )
+ return Sequence< DriverPropertyInfo >();
+}
+
+sal_Int32 SAL_CALL OFileDriver::getMajorVersion( )
+{
+ return 1;
+}
+
+sal_Int32 SAL_CALL OFileDriver::getMinorVersion( )
+{
+ return 0;
+}
+
+
+// XDataDefinitionSupplier
+Reference< XTablesSupplier > SAL_CALL OFileDriver::getDataDefinitionByConnection( const Reference< css::sdbc::XConnection >& connection )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(ODriver_BASE::rBHelper.bDisposed);
+
+ if (OConnection* pSearchConnection = comphelper::getFromUnoTunnel<OConnection>(connection))
+ {
+ for (auto const& elem : m_xConnections)
+ {
+ if (static_cast<OConnection*>( Reference< XConnection >::query(elem.get()).get() ) == pSearchConnection)
+ return pSearchConnection->createCatalog();
+ }
+ }
+ return {};
+}
+
+
+Reference< XTablesSupplier > SAL_CALL OFileDriver::getDataDefinitionByURL( const OUString& url, const Sequence< PropertyValue >& info )
+{
+ if ( ! acceptsURL(url) )
+ {
+ ::connectivity::SharedResources aResources;
+ const OUString sMessage = aResources.getResourceString(STR_URI_SYNTAX_ERROR);
+ ::dbtools::throwGenericSQLException(sMessage ,*this);
+ }
+ return getDataDefinitionByConnection(connect(url,info));
+}
+
+
+OOperandAttr::OOperandAttr(sal_uInt16 _nPos,const Reference< XPropertySet>& _xColumn)
+ : OOperandRow(_nPos,::comphelper::getINT32(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE))))
+{
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/file/FNoException.cxx b/connectivity/source/drivers/file/FNoException.cxx
new file mode 100644
index 0000000000..920bb38859
--- /dev/null
+++ b/connectivity/source/drivers/file/FNoException.cxx
@@ -0,0 +1,102 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <file/FCatalog.hxx>
+#include <file/fcomp.hxx>
+#include <file/fanalyzer.hxx>
+#include <file/FResultSet.hxx>
+#include <file/FPreparedStatement.hxx>
+#include <connectivity/FValue.hxx>
+#include <tools/debug.hxx>
+#include <TKeyValue.hxx>
+
+using namespace connectivity;
+using namespace connectivity::file;
+
+void OFileCatalog::refreshViews()
+{}
+void OFileCatalog::refreshGroups()
+{}
+void OFileCatalog::refreshUsers()
+{
+}
+
+OPredicateInterpreter::~OPredicateInterpreter()
+{
+ while(!m_aStack.empty())
+ {
+ delete m_aStack.top();
+ m_aStack.pop();
+ }
+ // m_aStack.clear();
+}
+
+void OPredicateCompiler::Clean()
+{
+ m_aCodeList.clear();
+}
+
+void OSQLAnalyzer::bindParameterRow(OValueRefRow const & _pRow)
+{
+ OCodeList& rCodeList = m_aCompiler->m_aCodeList;
+ for (auto const& code : rCodeList)
+ {
+ OOperandParam* pParam = dynamic_cast<OOperandParam*>(code.get());
+ if ( pParam )
+ pParam->bindValue(_pRow);
+ }
+}
+
+void OPreparedStatement::scanParameter(OSQLParseNode* pParseNode,std::vector< OSQLParseNode*>& _rParaNodes)
+{
+ DBG_ASSERT(pParseNode != nullptr,"OResultSet: internal error: invalid ParseNode");
+
+ // found parameter Name-Rule?
+ if (SQL_ISRULE(pParseNode,parameter))
+ {
+ DBG_ASSERT(pParseNode->count() >= 1,"OResultSet: faulty Parse Tree");
+ DBG_ASSERT(pParseNode->getChild(0)->getNodeType() == SQLNodeType::Punctuation,"OResultSet: faulty Parse Tree");
+
+ _rParaNodes.push_back(pParseNode);
+ // Further descend not necessary
+ return;
+ }
+
+ // Further descend in Parse Tree
+ for (size_t i = 0; i < pParseNode->count(); i++)
+ scanParameter(pParseNode->getChild(i),_rParaNodes);
+}
+
+std::unique_ptr<OKeyValue> OResultSet::GetOrderbyKeyValue(OValueRefRow const & _rRow)
+{
+ sal_uInt32 nBookmarkValue = std::abs((*_rRow)[0]->getValue().getInt32());
+
+ std::unique_ptr<OKeyValue> pKeyValue = OKeyValue::createKeyValue(nBookmarkValue);
+
+ for (auto const& elem : m_aOrderbyColumnNumber)
+ {
+ OSL_ENSURE(elem < static_cast<sal_Int32>(_rRow->size()),"Invalid index for orderkey values!");
+ pKeyValue->pushKey(new ORowSetValueDecorator((*_rRow)[elem]->getValue()));
+ }
+
+ return pKeyValue;
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/file/FNumericFunctions.cxx b/connectivity/source/drivers/file/FNumericFunctions.cxx
new file mode 100644
index 0000000000..7c7fdc7542
--- /dev/null
+++ b/connectivity/source/drivers/file/FNumericFunctions.cxx
@@ -0,0 +1,242 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <cmath>
+#include <basegfx/numeric/ftools.hxx>
+#include <file/FNumericFunctions.hxx>
+#include <rtl/math.hxx>
+
+using namespace connectivity;
+using namespace connectivity::file;
+
+ORowSetValue OOp_Abs::operate(const ORowSetValue& lhs) const
+{
+ if ( lhs.isNull() )
+ return lhs;
+
+ double nVal = lhs.getDouble();
+ if ( nVal < 0 )
+ nVal *= -1.0;
+ return fabs(nVal);
+}
+
+ORowSetValue OOp_Sign::operate(const ORowSetValue& lhs) const
+{
+ if ( lhs.isNull() )
+ return lhs;
+
+ sal_Int32 nRet = 0;
+ double nVal = lhs.getDouble();
+ if ( nVal < 0 )
+ nRet = -1;
+ else if ( nVal > 0 )
+ nRet = 1;
+
+ return nRet;
+}
+
+ORowSetValue OOp_Mod::operate(const ORowSetValue& lhs,const ORowSetValue& rhs) const
+{
+ if ( lhs.isNull() || rhs.isNull() )
+ return ORowSetValue();
+
+ return fmod(lhs.getDouble(), rhs.getDouble());
+}
+
+ORowSetValue OOp_Floor::operate(const ORowSetValue& lhs) const
+{
+ if ( lhs.isNull() )
+ return lhs;
+
+ return floor(lhs.getDouble());
+}
+
+ORowSetValue OOp_Ceiling::operate(const ORowSetValue& lhs) const
+{
+ if ( lhs.isNull() )
+ return lhs;
+
+ double nVal = lhs.getDouble();
+ return ceil(nVal);
+}
+
+ORowSetValue OOp_Round::operate(const std::vector<ORowSetValue>& lhs) const
+{
+ if ( lhs.empty() || lhs.size() > 2 )
+ return ORowSetValue();
+
+ size_t nSize = lhs.size();
+ double nVal = lhs[nSize-1].getDouble();
+
+ sal_Int32 nDec = 0;
+ if ( nSize == 2 && !lhs[0].isNull() )
+ nDec = lhs[0].getDouble();
+ return ::rtl::math::round(nVal,nDec);
+}
+
+ORowSetValue OOp_Exp::operate(const ORowSetValue& lhs) const
+{
+ if ( lhs.isNull() )
+ return lhs;
+
+ double nVal = lhs.getDouble();
+ return exp(nVal);
+}
+
+ORowSetValue OOp_Ln::operate(const ORowSetValue& lhs) const
+{
+ if ( lhs.isNull() || lhs.getDouble() < 0.0 )
+ return lhs;
+
+ double nVal = lhs.getDouble();
+ nVal = log(nVal);
+ if ( std::isnan(nVal) )
+ return ORowSetValue();
+ return nVal;
+}
+
+ORowSetValue OOp_Log::operate(const std::vector<ORowSetValue>& lhs) const
+{
+ if ( lhs.empty() || lhs.size() > 2 )
+ return ORowSetValue();
+ size_t nSize = lhs.size();
+ double nVal = log( lhs[nSize-1].getDouble() );
+
+
+ if ( nSize == 2 && !lhs[0].isNull() )
+ nVal /= log(lhs[0].getDouble());
+
+ if ( std::isnan(nVal) )
+ return ORowSetValue();
+ return nVal;
+}
+
+ORowSetValue OOp_Log10::operate(const ORowSetValue& lhs) const
+{
+ if ( lhs.isNull() || lhs.getDouble() < 0.0 )
+ return lhs;
+
+ double nVal = log(lhs.getDouble());
+ if ( std::isnan(nVal) )
+ return ORowSetValue();
+ nVal /= log(10.0);
+ return nVal;
+}
+
+ORowSetValue OOp_Pow::operate(const ORowSetValue& lhs,const ORowSetValue& rhs) const
+{
+ if ( lhs.isNull() || rhs.isNull() )
+ return lhs;
+
+ return pow(lhs.getDouble(), rhs.getDouble());
+}
+
+ORowSetValue OOp_Sqrt::operate(const ORowSetValue& lhs) const
+{
+ if ( lhs.isNull() )
+ return lhs;
+
+ double nVal = sqrt(lhs.getDouble());
+ if ( std::isnan(nVal) )
+ return ORowSetValue();
+ return nVal;
+}
+
+ORowSetValue OOp_Pi::operate(const std::vector<ORowSetValue>& /*lhs*/) const
+{
+ return M_PI;
+}
+
+ORowSetValue OOp_Cos::operate(const ORowSetValue& lhs) const
+{
+ if ( lhs.isNull() )
+ return lhs;
+
+ return cos(lhs.getDouble());
+}
+
+ORowSetValue OOp_Sin::operate(const ORowSetValue& lhs) const
+{
+ if ( lhs.isNull() )
+ return lhs;
+
+ return sin(lhs.getDouble());
+}
+
+ORowSetValue OOp_Tan::operate(const ORowSetValue& lhs) const
+{
+ if ( lhs.isNull() )
+ return lhs;
+
+ return tan(lhs.getDouble());
+}
+
+ORowSetValue OOp_ACos::operate(const ORowSetValue& lhs) const
+{
+ if ( lhs.isNull() )
+ return lhs;
+
+ return acos(lhs.getDouble());
+}
+
+ORowSetValue OOp_ASin::operate(const ORowSetValue& lhs) const
+{
+ if ( lhs.isNull() )
+ return lhs;
+
+ return asin(lhs.getDouble());
+}
+
+ORowSetValue OOp_ATan::operate(const ORowSetValue& lhs) const
+{
+ if ( lhs.isNull() )
+ return lhs;
+
+ return atan(lhs.getDouble());
+}
+
+ORowSetValue OOp_ATan2::operate(const ORowSetValue& lhs,const ORowSetValue& rhs) const
+{
+ if ( lhs.isNull() || rhs.isNull() )
+ return lhs;
+
+ return atan2(lhs.getDouble(), rhs.getDouble());
+}
+
+ORowSetValue OOp_Degrees::operate(const ORowSetValue& lhs) const
+{
+ if ( lhs.isNull() )
+ return lhs;
+
+ double nLhs = lhs.getDouble();
+ return basegfx::rad2deg(nLhs);
+}
+
+ORowSetValue OOp_Radians::operate(const ORowSetValue& lhs) const
+{
+ if ( lhs.isNull() )
+ return lhs;
+
+ double nLhs = lhs.getDouble();
+ return basegfx::deg2rad(nLhs);
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/file/FPreparedStatement.cxx b/connectivity/source/drivers/file/FPreparedStatement.cxx
new file mode 100644
index 0000000000..f2a8571b61
--- /dev/null
+++ b/connectivity/source/drivers/file/FPreparedStatement.cxx
@@ -0,0 +1,555 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <o3tl/safeint.hxx>
+#include <osl/diagnose.h>
+#include <file/FPreparedStatement.hxx>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <file/FResultSetMetaData.hxx>
+#include <cppuhelper/queryinterface.hxx>
+#include <cppuhelper/typeprovider.hxx>
+#include <comphelper/sequence.hxx>
+#include <connectivity/dbconversion.hxx>
+#include <connectivity/dbexception.hxx>
+#include <connectivity/dbtools.hxx>
+#include <connectivity/PColumn.hxx>
+#include <comphelper/types.hxx>
+#include <com/sun/star/sdbc/ColumnValue.hpp>
+#include <strings.hrc>
+
+using namespace connectivity;
+using namespace comphelper;
+using namespace ::dbtools;
+using namespace connectivity::file;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::sdbc;
+using namespace com::sun::star::sdbcx;
+using namespace com::sun::star::container;
+using namespace com::sun::star;
+
+IMPLEMENT_SERVICE_INFO(OPreparedStatement,"com.sun.star.sdbc.driver.file.PreparedStatement","com.sun.star.sdbc.PreparedStatement");
+
+OPreparedStatement::OPreparedStatement( OConnection* _pConnection)
+ : OStatement_BASE2( _pConnection )
+{
+}
+
+
+OPreparedStatement::~OPreparedStatement()
+{
+}
+
+
+void OPreparedStatement::disposing()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+
+ OStatement_BASE2::disposing();
+
+ m_xParamColumns = nullptr;
+ m_xMetaData.clear();
+ if(m_aParameterRow.is())
+ {
+ m_aParameterRow->clear();
+ m_aParameterRow = nullptr;
+ }
+}
+
+void OPreparedStatement::construct(const OUString& sql)
+{
+ OStatement_Base::construct(sql);
+
+ m_aParameterRow = new OValueRefVector();
+ m_aParameterRow->push_back(new ORowSetValueDecorator(sal_Int32(0)) );
+
+ Reference<XIndexAccess> xNames(m_xColNames,UNO_QUERY);
+
+ if ( m_aSQLIterator.getStatementType() == OSQLStatementType::Select )
+ m_xParamColumns = m_aSQLIterator.getParameters();
+ else
+ {
+ m_xParamColumns = new OSQLColumns();
+ // describe all parameters need for the resultset
+ describeParameter();
+ }
+
+ OValueRefRow aTemp;
+ OResultSet::setBoundedColumns(m_aEvaluateRow,aTemp,m_xParamColumns,xNames,false,m_xDBMetaData,m_aColMapping);
+}
+
+rtl::Reference<OResultSet> OPreparedStatement::makeResultSet()
+{
+ closeResultSet();
+
+ rtl::Reference<OResultSet> xResultSet(createResultSet());
+ m_xResultSet = uno::Reference<uno::XWeak>(xResultSet);
+ initializeResultSet(xResultSet.get());
+ initResultSet(xResultSet.get());
+ return xResultSet;
+}
+
+Any SAL_CALL OPreparedStatement::queryInterface( const Type & rType )
+{
+ Any aRet = OStatement_BASE2::queryInterface(rType);
+ return aRet.hasValue() ? aRet : ::cppu::queryInterface( rType,
+ static_cast< XPreparedStatement*>(this),
+ static_cast< XParameters*>(this),
+ static_cast< XResultSetMetaDataSupplier*>(this));
+}
+
+css::uno::Sequence< css::uno::Type > SAL_CALL OPreparedStatement::getTypes( )
+{
+ ::cppu::OTypeCollection aTypes( cppu::UnoType<XPreparedStatement>::get(),
+ cppu::UnoType<XParameters>::get(),
+ cppu::UnoType<XResultSetMetaDataSupplier>::get());
+
+ return ::comphelper::concatSequences(aTypes.getTypes(),OStatement_BASE2::getTypes());
+}
+
+
+Reference< XResultSetMetaData > SAL_CALL OPreparedStatement::getMetaData( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OStatement_BASE::rBHelper.bDisposed);
+
+
+ if(!m_xMetaData.is())
+ m_xMetaData = new OResultSetMetaData(m_aSQLIterator.getSelectColumns(),m_aSQLIterator.getTables().begin()->first,m_pTable.get());
+ return m_xMetaData;
+}
+
+
+void SAL_CALL OPreparedStatement::close( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OStatement_BASE::rBHelper.bDisposed);
+
+ closeResultSet();
+}
+
+
+sal_Bool SAL_CALL OPreparedStatement::execute( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OStatement_BASE::rBHelper.bDisposed);
+
+ rtl::Reference<OResultSet> xRS(makeResultSet());
+ // since we don't support the XMultipleResults interface, nobody will ever get that ResultSet...
+ if(xRS.is())
+ xRS->dispose();
+
+ return m_aSQLIterator.getStatementType() == OSQLStatementType::Select;
+}
+
+
+sal_Int32 SAL_CALL OPreparedStatement::executeUpdate( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OStatement_BASE::rBHelper.bDisposed);
+
+ rtl::Reference<OResultSet> xRS(makeResultSet());
+ if(xRS.is())
+ {
+ const sal_Int32 res(xRS->getRowCountResult());
+ // nobody will ever get that ResultSet...
+ xRS->dispose();
+ return res;
+ }
+ else
+ return 0;
+}
+
+
+void SAL_CALL OPreparedStatement::setString( sal_Int32 parameterIndex, const OUString& x )
+{
+ setParameter(parameterIndex,x);
+}
+
+
+Reference< XConnection > SAL_CALL OPreparedStatement::getConnection( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OStatement_BASE::rBHelper.bDisposed);
+
+ return m_pConnection;
+}
+
+
+Reference< XResultSet > SAL_CALL OPreparedStatement::executeQuery( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OStatement_BASE::rBHelper.bDisposed);
+
+ return makeResultSet();
+}
+
+
+void SAL_CALL OPreparedStatement::setBoolean( sal_Int32 parameterIndex, sal_Bool x )
+{
+ setParameter(parameterIndex,static_cast<bool>(x));
+}
+
+void SAL_CALL OPreparedStatement::setByte( sal_Int32 parameterIndex, sal_Int8 x )
+{
+ setParameter(parameterIndex,x);
+}
+
+
+void SAL_CALL OPreparedStatement::setDate( sal_Int32 parameterIndex, const util::Date& aData )
+{
+ setParameter(parameterIndex,DBTypeConversion::toDouble(aData));
+}
+
+void SAL_CALL OPreparedStatement::setTime( sal_Int32 parameterIndex, const util::Time& aVal )
+{
+ setParameter(parameterIndex,DBTypeConversion::toDouble(aVal));
+}
+
+
+void SAL_CALL OPreparedStatement::setTimestamp( sal_Int32 parameterIndex, const util::DateTime& aVal )
+{
+ setParameter(parameterIndex,DBTypeConversion::toDouble(aVal));
+}
+
+
+void SAL_CALL OPreparedStatement::setDouble( sal_Int32 parameterIndex, double x )
+{
+ setParameter(parameterIndex,x);
+}
+
+
+void SAL_CALL OPreparedStatement::setFloat( sal_Int32 parameterIndex, float x )
+{
+ setParameter(parameterIndex,x);
+}
+
+
+void SAL_CALL OPreparedStatement::setInt( sal_Int32 parameterIndex, sal_Int32 x )
+{
+ setParameter(parameterIndex,x);
+}
+
+
+void SAL_CALL OPreparedStatement::setLong( sal_Int32 /*parameterIndex*/, sal_Int64 /*aVal*/ )
+{
+ throwFeatureNotImplementedSQLException( "XParameters::setLong", *this );
+}
+
+
+void SAL_CALL OPreparedStatement::setNull( sal_Int32 parameterIndex, sal_Int32 /*sqlType*/ )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkAndResizeParameters(parameterIndex);
+
+ if ( m_aAssignValues.is() )
+ (*m_aAssignValues)[m_aParameterIndexes[parameterIndex]]->setNull();
+ else
+ (*m_aParameterRow)[parameterIndex]->setNull();
+}
+
+
+void SAL_CALL OPreparedStatement::setClob( sal_Int32 /*parameterIndex*/, const Reference< XClob >& /*x*/ )
+{
+ throwFeatureNotImplementedSQLException( "XParameters::setClob", *this );
+}
+
+
+void SAL_CALL OPreparedStatement::setBlob( sal_Int32 /*parameterIndex*/, const Reference< XBlob >& /*x*/ )
+{
+ throwFeatureNotImplementedSQLException( "XParameters::setBlob", *this );
+}
+
+
+void SAL_CALL OPreparedStatement::setArray( sal_Int32 /*parameterIndex*/, const Reference< XArray >& /*x*/ )
+{
+ throwFeatureNotImplementedSQLException( "XParameters::setArray", *this );
+}
+
+
+void SAL_CALL OPreparedStatement::setRef( sal_Int32 /*parameterIndex*/, const Reference< XRef >& /*x*/ )
+{
+ throwFeatureNotImplementedSQLException( "XParameters::setRef", *this );
+}
+
+
+void SAL_CALL OPreparedStatement::setObjectWithInfo( sal_Int32 parameterIndex, const Any& x, sal_Int32 sqlType, sal_Int32 scale )
+{
+ switch(sqlType)
+ {
+ case DataType::DECIMAL:
+ case DataType::NUMERIC:
+ setString(parameterIndex,::comphelper::getString(x));
+ break;
+ default:
+ ::dbtools::setObjectWithInfo(this,parameterIndex,x,sqlType,scale);
+ break;
+ }
+}
+
+
+void SAL_CALL OPreparedStatement::setObjectNull( sal_Int32 parameterIndex, sal_Int32 sqlType, const OUString& /*typeName*/ )
+{
+ setNull(parameterIndex,sqlType);
+}
+
+
+void SAL_CALL OPreparedStatement::setObject( sal_Int32 parameterIndex, const Any& x )
+{
+ if(!::dbtools::implSetObject(this,parameterIndex,x))
+ {
+ const OUString sError( m_pConnection->getResources().getResourceStringWithSubstitution(
+ STR_UNKNOWN_PARA_TYPE,
+ "$position$", OUString::number(parameterIndex)
+ ) );
+ ::dbtools::throwGenericSQLException(sError,*this);
+ }
+ // setObject (parameterIndex, x, sqlType, 0);
+}
+
+
+void SAL_CALL OPreparedStatement::setShort( sal_Int32 parameterIndex, sal_Int16 x )
+{
+ setParameter(parameterIndex,x);
+}
+
+
+void SAL_CALL OPreparedStatement::setBytes( sal_Int32 parameterIndex, const Sequence< sal_Int8 >& x )
+{
+ setParameter(parameterIndex,x);
+}
+
+
+void SAL_CALL OPreparedStatement::setCharacterStream( sal_Int32 parameterIndex, const Reference< css::io::XInputStream >& x, sal_Int32 length )
+{
+ setBinaryStream(parameterIndex,x,length );
+}
+
+
+void SAL_CALL OPreparedStatement::setBinaryStream( sal_Int32 parameterIndex, const Reference< css::io::XInputStream >& x, sal_Int32 length )
+{
+ if(!x.is())
+ ::dbtools::throwFunctionSequenceException(*this);
+
+ Sequence<sal_Int8> aSeq;
+ x->readBytes(aSeq,length);
+ setParameter(parameterIndex,aSeq);
+}
+
+
+void SAL_CALL OPreparedStatement::clearParameters( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OStatement_BASE::rBHelper.bDisposed);
+
+ m_aParameterRow->clear();
+ m_aParameterRow->push_back(new ORowSetValueDecorator(sal_Int32(0)) );
+}
+
+rtl::Reference<OResultSet> OPreparedStatement::createResultSet()
+{
+ return new OResultSet(this,m_aSQLIterator);
+}
+
+void OPreparedStatement::initResultSet(OResultSet *pResultSet)
+{
+ // check if we got enough parameters
+ if ( (m_aParameterRow.is() && ( m_aParameterRow->size() -1 ) < m_xParamColumns->size()) ||
+ (m_xParamColumns.is() && !m_aParameterRow.is() && !m_aParameterRow->empty()) )
+ m_pConnection->throwGenericSQLException(STR_INVALID_PARA_COUNT,*this);
+
+ pResultSet->OpenImpl();
+ pResultSet->setMetaData(getMetaData());
+}
+
+void SAL_CALL OPreparedStatement::acquire() noexcept
+{
+ OStatement_BASE2::acquire();
+}
+
+void SAL_CALL OPreparedStatement::release() noexcept
+{
+ OStatement_BASE2::release();
+}
+
+void OPreparedStatement::checkAndResizeParameters(sal_Int32 parameterIndex)
+{
+ ::connectivity::checkDisposed(OStatement_BASE::rBHelper.bDisposed);
+ if ( m_aAssignValues.is() && (parameterIndex < 1 || o3tl::make_unsigned(parameterIndex) >= m_aParameterIndexes.size()) )
+ throwInvalidIndexException(*this);
+ else if ( static_cast<sal_Int32>(m_aParameterRow->size()) <= parameterIndex )
+ {
+ sal_Int32 i = m_aParameterRow->size();
+ m_aParameterRow->resize(parameterIndex+1);
+ for ( ; i <= parameterIndex; ++i)
+ {
+ if ( !(*m_aParameterRow)[i].is() )
+ (*m_aParameterRow)[i] = new ORowSetValueDecorator;
+ }
+ }
+}
+
+void OPreparedStatement::setParameter(sal_Int32 parameterIndex, const ORowSetValue& x)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkAndResizeParameters(parameterIndex);
+
+ if(m_aAssignValues.is())
+ *(*m_aAssignValues)[m_aParameterIndexes[parameterIndex]] = x;
+ else
+ *((*m_aParameterRow)[parameterIndex]) = x;
+}
+
+sal_uInt32 OPreparedStatement::AddParameter(OSQLParseNode const * pParameter, const Reference<XPropertySet>& _xCol)
+{
+ OSL_ENSURE(SQL_ISRULE(pParameter,parameter),"OResultSet::AddParameter: Argument is not a parameter");
+ OSL_ENSURE(pParameter->count() > 0,"OResultSet: Error in Parse Tree");
+
+ OUString sParameterName;
+ // set up Parameter-Column:
+ sal_Int32 eType = DataType::VARCHAR;
+ sal_uInt32 nPrecision = 255;
+ sal_Int32 nScale = 0;
+ sal_Int32 nNullable = ColumnValue::NULLABLE;
+
+ if (_xCol.is())
+ {
+ // Use type, precision, scale ... from the given column,
+ // because this Column will get a value assigned or
+ // with this Column the value will be compared.
+ _xCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE)) >>= eType;
+ _xCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PRECISION)) >>= nPrecision;
+ _xCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCALE)) >>= nScale;
+ _xCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISNULLABLE)) >>= nNullable;
+ _xCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME)) >>= sParameterName;
+ }
+
+ Reference<XPropertySet> xParaColumn = new connectivity::parse::OParseColumn(sParameterName
+ ,OUString()
+ ,OUString()
+ ,OUString()
+ ,nNullable
+ ,nPrecision
+ ,nScale
+ ,eType
+ ,false
+ ,false
+ ,m_aSQLIterator.isCaseSensitive()
+ ,OUString()
+ ,OUString()
+ ,OUString());
+ m_xParamColumns->push_back(xParaColumn);
+ return m_xParamColumns->size();
+}
+
+void OPreparedStatement::describeColumn(OSQLParseNode const * _pParameter, OSQLParseNode const * _pNode,const OSQLTable& _xTable)
+{
+ Reference<XPropertySet> xProp;
+ if(SQL_ISRULE(_pNode,column_ref))
+ {
+ OUString sColumnName,sTableRange;
+ m_aSQLIterator.getColumnRange(_pNode,sColumnName,sTableRange);
+ if ( !sColumnName.isEmpty() )
+ {
+ Reference<XNameAccess> xNameAccess = _xTable->getColumns();
+ if(xNameAccess->hasByName(sColumnName))
+ xNameAccess->getByName(sColumnName) >>= xProp;
+ AddParameter(_pParameter,xProp);
+ }
+ }
+ // else
+ // AddParameter(_pParameter,xProp);
+}
+
+void OPreparedStatement::describeParameter()
+{
+ std::vector< OSQLParseNode*> aParseNodes;
+ scanParameter(m_pParseTree,aParseNodes);
+ if ( aParseNodes.empty() )
+ return;
+
+ // m_xParamColumns = new OSQLColumns();
+ const OSQLTables& rTabs = m_aSQLIterator.getTables();
+ if( !rTabs.empty() )
+ {
+ OSQLTable xTable = rTabs.begin()->second;
+ for (auto const& parseNode : aParseNodes)
+ {
+ describeColumn(parseNode,parseNode->getParent()->getChild(0),xTable);
+ }
+ }
+}
+void OPreparedStatement::initializeResultSet(OResultSet* pRS)
+{
+ OStatement_Base::initializeResultSet(pRS);
+
+ // Substitute parameter (AssignValues and criteria):
+ if (m_xParamColumns->empty())
+ return;
+
+ // begin with AssignValues
+ sal_uInt16 nParaCount=0; // gives the current number of previously set Parameters
+
+ // search for parameters to be substituted:
+ size_t nCount = m_aAssignValues.is() ? m_aAssignValues->size() : 1; // 1 is important for the Criteria
+ for (size_t j = 1; j < nCount; j++)
+ {
+ sal_uInt32 nParameter = (*m_aAssignValues).getParameterIndex(j);
+ if (nParameter == SQL_NO_PARAMETER)
+ continue; // this AssignValue is no Parameter
+
+ ++nParaCount; // now the Parameter is valid
+ }
+
+ if (m_aParameterRow.is() && (m_xParamColumns->size()+1) != m_aParameterRow->size() )
+ {
+ sal_Int32 i = m_aParameterRow->size();
+ sal_Int32 nParamColumns = m_xParamColumns->size()+1;
+ m_aParameterRow->resize(nParamColumns);
+ for ( ;i < nParamColumns; ++i )
+ {
+ if ( !(*m_aParameterRow)[i].is() )
+ (*m_aParameterRow)[i] = new ORowSetValueDecorator;
+ }
+ }
+ if (m_aParameterRow.is() && nParaCount < m_aParameterRow->size() )
+ m_pSQLAnalyzer->bindParameterRow(m_aParameterRow);
+}
+
+void OPreparedStatement::parseParamterElem(const OUString& _sColumnName, OSQLParseNode* pRow_Value_Constructor_Elem)
+{
+ Reference<XPropertySet> xCol;
+ m_xColNames->getByName(_sColumnName) >>= xCol;
+ sal_Int32 nParameter = -1;
+ if(m_xParamColumns.is())
+ {
+ OSQLColumns::const_iterator aIter = find(m_xParamColumns->begin(),m_xParamColumns->end(),_sColumnName,::comphelper::UStringMixEqual(m_pTable->isCaseSensitive()));
+ if(aIter != m_xParamColumns->end())
+ nParameter = m_xParamColumns->size() - (m_xParamColumns->end() - aIter) + 1;// +1 because the rows start at 1
+ }
+ if(nParameter == -1)
+ nParameter = AddParameter(pRow_Value_Constructor_Elem,xCol);
+ // Save number of parameter in the variable:
+ SetAssignValue(_sColumnName, OUString(), true, nParameter);
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/file/FResultSet.cxx b/connectivity/source/drivers/file/FResultSet.cxx
new file mode 100644
index 0000000000..5612c68fee
--- /dev/null
+++ b/connectivity/source/drivers/file/FResultSet.cxx
@@ -0,0 +1,1579 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <file/FResultSet.hxx>
+#include <sqlbison.hxx>
+#include <file/FResultSetMetaData.hxx>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/container/XIndexAccess.hpp>
+#include <comphelper/sequence.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <cppuhelper/typeprovider.hxx>
+#include <connectivity/dbtools.hxx>
+#include <cppuhelper/propshlp.hxx>
+#include <o3tl/safeint.hxx>
+#include <sal/log.hxx>
+#include <iterator>
+#include <com/sun/star/sdbc/ResultSetType.hpp>
+#include <com/sun/star/sdbc/FetchDirection.hpp>
+#include <com/sun/star/sdbc/ResultSetConcurrency.hpp>
+#include <com/sun/star/sdbcx/XIndexesSupplier.hpp>
+
+#include <algorithm>
+#include <connectivity/dbexception.hxx>
+#include <comphelper/types.hxx>
+#include <resource/sharedresources.hxx>
+#include <strings.hrc>
+#include <comphelper/diagnose_ex.hxx>
+
+using namespace ::comphelper;
+using namespace connectivity;
+using namespace connectivity::file;
+using namespace ::cppu;
+using namespace dbtools;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::sdbc;
+using namespace com::sun::star::sdbcx;
+using namespace com::sun::star::container;
+
+namespace
+{
+ void lcl_throwError(TranslateId pErrorId, const css::uno::Reference< css::uno::XInterface>& _xContext)
+ {
+ ::connectivity::SharedResources aResources;
+ const OUString sMessage = aResources.getResourceString(pErrorId);
+ ::dbtools::throwGenericSQLException(sMessage ,_xContext);
+ }
+}
+
+IMPLEMENT_SERVICE_INFO(OResultSet,"com.sun.star.sdbcx.drivers.file.ResultSet","com.sun.star.sdbc.ResultSet");
+
+OResultSet::OResultSet(OStatement_Base* pStmt,OSQLParseTreeIterator& _aSQLIterator) : OResultSet_BASE(m_aMutex)
+ ,::comphelper::OPropertyContainer(OResultSet_BASE::rBHelper)
+ ,m_aSkipDeletedSet(this)
+ ,m_pParseTree(pStmt->getParseTree())
+ ,m_pSQLAnalyzer(nullptr)
+ ,m_aSQLIterator(_aSQLIterator)
+ ,m_nFetchSize(0)
+ ,m_nResultSetType(ResultSetType::SCROLL_INSENSITIVE)
+ ,m_nFetchDirection(FetchDirection::FORWARD)
+ ,m_nResultSetConcurrency(ResultSetConcurrency::UPDATABLE)
+ ,m_xStatement(*pStmt)
+ ,m_nRowPos(-1)
+ ,m_nFilePos(0)
+ ,m_nLastVisitedPos(-1)
+ ,m_nRowCountResult(-1)
+ ,m_nColumnCount(0)
+ ,m_bWasNull(false)
+ ,m_bInserted(false)
+ ,m_bRowUpdated(false)
+ ,m_bRowInserted(false)
+ ,m_bRowDeleted(false)
+ ,m_bShowDeleted(pStmt->getOwnConnection()->showDeleted())
+ ,m_bIsCount(false)
+{
+ osl_atomic_increment( &m_refCount );
+ m_bIsCount = (m_pParseTree &&
+ m_pParseTree->count() > 2 &&
+ SQL_ISRULE(m_pParseTree->getChild(2),scalar_exp_commalist) &&
+ SQL_ISRULE(m_pParseTree->getChild(2)->getChild(0),derived_column) &&
+ SQL_ISRULE(m_pParseTree->getChild(2)->getChild(0)->getChild(0),general_set_fct) &&
+ m_pParseTree->getChild(2)->getChild(0)->getChild(0)->count() == 4
+ );
+
+ m_nResultSetConcurrency = isCount() ? ResultSetConcurrency::READ_ONLY : ResultSetConcurrency::UPDATABLE;
+ construct();
+ m_aSkipDeletedSet.SetDeletedVisible(m_bShowDeleted);
+ osl_atomic_decrement( &m_refCount );
+}
+
+
+OResultSet::~OResultSet()
+{
+ osl_atomic_increment( &m_refCount );
+ disposing();
+}
+
+void OResultSet::construct()
+{
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHSIZE), PROPERTY_ID_FETCHSIZE, 0,&m_nFetchSize, ::cppu::UnoType<sal_Int32>::get());
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETTYPE), PROPERTY_ID_RESULTSETTYPE, PropertyAttribute::READONLY,&m_nResultSetType, ::cppu::UnoType<sal_Int32>::get());
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHDIRECTION), PROPERTY_ID_FETCHDIRECTION, 0,&m_nFetchDirection, ::cppu::UnoType<sal_Int32>::get());
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETCONCURRENCY), PROPERTY_ID_RESULTSETCONCURRENCY,PropertyAttribute::READONLY,&m_nResultSetConcurrency, ::cppu::UnoType<sal_Int32>::get());
+}
+
+void OResultSet::disposing()
+{
+ OPropertySetHelper::disposing();
+
+ ::osl::MutexGuard aGuard(m_aMutex);
+ m_xStatement.clear();
+ m_xMetaData.clear();
+ m_pParseTree = nullptr;
+ m_xColNames.clear();
+ m_xColumns = nullptr;
+ m_xColsIdx.clear();
+
+ if ( m_pTable.is() )
+ m_pTable->removeEventListener(this);
+ m_pTable.clear();
+
+ m_pFileSet = nullptr;
+ m_pSortIndex.reset();
+
+ if(m_aInsertRow.is())
+ m_aInsertRow->clear();
+
+ m_aSkipDeletedSet.clear();
+}
+
+Any SAL_CALL OResultSet::queryInterface( const Type & rType )
+{
+ Any aRet = OPropertySetHelper::queryInterface(rType);
+ return aRet.hasValue() ? aRet : OResultSet_BASE::queryInterface(rType);
+}
+
+Sequence< Type > SAL_CALL OResultSet::getTypes( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ OTypeCollection aTypes( cppu::UnoType<css::beans::XMultiPropertySet>::get(),
+ cppu::UnoType<css::beans::XPropertySet>::get(),
+ cppu::UnoType<css::beans::XPropertySet>::get());
+
+ return ::comphelper::concatSequences(aTypes.getTypes(),OResultSet_BASE::getTypes());
+}
+
+
+sal_Int32 SAL_CALL OResultSet::findColumn( const OUString& columnName )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+
+ Reference< XResultSetMetaData > xMeta = getMetaData();
+ sal_Int32 nLen = xMeta->getColumnCount();
+ sal_Int32 i = 1;
+ for(;i<=nLen;++i)
+ {
+ if(xMeta->isCaseSensitive(i) ? columnName == xMeta->getColumnName(i) :
+ columnName.equalsIgnoreAsciiCase(xMeta->getColumnName(i)))
+ return i;
+ }
+
+ ::dbtools::throwInvalidColumnException( columnName, *this );
+ assert(false);
+ return 0; // Never reached
+}
+
+const ORowSetValue& OResultSet::getValue(sal_Int32 columnIndex)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ checkIndex(columnIndex );
+
+
+ m_bWasNull = (*m_aSelectRow)[columnIndex]->getValue().isNull();
+ return *(*m_aSelectRow)[columnIndex];
+}
+
+void OResultSet::checkIndex(sal_Int32 columnIndex )
+{
+ if ( columnIndex <= 0
+ || columnIndex >= m_nColumnCount )
+ ::dbtools::throwInvalidIndexException(*this);
+}
+
+Reference< css::io::XInputStream > SAL_CALL OResultSet::getBinaryStream( sal_Int32 /*columnIndex*/ )
+{
+ return nullptr;
+}
+
+Reference< css::io::XInputStream > SAL_CALL OResultSet::getCharacterStream( sal_Int32 /*columnIndex*/ )
+{
+ return nullptr;
+}
+
+
+sal_Bool SAL_CALL OResultSet::getBoolean( sal_Int32 columnIndex )
+{
+ return getValue(columnIndex).getBool();
+}
+
+
+sal_Int8 SAL_CALL OResultSet::getByte( sal_Int32 columnIndex )
+{
+ return getValue(columnIndex).getInt8();
+}
+
+
+Sequence< sal_Int8 > SAL_CALL OResultSet::getBytes( sal_Int32 columnIndex )
+{
+ return getValue(columnIndex).getSequence();
+}
+
+
+css::util::Date SAL_CALL OResultSet::getDate( sal_Int32 columnIndex )
+{
+ return getValue(columnIndex).getDate();
+}
+
+
+double SAL_CALL OResultSet::getDouble( sal_Int32 columnIndex )
+{
+ return getValue(columnIndex).getDouble();
+}
+
+
+float SAL_CALL OResultSet::getFloat( sal_Int32 columnIndex )
+{
+ return getValue(columnIndex).getFloat();
+}
+
+
+sal_Int32 SAL_CALL OResultSet::getInt( sal_Int32 columnIndex )
+{
+ return getValue(columnIndex).getInt32();
+}
+
+
+sal_Int32 SAL_CALL OResultSet::getRow( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ OSL_ENSURE((m_bShowDeleted || !m_aRow->isDeleted()),"getRow called for deleted row");
+
+ return m_aSkipDeletedSet.getMappedPosition((*m_aRow)[0]->getValue().getInt32());
+}
+
+
+sal_Int64 SAL_CALL OResultSet::getLong( sal_Int32 columnIndex )
+{
+ return getValue(columnIndex).getLong();
+}
+
+
+Reference< XResultSetMetaData > SAL_CALL OResultSet::getMetaData( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+
+ if(!m_xMetaData.is())
+ m_xMetaData = new OResultSetMetaData(m_xColumns,m_aSQLIterator.getTables().begin()->first,m_pTable.get());
+ return m_xMetaData;
+}
+
+Reference< XArray > SAL_CALL OResultSet::getArray( sal_Int32 /*columnIndex*/ )
+{
+ return nullptr;
+}
+
+
+Reference< XClob > SAL_CALL OResultSet::getClob( sal_Int32 /*columnIndex*/ )
+{
+ return nullptr;
+}
+
+Reference< XBlob > SAL_CALL OResultSet::getBlob( sal_Int32 /*columnIndex*/ )
+{
+ return nullptr;
+}
+
+
+Reference< XRef > SAL_CALL OResultSet::getRef( sal_Int32 /*columnIndex*/ )
+{
+ return nullptr;
+}
+
+
+Any SAL_CALL OResultSet::getObject( sal_Int32 columnIndex, const Reference< css::container::XNameAccess >& /*typeMap*/ )
+{
+ return getValue(columnIndex).makeAny();
+}
+
+
+sal_Int16 SAL_CALL OResultSet::getShort( sal_Int32 columnIndex )
+{
+ return getValue(columnIndex).getInt16();
+}
+
+OUString SAL_CALL OResultSet::getString( sal_Int32 columnIndex )
+{
+ return getValue(columnIndex).getString();
+}
+
+css::util::Time SAL_CALL OResultSet::getTime( sal_Int32 columnIndex )
+{
+ return getValue(columnIndex).getTime();
+}
+
+css::util::DateTime SAL_CALL OResultSet::getTimestamp( sal_Int32 columnIndex )
+{
+ return getValue(columnIndex).getDateTime();
+}
+
+
+sal_Bool SAL_CALL OResultSet::isAfterLast( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+
+ return m_nRowPos == sal_Int32(m_pFileSet->size());
+}
+
+sal_Bool SAL_CALL OResultSet::isFirst( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+
+ return m_nRowPos == 0;
+}
+
+sal_Bool SAL_CALL OResultSet::isLast( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+
+ return m_nRowPos == sal_Int32(m_pFileSet->size() - 1);
+}
+
+void SAL_CALL OResultSet::beforeFirst( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+
+ if(first())
+ previous();
+}
+
+void SAL_CALL OResultSet::afterLast( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+
+ if(last())
+ next();
+}
+
+
+void SAL_CALL OResultSet::close( )
+{
+ dispose();
+}
+
+
+sal_Bool SAL_CALL OResultSet::first( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+ return m_pTable.is() && m_aSkipDeletedSet.skipDeleted(IResultSetHelper::FIRST,1,true);
+}
+
+
+sal_Bool SAL_CALL OResultSet::last( )
+{
+ // here I know definitely that I stand on the last record
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+ return m_pTable.is() && m_aSkipDeletedSet.skipDeleted(IResultSetHelper::LAST,1,true);
+}
+
+sal_Bool SAL_CALL OResultSet::absolute( sal_Int32 row )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+ return m_pTable.is() && m_aSkipDeletedSet.skipDeleted(IResultSetHelper::ABSOLUTE1,row,true);
+}
+
+sal_Bool SAL_CALL OResultSet::relative( sal_Int32 row )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+ return m_pTable.is() && m_aSkipDeletedSet.skipDeleted(IResultSetHelper::RELATIVE1,row,true);
+}
+
+sal_Bool SAL_CALL OResultSet::previous( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+ return m_pTable.is() && m_aSkipDeletedSet.skipDeleted(IResultSetHelper::PRIOR,0,true);
+}
+
+Reference< XInterface > SAL_CALL OResultSet::getStatement( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+
+ return m_xStatement;
+}
+
+
+sal_Bool SAL_CALL OResultSet::rowDeleted( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+
+ return m_bRowDeleted;
+}
+
+sal_Bool SAL_CALL OResultSet::rowInserted( )
+{ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+
+ return m_bRowInserted;
+}
+
+sal_Bool SAL_CALL OResultSet::rowUpdated( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+
+ return m_bRowUpdated;
+}
+
+
+sal_Bool SAL_CALL OResultSet::isBeforeFirst( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+
+ return m_nRowPos == -1;
+}
+
+sal_Bool SAL_CALL OResultSet::next( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ return m_pTable.is() && m_aSkipDeletedSet.skipDeleted(IResultSetHelper::NEXT,1,true);
+}
+
+
+sal_Bool SAL_CALL OResultSet::wasNull( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ return m_bWasNull;
+}
+
+
+void SAL_CALL OResultSet::cancel( )
+{
+}
+
+void SAL_CALL OResultSet::clearWarnings( )
+{
+}
+
+Any SAL_CALL OResultSet::getWarnings( )
+{
+ return Any();
+}
+
+void SAL_CALL OResultSet::insertRow( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+
+ if(!m_bInserted || !m_pTable.is())
+ throwFunctionSequenceException(*this);
+
+ // we know that we append new rows at the end
+ // so we have to know where the end is
+ (void)m_aSkipDeletedSet.skipDeleted(IResultSetHelper::LAST,1,false);
+ m_bRowInserted = m_pTable->InsertRow(*m_aInsertRow, m_xColsIdx);
+ if(m_bRowInserted && m_pFileSet.is())
+ {
+ sal_Int32 nPos = (*m_aInsertRow)[0]->getValue().getInt32();
+ m_pFileSet->push_back(nPos);
+ *(*m_aInsertRow)[0] = sal_Int32(m_pFileSet->size());
+ clearInsertRow();
+
+ m_aSkipDeletedSet.insertNewPosition((*m_aRow)[0]->getValue().getInt32());
+ }
+}
+
+void SAL_CALL OResultSet::updateRow( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ if(!m_pTable.is() || m_pTable->isReadOnly())
+ lcl_throwError(STR_TABLE_READONLY,*this);
+
+ m_bRowUpdated = m_pTable->UpdateRow(*m_aInsertRow, m_aRow,m_xColsIdx);
+ *(*m_aInsertRow)[0] = (*m_aRow)[0]->getValue().getInt32();
+
+ clearInsertRow();
+}
+
+void SAL_CALL OResultSet::deleteRow()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ if(!m_pTable.is() || m_pTable->isReadOnly())
+ lcl_throwError(STR_TABLE_READONLY,*this);
+ if (m_bShowDeleted)
+ lcl_throwError(STR_DELETE_ROW,*this);
+ if(m_aRow->isDeleted())
+ lcl_throwError(STR_ROW_ALREADY_DELETED,*this);
+
+ sal_Int32 nPos = (*m_aRow)[0]->getValue().getInt32();
+ m_bRowDeleted = m_pTable->DeleteRow(*m_xColumns);
+ if(m_bRowDeleted && m_pFileSet.is())
+ {
+ m_aRow->setDeleted(true);
+ // don't touch the m_pFileSet member here
+ m_aSkipDeletedSet.deletePosition(nPos);
+ }
+}
+
+void SAL_CALL OResultSet::cancelRowUpdates( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+
+ m_bInserted = false;
+ m_bRowUpdated = false;
+ m_bRowInserted = false;
+ m_bRowDeleted = false;
+
+ if(m_aInsertRow.is())
+ {
+ OValueRefVector::iterator aIter = m_aInsertRow->begin()+1;
+ for(;aIter != m_aInsertRow->end();++aIter)
+ {
+ (*aIter)->setBound(false);
+ (*aIter)->setNull();
+ }
+ }
+}
+
+
+void SAL_CALL OResultSet::moveToInsertRow( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ if(!m_pTable.is() || m_pTable->isReadOnly())
+ lcl_throwError(STR_TABLE_READONLY,*this);
+
+ m_bInserted = true;
+
+ OValueRefVector::iterator aIter = m_aInsertRow->begin()+1;
+ for(;aIter != m_aInsertRow->end();++aIter)
+ {
+ (*aIter)->setBound(false);
+ (*aIter)->setNull();
+ }
+}
+
+
+void SAL_CALL OResultSet::moveToCurrentRow( )
+{
+}
+
+void OResultSet::updateValue(sal_Int32 columnIndex ,const ORowSetValue& x)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ checkIndex(columnIndex );
+ columnIndex = mapColumn(columnIndex);
+
+ (*m_aInsertRow)[columnIndex]->setBound(true);
+ *(*m_aInsertRow)[columnIndex] = x;
+}
+
+
+void SAL_CALL OResultSet::updateNull( sal_Int32 columnIndex )
+{
+ ORowSetValue aEmpty;
+ updateValue(columnIndex,aEmpty);
+}
+
+
+void SAL_CALL OResultSet::updateBoolean( sal_Int32 columnIndex, sal_Bool x )
+{
+ updateValue(columnIndex, static_cast<bool>(x));
+}
+
+void SAL_CALL OResultSet::updateByte( sal_Int32 columnIndex, sal_Int8 x )
+{
+ updateValue(columnIndex,x);
+}
+
+
+void SAL_CALL OResultSet::updateShort( sal_Int32 columnIndex, sal_Int16 x )
+{
+ updateValue(columnIndex,x);
+}
+
+void SAL_CALL OResultSet::updateInt( sal_Int32 columnIndex, sal_Int32 x )
+{
+ updateValue(columnIndex,x);
+}
+
+void SAL_CALL OResultSet::updateLong( sal_Int32 /*columnIndex*/, sal_Int64 /*x*/ )
+{
+ ::dbtools::throwFeatureNotImplementedSQLException( "XRowUpdate::updateLong", *this );
+}
+
+void SAL_CALL OResultSet::updateFloat( sal_Int32 columnIndex, float x )
+{
+ updateValue(columnIndex,x);
+}
+
+
+void SAL_CALL OResultSet::updateDouble( sal_Int32 columnIndex, double x )
+{
+ updateValue(columnIndex,x);
+}
+
+void SAL_CALL OResultSet::updateString( sal_Int32 columnIndex, const OUString& x )
+{
+ updateValue(columnIndex,x);
+}
+
+void SAL_CALL OResultSet::updateBytes( sal_Int32 columnIndex, const Sequence< sal_Int8 >& x )
+{
+ updateValue(columnIndex,x);
+}
+
+void SAL_CALL OResultSet::updateDate( sal_Int32 columnIndex, const css::util::Date& x )
+{
+ updateValue(columnIndex,x);
+}
+
+
+void SAL_CALL OResultSet::updateTime( sal_Int32 columnIndex, const css::util::Time& x )
+{
+ updateValue(columnIndex,x);
+}
+
+
+void SAL_CALL OResultSet::updateTimestamp( sal_Int32 columnIndex, const css::util::DateTime& x )
+{
+ updateValue(columnIndex,x);
+}
+
+
+void SAL_CALL OResultSet::updateBinaryStream( sal_Int32 columnIndex, const Reference< css::io::XInputStream >& x, sal_Int32 length )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ if(!x.is())
+ ::dbtools::throwFunctionSequenceException(*this);
+
+ Sequence<sal_Int8> aSeq;
+ x->readBytes(aSeq,length);
+ updateValue(columnIndex,aSeq);
+}
+
+void SAL_CALL OResultSet::updateCharacterStream( sal_Int32 columnIndex, const Reference< css::io::XInputStream >& x, sal_Int32 length )
+{
+ updateBinaryStream(columnIndex,x,length);
+}
+
+void SAL_CALL OResultSet::refreshRow( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+}
+
+void SAL_CALL OResultSet::updateObject( sal_Int32 columnIndex, const Any& x )
+{
+ if (!::dbtools::implUpdateObject(this, columnIndex, x))
+ throw SQLException();
+}
+
+
+void SAL_CALL OResultSet::updateNumericObject( sal_Int32 columnIndex, const Any& x, sal_Int32 /*scale*/ )
+{
+ if (!::dbtools::implUpdateObject(this, columnIndex, x))
+ throw SQLException();
+}
+
+IPropertyArrayHelper* OResultSet::createArrayHelper( ) const
+{
+ Sequence< Property > aProps;
+ describeProperties(aProps);
+ return new ::cppu::OPropertyArrayHelper(aProps);
+}
+
+IPropertyArrayHelper & OResultSet::getInfoHelper()
+{
+ return *getArrayHelper();
+}
+
+
+bool OResultSet::ExecuteRow(IResultSetHelper::Movement eFirstCursorPosition,
+ sal_Int32 nFirstOffset,
+ bool bEvaluate,
+ bool bRetrieveData)
+{
+ OSL_ENSURE(m_pSQLAnalyzer,"OResultSet::ExecuteRow: Analyzer isn't set!");
+
+ // For further Fetch-Operations this information may possibly be changed ...
+ IResultSetHelper::Movement eCursorPosition = eFirstCursorPosition;
+ sal_Int32 nOffset = nFirstOffset;
+
+ if (!m_pTable.is())
+ return false;
+
+ const OSQLColumns & rTableCols = *(m_pTable->getTableColumns());
+ bool bHasRestriction = m_pSQLAnalyzer->hasRestriction();
+again:
+
+ // protect from reading over the end when somebody is inserting while we are reading
+ // this method works only for dBase at the moment!!!
+ if (eCursorPosition == IResultSetHelper::NEXT && m_nFilePos == m_nLastVisitedPos)
+ {
+ return false;
+ }
+
+ if (!m_pTable.is() || !m_pTable->seekRow(eCursorPosition, nOffset, m_nFilePos))
+ {
+ return false;
+ }
+
+ if (!bEvaluate) // If no evaluation runs, then just fill the results-row
+ {
+ m_pTable->fetchRow(m_aRow,rTableCols, bRetrieveData);
+ }
+ else
+ {
+ m_pTable->fetchRow(m_aEvaluateRow, rTableCols, bRetrieveData || bHasRestriction);
+
+ if ( ( !m_bShowDeleted
+ && m_aEvaluateRow->isDeleted()
+ )
+ || ( bHasRestriction
+ && !m_pSQLAnalyzer->evaluateRestriction()
+ )
+ )
+ { // Evaluate the next record
+ // delete current row in Keyset
+ if (m_pFileSet.is())
+ {
+ OSL_ENSURE(eCursorPosition == IResultSetHelper::NEXT, "Wrong CursorPosition!");
+ eCursorPosition = IResultSetHelper::NEXT;
+ nOffset = 1;
+ }
+ else if (eCursorPosition == IResultSetHelper::FIRST ||
+ eCursorPosition == IResultSetHelper::NEXT ||
+ eCursorPosition == IResultSetHelper::ABSOLUTE1)
+ {
+ eCursorPosition = IResultSetHelper::NEXT;
+ nOffset = 1;
+ }
+ else if (eCursorPosition == IResultSetHelper::LAST ||
+ eCursorPosition == IResultSetHelper::PRIOR)
+ {
+ eCursorPosition = IResultSetHelper::PRIOR;
+ nOffset = 1;
+ }
+ else if (eCursorPosition == IResultSetHelper::RELATIVE1)
+ {
+ eCursorPosition = (nOffset >= 0) ? IResultSetHelper::NEXT : IResultSetHelper::PRIOR;
+ }
+ else
+ {
+ return false;
+ }
+ // Try again ...
+ goto again;
+ }
+ }
+
+ // Evaluate may only be set,
+ // if the Keyset will be constructed further
+ if ( ( m_aSQLIterator.getStatementType() == OSQLStatementType::Select )
+ && !isCount()
+ && bEvaluate
+ )
+ {
+ if (m_pSortIndex)
+ {
+ std::unique_ptr<OKeyValue> pKeyValue = GetOrderbyKeyValue( m_aSelectRow );
+ m_pSortIndex->AddKeyValue(std::move(pKeyValue));
+ }
+ else if (m_pFileSet.is())
+ {
+ sal_uInt32 nBookmarkValue = std::abs((*m_aEvaluateRow)[0]->getValue().getInt32());
+ m_pFileSet->push_back(nBookmarkValue);
+ }
+ }
+ else if (m_aSQLIterator.getStatementType() == OSQLStatementType::Update)
+ {
+ bool bOK = true;
+ if (bEvaluate)
+ {
+ // read the actual result-row
+ bOK = m_pTable->fetchRow(m_aEvaluateRow, *(m_pTable->getTableColumns()), true);
+ }
+
+ if (bOK)
+ {
+ // just give the values to be changed:
+ if(!m_pTable->UpdateRow(*m_aAssignValues,m_aEvaluateRow, m_xColsIdx))
+ return false;
+ }
+ }
+ else if (m_aSQLIterator.getStatementType() == OSQLStatementType::Delete)
+ {
+ bool bOK = true;
+ if (bEvaluate)
+ {
+ bOK = m_pTable->fetchRow(m_aEvaluateRow, *(m_pTable->getTableColumns()), true);
+ }
+ if (bOK)
+ {
+ if(!m_pTable->DeleteRow(*m_xColumns))
+ return false;
+ }
+ }
+ return true;
+}
+
+
+bool OResultSet::Move(IResultSetHelper::Movement eCursorPosition, sal_Int32 nOffset, bool bRetrieveData)
+{
+ sal_Int32 nTempPos = m_nRowPos;
+
+ if (m_aSQLIterator.getStatementType() == OSQLStatementType::Select &&
+ !isCount())
+ {
+ if (!m_pFileSet.is()) //no Index available
+ {
+ // Normal FETCH
+ ExecuteRow(eCursorPosition,nOffset,false,bRetrieveData);
+
+ // now set the bookmark for outside this is the logical pos and not the file pos
+ *(*m_aRow->begin()) = sal_Int32(m_nRowPos + 1);
+ }
+ else
+ {
+ switch(eCursorPosition)
+ {
+ case IResultSetHelper::NEXT:
+ ++m_nRowPos;
+ break;
+ case IResultSetHelper::PRIOR:
+ if (m_nRowPos >= 0)
+ --m_nRowPos;
+ break;
+ case IResultSetHelper::FIRST:
+ m_nRowPos = 0;
+ break;
+ case IResultSetHelper::LAST:
+ m_nRowPos = m_pFileSet->size() - 1;
+ break;
+ case IResultSetHelper::RELATIVE1:
+ m_nRowPos += nOffset;
+ break;
+ case IResultSetHelper::ABSOLUTE1:
+ case IResultSetHelper::BOOKMARK:
+ if ( m_nRowPos == (nOffset -1) )
+ return true;
+ m_nRowPos = nOffset -1;
+ break;
+ }
+
+ // OffRange?
+ // The FileCursor is outside of the valid range, if:
+ // a.) m_nRowPos < 1
+ // b.) a KeySet exists and m_nRowPos > m_pFileSet->size()
+ if (m_nRowPos < 0 || (m_pFileSet->isFrozen() && eCursorPosition != IResultSetHelper::BOOKMARK && o3tl::make_unsigned(m_nRowPos) >= m_pFileSet->size() )) // && m_pFileSet->IsFrozen()
+ {
+ goto Error;
+ }
+ else
+ {
+ if (m_nRowPos < static_cast<sal_Int32>(m_pFileSet->size()))
+ {
+ // Fetch via Index
+ bool bOK = ExecuteRow(IResultSetHelper::BOOKMARK,(*m_pFileSet)[m_nRowPos],false,bRetrieveData);
+ if (!bOK)
+ goto Error;
+
+ // now set the bookmark for outside
+ *(*m_aRow->begin()) = sal_Int32(m_nRowPos + 1);
+ if ( (bRetrieveData || m_pSQLAnalyzer->hasRestriction()) && m_pSQLAnalyzer->hasFunctions() )
+ {
+ m_pSQLAnalyzer->setSelectionEvaluationResult(m_aSelectRow,m_aColMapping);
+ }
+ }
+ else // Index must be further constructed
+ {
+ // set first on the last known row
+ if (m_pFileSet->empty())
+ {
+ m_pTable->seekRow(IResultSetHelper::ABSOLUTE1, 0, m_nFilePos);
+ }
+ else
+ {
+ m_aFileSetIter = m_pFileSet->end()-1;
+ m_pTable->seekRow(IResultSetHelper::BOOKMARK, *m_aFileSetIter, m_nFilePos);
+ }
+ bool bOK = true;
+ // Determine the number of further Fetches
+ while (bOK && m_nRowPos >= static_cast<sal_Int32>(m_pFileSet->size()))
+ {
+ bOK = ExecuteRow(IResultSetHelper::NEXT,1,true, false);//bRetrieveData);
+ }
+
+ if (bOK)
+ {
+ // read the results again
+ m_pTable->fetchRow(m_aRow, *(m_pTable->getTableColumns()), bRetrieveData);
+
+ // now set the bookmark for outside
+ *(*m_aRow->begin()) = sal_Int32(m_nRowPos + 1);
+
+ if ( (bRetrieveData || m_pSQLAnalyzer->hasRestriction()) && m_pSQLAnalyzer->hasFunctions() )
+ {
+ m_pSQLAnalyzer->setSelectionEvaluationResult(m_aSelectRow,m_aColMapping);
+ }
+ }
+ else if (!m_pFileSet->isFrozen()) // no valid record found
+ {
+ m_pFileSet->setFrozen();
+ goto Error;
+ }
+ }
+ }
+ }
+ }
+ else if (m_aSQLIterator.getStatementType() == OSQLStatementType::Select && isCount())
+ {
+ // Fetch the COUNT(*)
+ switch (eCursorPosition)
+ {
+ case IResultSetHelper::NEXT:
+ ++m_nRowPos;
+ break;
+ case IResultSetHelper::PRIOR:
+ --m_nRowPos;
+ break;
+ case IResultSetHelper::FIRST:
+ m_nRowPos = 0;
+ break;
+ case IResultSetHelper::LAST:
+ m_nRowPos = 0;
+ break;
+ case IResultSetHelper::RELATIVE1:
+ m_nRowPos += nOffset;
+ break;
+ case IResultSetHelper::ABSOLUTE1:
+ case IResultSetHelper::BOOKMARK:
+ m_nRowPos = nOffset - 1;
+ break;
+ }
+
+ if ( m_nRowPos < 0 )
+ goto Error;
+ else if (m_nRowPos == 0)
+ {
+ // put COUNT(*) in result-row
+ // (must be the first and only variable in the row)
+ if (m_aRow->size() >= 2)
+ {
+ *(*m_aRow)[1] = m_nRowCountResult;
+ *(*m_aRow)[0] = sal_Int32(1);
+ (*m_aRow)[1]->setBound(true);
+ (*m_aSelectRow)[1] = (*m_aRow)[1];
+ }
+ }
+ else
+ {
+ m_nRowPos = 1;
+ return false;
+ }
+ }
+ else
+ // Fetch only possible at SELECT!
+ return false;
+
+ return true;
+
+Error:
+ // is the Cursor positioned before the first row
+ // then the position will be maintained
+ if (nTempPos == -1)
+ m_nRowPos = nTempPos;
+ else
+ {
+ switch(eCursorPosition)
+ {
+ case IResultSetHelper::PRIOR:
+ case IResultSetHelper::FIRST:
+ m_nRowPos = -1;
+ break;
+ case IResultSetHelper::LAST:
+ case IResultSetHelper::NEXT:
+ case IResultSetHelper::ABSOLUTE1:
+ case IResultSetHelper::RELATIVE1:
+ if (nOffset > 0)
+ m_nRowPos = m_pFileSet.is() ? static_cast<sal_Int32>(m_pFileSet->size()) : -1;
+ else if (nOffset < 0)
+ m_nRowPos = -1;
+ break;
+ case IResultSetHelper::BOOKMARK:
+ m_nRowPos = nTempPos; // last Position
+ }
+ }
+ return false;
+}
+
+void OResultSet::sortRows()
+{
+ if (!m_pSQLAnalyzer->hasRestriction() && m_aOrderbyColumnNumber.size() == 1)
+ {
+ // is just one field given for sorting
+ // and this field is indexed, then the Index will be used
+ Reference<XIndexesSupplier> xIndexSup;
+ m_pTable->queryInterface(cppu::UnoType<XIndexesSupplier>::get()) >>= xIndexSup;
+
+ Reference<XIndexAccess> xIndexes;
+ if(xIndexSup.is())
+ {
+ xIndexes.set(xIndexSup->getIndexes(),UNO_QUERY);
+ Reference<XPropertySet> xColProp;
+ if(m_aOrderbyColumnNumber[0] < xIndexes->getCount())
+ {
+ xColProp.set(xIndexes->getByIndex(m_aOrderbyColumnNumber[0]),UNO_QUERY);
+ // iterate through the indexes to find the matching column
+ const sal_Int32 nCount = xIndexes->getCount();
+ for(sal_Int32 i=0; i < nCount;++i)
+ {
+ Reference<XColumnsSupplier> xIndex(xIndexes->getByIndex(i),UNO_QUERY);
+ Reference<XNameAccess> xIndexCols = xIndex->getColumns();
+ if(xIndexCols->hasByName(comphelper::getString(xColProp->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME)))))
+ {
+ m_pFileSet = new OKeySet();
+
+ if(fillIndexValues(xIndex))
+ return;
+ }
+ }
+ }
+ }
+ }
+
+ OSortIndex::TKeyTypeVector eKeyType(m_aOrderbyColumnNumber.size());
+ size_t i = 0;
+ for (auto const& elem : m_aOrderbyColumnNumber)
+ {
+ OSL_ENSURE(static_cast<sal_Int32>(m_aSelectRow->size()) > elem,"Invalid Index");
+ switch ((*(m_aSelectRow->begin()+elem))->getValue().getTypeKind())
+ {
+ case DataType::CHAR:
+ case DataType::VARCHAR:
+ case DataType::LONGVARCHAR:
+ eKeyType[i] = OKeyType::String;
+ break;
+
+ case DataType::OTHER:
+ case DataType::TINYINT:
+ case DataType::SMALLINT:
+ case DataType::INTEGER:
+ case DataType::DECIMAL:
+ case DataType::NUMERIC:
+ case DataType::REAL:
+ case DataType::DOUBLE:
+ case DataType::DATE:
+ case DataType::TIME:
+ case DataType::TIMESTAMP:
+ case DataType::BIT:
+ eKeyType[i] = OKeyType::Double;
+ break;
+
+ // Other types aren't implemented (so they are always FALSE)
+ default:
+ eKeyType[i] = OKeyType::NONE;
+ SAL_WARN( "connectivity.drivers","OFILECursor::Execute: Data type not implemented");
+ break;
+ }
+ (*m_aSelectRow)[elem]->setBound(true);
+ ++i;
+ }
+
+ m_pSortIndex.reset(new OSortIndex(std::move(eKeyType), std::vector(m_aOrderbyAscending)));
+
+ while ( ExecuteRow( IResultSetHelper::NEXT, 1, false ) )
+ {
+ (*m_aSelectRow)[0]->setValue( (*m_aRow)[0]->getValue() );
+ if ( m_pSQLAnalyzer->hasFunctions() )
+ m_pSQLAnalyzer->setSelectionEvaluationResult( m_aSelectRow, m_aColMapping );
+ const sal_Int32 nBookmark = (*m_aRow->begin())->getValue().getInt32();
+ ExecuteRow( IResultSetHelper::BOOKMARK, nBookmark, true, false );
+ }
+
+ // create sorted Keyset
+ m_pFileSet = nullptr;
+ m_pFileSet = m_pSortIndex->CreateKeySet();
+ m_pSortIndex.reset();
+ // now access to a sorted set is possible via Index
+}
+
+
+void OResultSet::OpenImpl()
+{
+ OSL_ENSURE(m_pSQLAnalyzer,"No analyzer set with setSqlAnalyzer!");
+ if(!m_pTable.is())
+ {
+ const OSQLTables& rTabs = m_aSQLIterator.getTables();
+ if (rTabs.empty() || !rTabs.begin()->second.is())
+ lcl_throwError(STR_QUERY_TOO_COMPLEX,*this);
+
+ if ( rTabs.size() > 1 || m_aSQLIterator.hasErrors() )
+ lcl_throwError(STR_QUERY_MORE_TABLES,*this);
+
+ OSQLTable xTable = rTabs.begin()->second;
+ m_xColumns = m_aSQLIterator.getSelectColumns();
+
+ m_xColNames = xTable->getColumns();
+ m_xColsIdx.set(m_xColNames,UNO_QUERY);
+ doTableSpecials(xTable);
+ Reference<XComponent> xComp(xTable,UNO_QUERY);
+ if(xComp.is())
+ xComp->addEventListener(this);
+ }
+
+ m_pTable->refreshHeader();
+
+ sal_Int32 nColumnCount = m_xColsIdx->getCount();
+
+ initializeRow(m_aRow,nColumnCount);
+ initializeRow(m_aEvaluateRow,nColumnCount);
+ initializeRow(m_aInsertRow,nColumnCount);
+
+
+ m_nResultSetConcurrency = (m_pTable->isReadOnly() || isCount()) ? ResultSetConcurrency::READ_ONLY : ResultSetConcurrency::UPDATABLE;
+
+ // create new Index:
+ m_pFileSet = nullptr;
+
+ // position at the beginning
+ m_nRowPos = -1;
+ m_nFilePos = 0;
+ m_nRowCountResult = -1;
+ m_pTable->seekRow(IResultSetHelper::ABSOLUTE1, 0, m_nFilePos);
+
+ m_nLastVisitedPos = m_pTable->getCurrentLastPos();
+
+ switch(m_aSQLIterator.getStatementType())
+ {
+ case OSQLStatementType::Select:
+ {
+ if(isCount())
+ {
+ if(m_xColumns->size() > 1)
+ lcl_throwError(STR_QUERY_COMPLEX_COUNT,*this);
+
+ m_nRowCountResult = 0;
+ // for now simply iterate over all rows and
+ // do all actions (or just count)
+ {
+ bool bOK = true;
+ while (bOK)
+ {
+ bOK = ExecuteRow(IResultSetHelper::NEXT);
+
+ if (bOK)
+ {
+ m_nRowCountResult++;
+ }
+ }
+
+ // save result of COUNT(*) in m_nRowCountResult.
+ // nRowCount (number of Rows in the result) = 1 for this request!
+ }
+ }
+ else
+ {
+ bool bDistinct = false;
+ assert(m_pParseTree != nullptr);
+ OSQLParseNode *pDistinct = m_pParseTree->getChild(1);
+
+ assert(m_aOrderbyColumnNumber.size() ==
+ m_aOrderbyAscending.size());
+ if (pDistinct && pDistinct->getTokenID() == SQL_TOKEN_DISTINCT )
+ {
+ // To eliminate duplicates we need to sort on all columns.
+ // This is not a problem because the SQL spec says that the
+ // order of columns that are not specified in ORDER BY
+ // clause is undefined, so it doesn't hurt to sort on
+ // these; pad the vectors to include them.
+ for (size_t i = 1; // 0: bookmark (see setBoundedColumns)
+ i < m_aColMapping.size(); ++i)
+ {
+ if (std::find(m_aOrderbyColumnNumber.begin(),
+ m_aOrderbyColumnNumber.end(),
+ sal::static_int_cast<sal_Int32>(i))
+ == m_aOrderbyColumnNumber.end())
+ {
+ m_aOrderbyColumnNumber.push_back(i);
+ // ASC or DESC doesn't matter
+ m_aOrderbyAscending.push_back(TAscendingOrder::ASC);
+ }
+ }
+ bDistinct = true;
+ }
+
+ if (IsSorted())
+ sortRows();
+
+ if (!m_pFileSet.is())
+ {
+ m_pFileSet = new OKeySet();
+
+ if (!m_pSQLAnalyzer->hasRestriction())
+ // now the Keyset can be filled!
+ // But be careful: It is assumed, that the FilePositions will be stored as sequence 1..n
+ {
+ if ( m_nLastVisitedPos > 0)
+ m_pFileSet->reserve( m_nLastVisitedPos );
+ for (sal_Int32 i = 0; i < m_nLastVisitedPos; i++)
+ m_pFileSet->push_back(i + 1);
+ }
+ }
+ OSL_ENSURE(m_pFileSet.is(),"No KeySet existing! :-(");
+
+ if(bDistinct && m_pFileSet.is())
+ {
+ OValueRow aSearchRow = new OValueVector(m_aRow->size());
+ OValueRefVector::iterator aRowIter = m_aRow->begin();
+ OValueVector::iterator aSearchIter = aSearchRow->begin();
+ for ( ++aRowIter,++aSearchIter; // the first column is the bookmark column
+ aRowIter != m_aRow->end();
+ ++aRowIter,++aSearchIter)
+ aSearchIter->setBound((*aRowIter)->isBound());
+
+ size_t nMaxRow = m_pFileSet->size();
+
+ if (nMaxRow)
+ {
+ #if OSL_DEBUG_LEVEL > 1
+ sal_Int32 nFound=0;
+ #endif
+ sal_Int32 nPos;
+ sal_Int32 nKey;
+
+ for( size_t j = nMaxRow-1; j > 0; --j)
+ {
+ nPos = (*m_pFileSet)[j];
+ ExecuteRow(IResultSetHelper::BOOKMARK,nPos,false);
+ m_pSQLAnalyzer->setSelectionEvaluationResult(m_aSelectRow,m_aColMapping);
+ { // cop*y row values
+ OValueRefVector::iterator copyFrom = m_aSelectRow->begin();
+ OValueVector::iterator copyTo = aSearchRow->begin();
+ for ( ++copyFrom,++copyTo; // the first column is the bookmark column
+ copyFrom != m_aSelectRow->end();
+ ++copyFrom,++copyTo)
+ *copyTo = *(*copyFrom);
+ }
+
+ // compare with next row
+ nKey = (*m_pFileSet)[j-1];
+ ExecuteRow(IResultSetHelper::BOOKMARK,nKey,false);
+ m_pSQLAnalyzer->setSelectionEvaluationResult(m_aSelectRow,m_aColMapping);
+ auto rowsMismatchIters = std::mismatch(std::next(m_aSelectRow->begin()), m_aSelectRow->end(),
+ std::next(aSearchRow->begin()), // the first column is the bookmark column
+ [](const OValueRefVector::value_type& a, const OValueVector::value_type& b) {
+ return !a->isBound() || (*a == b); });
+
+ if(rowsMismatchIters.first == m_aSelectRow->end())
+ (*m_pFileSet)[j] = 0; // Rows match -- Mark for deletion by setting key to 0
+ #if OSL_DEBUG_LEVEL > 1
+ else
+ nFound++;
+ #endif
+ }
+
+ m_pFileSet->erase(std::remove(m_pFileSet->begin(),m_pFileSet->end(),0)
+ ,m_pFileSet->end());
+ }
+ }
+ }
+ } break;
+
+ case OSQLStatementType::Update:
+ case OSQLStatementType::Delete:
+ // during processing count the number of processed Rows
+ m_nRowCountResult = 0;
+ // for now simply iterate over all rows and
+ // run the actions (or simply count):
+ {
+
+ bool bOK = true;
+ while (bOK)
+ {
+ bOK = ExecuteRow(IResultSetHelper::NEXT);
+
+ if (bOK)
+ {
+ m_nRowCountResult++;
+ }
+ }
+
+ // save result of COUNT(*) in nRowCountResult.
+ // nRowCount (number of rows in the result-set) = 1 for this request!
+ }
+ break;
+ case OSQLStatementType::Insert:
+ m_nRowCountResult = 0;
+
+ OSL_ENSURE(m_aAssignValues.is(),"No assign values set!");
+ if(!m_pTable->InsertRow(*m_aAssignValues, m_xColsIdx))
+ {
+ m_nFilePos = 0;
+ return;
+ }
+
+ m_nRowCountResult = 1;
+ break;
+ default:
+ SAL_WARN( "connectivity.drivers", "OResultSet::OpenImpl: unsupported statement type!" );
+ break;
+ }
+
+ // reset FilePos
+ m_nFilePos = 0;
+}
+
+void OResultSet::setBoundedColumns(const OValueRefRow& _rRow,
+ const OValueRefRow& _rSelectRow,
+ const ::rtl::Reference<connectivity::OSQLColumns>& _rxColumns,
+ const Reference<XIndexAccess>& _xNames,
+ bool _bSetColumnMapping,
+ const Reference<XDatabaseMetaData>& _xMetaData,
+ std::vector<sal_Int32>& _rColMapping)
+{
+ ::comphelper::UStringMixEqual aCase(_xMetaData->supportsMixedCaseQuotedIdentifiers());
+
+ Reference<XPropertySet> xTableColumn;
+ OUString sTableColumnName, sSelectColumnRealName;
+
+ const OUString sName = OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME);
+ const OUString sRealName = OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_REALNAME);
+ const OUString sType = OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE);
+
+ std::map<OSQLColumns::iterator,bool> aSelectIters;
+ OValueRefVector::const_iterator aRowIter = _rRow->begin()+1;
+ for (sal_Int32 i=0; // the first column is the bookmark column
+ aRowIter != _rRow->end();
+ ++i, ++aRowIter
+ )
+ {
+ (*aRowIter)->setBound(false);
+ try
+ {
+ // get the table column and its name
+ _xNames->getByIndex(i) >>= xTableColumn;
+ OSL_ENSURE(xTableColumn.is(), "OResultSet::setBoundedColumns: invalid table column!");
+ if (xTableColumn.is())
+ xTableColumn->getPropertyValue(sName) >>= sTableColumnName;
+ else
+ sTableColumnName.clear();
+
+ // look if we have such a select column
+ // TODO: would like to have a O(log n) search here ...
+ for ( OSQLColumns::iterator aIter = _rxColumns->begin();
+ aIter != _rxColumns->end();
+ ++aIter
+ )
+ {
+ if((*aIter)->getPropertySetInfo()->hasPropertyByName(sRealName))
+ (*aIter)->getPropertyValue(sRealName) >>= sSelectColumnRealName;
+ else
+ (*aIter)->getPropertyValue(sName) >>= sSelectColumnRealName;
+
+ if ( aCase(sTableColumnName, sSelectColumnRealName) && !(*aRowIter)->isBound() && aSelectIters.end() == aSelectIters.find(aIter) )
+ {
+ aSelectIters.emplace(aIter,true);
+ if(_bSetColumnMapping)
+ {
+ sal_Int32 nSelectColumnPos = aIter - _rxColumns->begin() + 1;
+ // the getXXX methods are 1-based ...
+ sal_Int32 nTableColumnPos = i + 1;
+ // get first table column is the bookmark column ...
+ _rColMapping[nSelectColumnPos] = nTableColumnPos;
+ (*_rSelectRow)[nSelectColumnPos] = *aRowIter;
+ }
+
+ (*aRowIter)->setBound(true);
+ sal_Int32 nType = DataType::OTHER;
+ if (xTableColumn.is())
+ xTableColumn->getPropertyValue(sType) >>= nType;
+ (*aRowIter)->setTypeKind(nType);
+
+ break;
+ }
+ }
+ }
+ catch (Exception&)
+ {
+ TOOLS_WARN_EXCEPTION( "connectivity.drivers","");
+ }
+ }
+ // in this case we got more select columns as columns exist in the table
+ if ( !(_bSetColumnMapping && aSelectIters.size() != _rColMapping.size()) )
+ return;
+
+ Reference<XNameAccess> xNameAccess(_xNames,UNO_QUERY);
+ Sequence< OUString > aSelectColumns = xNameAccess->getElementNames();
+
+ for ( OSQLColumns::iterator aIter = _rxColumns->begin();
+ aIter != _rxColumns->end();
+ ++aIter
+ )
+ {
+ if ( aSelectIters.end() == aSelectIters.find(aIter) )
+ {
+ if ( (*aIter)->getPropertySetInfo()->hasPropertyByName(sRealName) )
+ (*aIter)->getPropertyValue(sRealName) >>= sSelectColumnRealName;
+ else
+ (*aIter)->getPropertyValue(sName) >>= sSelectColumnRealName;
+
+ if ( xNameAccess->hasByName( sSelectColumnRealName ) )
+ {
+ aSelectIters.emplace(aIter,true);
+ sal_Int32 nSelectColumnPos = aIter - _rxColumns->begin() + 1;
+ const OUString* pBegin = aSelectColumns.getConstArray();
+ const OUString* pEnd = pBegin + aSelectColumns.getLength();
+ for(sal_Int32 i=0;pBegin != pEnd;++pBegin,++i)
+ {
+ if ( aCase(*pBegin, sSelectColumnRealName) )
+ {
+ // the getXXX methods are 1-based ...
+ sal_Int32 nTableColumnPos = i + 1;
+ // get first table column is the bookmark column ...
+ _rColMapping[nSelectColumnPos] = nTableColumnPos;
+ (*_rSelectRow)[nSelectColumnPos] = (*_rRow)[nTableColumnPos];
+ break;
+ }
+ }
+ }
+ }
+ }
+}
+
+void SAL_CALL OResultSet::acquire() noexcept
+{
+ OResultSet_BASE::acquire();
+}
+
+void SAL_CALL OResultSet::release() noexcept
+{
+ OResultSet_BASE::release();
+}
+
+Reference< css::beans::XPropertySetInfo > SAL_CALL OResultSet::getPropertySetInfo( )
+{
+ return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper());
+}
+
+void OResultSet::doTableSpecials(const OSQLTable& _xTable)
+{
+ m_pTable = dynamic_cast<OFileTable*>(_xTable.get());
+ assert(m_pTable.is());
+}
+
+void OResultSet::clearInsertRow()
+{
+ m_aRow->setDeleted(false); // set to false here because this is the new row
+ sal_Int32 nPos = 0;
+ for(ORowSetValueDecoratorRef& rValue : *m_aInsertRow)
+ {
+ if ( rValue->isBound() )
+ {
+ (*m_aRow)[nPos]->setValue( rValue->getValue() );
+ }
+ rValue->setBound(nPos == 0);
+ rValue->setModified(false);
+ rValue->setNull();
+ ++nPos;
+ }
+}
+
+void OResultSet::initializeRow(OValueRefRow& _rRow,sal_Int32 _nColumnCount)
+{
+ if(!_rRow.is())
+ {
+ _rRow = new OValueRefVector(_nColumnCount);
+ (*_rRow)[0]->setBound(true);
+ std::for_each(_rRow->begin()+1,_rRow->end(),TSetRefBound(false));
+ }
+}
+
+bool OResultSet::fillIndexValues(const Reference< XColumnsSupplier> &/*_xIndex*/)
+{
+ return false;
+}
+
+bool OResultSet::move(IResultSetHelper::Movement _eCursorPosition, sal_Int32 _nOffset, bool _bRetrieveData)
+{
+ return Move(_eCursorPosition,_nOffset,_bRetrieveData);
+}
+
+sal_Int32 OResultSet::getDriverPos() const
+{
+ return (*m_aRow)[0]->getValue().getInt32();
+}
+
+bool OResultSet::isRowDeleted() const
+{
+ return m_aRow->isDeleted();
+}
+
+void SAL_CALL OResultSet::disposing( const EventObject& Source )
+{
+ Reference<XPropertySet> xProp = m_pTable;
+ if(m_pTable.is() && Source.Source == xProp)
+ {
+ m_pTable.clear();
+ }
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/file/FResultSetMetaData.cxx b/connectivity/source/drivers/file/FResultSetMetaData.cxx
new file mode 100644
index 0000000000..b9fdcc4c4c
--- /dev/null
+++ b/connectivity/source/drivers/file/FResultSetMetaData.cxx
@@ -0,0 +1,189 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <file/FResultSetMetaData.hxx>
+#include <file/FTable.hxx>
+#include <comphelper/extract.hxx>
+#include <connectivity/dbexception.hxx>
+#include <comphelper/types.hxx>
+#include <o3tl/safeint.hxx>
+#include <utility>
+
+
+using namespace ::comphelper;
+using namespace connectivity;
+using namespace dbtools;
+using namespace connectivity::file;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+
+
+OResultSetMetaData::OResultSetMetaData(::rtl::Reference<connectivity::OSQLColumns> _xColumns, OUString _aTableName, OFileTable* _pTable)
+ :m_aTableName(std::move(_aTableName))
+ ,m_xColumns(std::move(_xColumns))
+ ,m_pTable(_pTable)
+{
+}
+
+
+OResultSetMetaData::~OResultSetMetaData()
+{
+ m_xColumns = nullptr;
+}
+
+void OResultSetMetaData::checkColumnIndex(sal_Int32 column)
+{
+ if(column <= 0 || o3tl::make_unsigned(column) > m_xColumns->size())
+ throwInvalidIndexException(*this);
+}
+
+sal_Int32 SAL_CALL OResultSetMetaData::getColumnDisplaySize( sal_Int32 column )
+{
+ return getPrecision(column);
+}
+
+
+sal_Int32 SAL_CALL OResultSetMetaData::getColumnType( sal_Int32 column )
+{
+ checkColumnIndex(column);
+ return getINT32((*m_xColumns)[column-1]->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE)));
+}
+
+
+sal_Int32 SAL_CALL OResultSetMetaData::getColumnCount( )
+{
+ return m_xColumns->size();
+}
+
+
+sal_Bool SAL_CALL OResultSetMetaData::isCaseSensitive( sal_Int32 /*column*/ )
+{
+ return false;
+}
+
+
+OUString SAL_CALL OResultSetMetaData::getSchemaName( sal_Int32 /*column*/ )
+{
+ return OUString();
+}
+
+
+OUString SAL_CALL OResultSetMetaData::getColumnName( sal_Int32 column )
+{
+ checkColumnIndex(column);
+
+ Any aName((*m_xColumns)[column-1]->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME)));
+ return aName.hasValue() ? getString(aName) : getString((*m_xColumns)[column-1]->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME)));
+}
+
+OUString SAL_CALL OResultSetMetaData::getTableName( sal_Int32 /*column*/ )
+{
+ return m_aTableName;
+}
+
+OUString SAL_CALL OResultSetMetaData::getCatalogName( sal_Int32 /*column*/ )
+{
+ return OUString();
+}
+
+OUString SAL_CALL OResultSetMetaData::getColumnTypeName( sal_Int32 column )
+{
+ checkColumnIndex(column);
+ return getString((*m_xColumns)[column-1]->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPENAME)));
+}
+
+OUString SAL_CALL OResultSetMetaData::getColumnLabel( sal_Int32 column )
+{
+ return getColumnName(column);
+}
+
+OUString SAL_CALL OResultSetMetaData::getColumnServiceName( sal_Int32 /*column*/ )
+{
+ return OUString();
+}
+
+
+sal_Bool SAL_CALL OResultSetMetaData::isCurrency( sal_Int32 column )
+{
+ checkColumnIndex(column);
+ return getBOOL((*m_xColumns)[column-1]->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISCURRENCY)));
+}
+
+
+sal_Bool SAL_CALL OResultSetMetaData::isAutoIncrement( sal_Int32 /*setCatalogcolumn*/ )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL OResultSetMetaData::isSigned( sal_Int32 /*column*/ )
+{
+ return true;
+}
+
+sal_Int32 SAL_CALL OResultSetMetaData::getPrecision( sal_Int32 column )
+{
+ checkColumnIndex(column);
+ return getINT32((*m_xColumns)[column-1]->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PRECISION)));
+}
+
+sal_Int32 SAL_CALL OResultSetMetaData::getScale( sal_Int32 column )
+{
+ checkColumnIndex(column);
+ return getINT32((*m_xColumns)[column-1]->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCALE)));
+}
+
+
+sal_Int32 SAL_CALL OResultSetMetaData::isNullable( sal_Int32 column )
+{
+ checkColumnIndex(column);
+ return getINT32((*m_xColumns)[column-1]->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISNULLABLE)));
+}
+
+
+sal_Bool SAL_CALL OResultSetMetaData::isSearchable( sal_Int32 /*column*/ )
+{
+ return true;
+}
+
+
+sal_Bool SAL_CALL OResultSetMetaData::isReadOnly( sal_Int32 column )
+{
+ checkColumnIndex(column);
+ return m_pTable->isReadOnly() || (
+ (*m_xColumns)[column-1]->getPropertySetInfo()->hasPropertyByName(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FUNCTION)) &&
+ ::cppu::any2bool((*m_xColumns)[column-1]->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FUNCTION))));
+}
+
+
+sal_Bool SAL_CALL OResultSetMetaData::isDefinitelyWritable( sal_Int32 column )
+{
+ return !isReadOnly(column);
+}
+
+sal_Bool SAL_CALL OResultSetMetaData::isWritable( sal_Int32 column )
+{
+ return !isReadOnly(column);
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/file/FStatement.cxx b/connectivity/source/drivers/file/FStatement.cxx
new file mode 100644
index 0000000000..4520abfeff
--- /dev/null
+++ b/connectivity/source/drivers/file/FStatement.cxx
@@ -0,0 +1,712 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <o3tl/safeint.hxx>
+#include <osl/diagnose.h>
+#include <file/FStatement.hxx>
+#include <file/FConnection.hxx>
+#include <sqlbison.hxx>
+#include <file/FDriver.hxx>
+#include <file/FResultSet.hxx>
+#include <sal/log.hxx>
+#include <com/sun/star/sdbc/ResultSetConcurrency.hpp>
+#include <com/sun/star/sdbc/ResultSetType.hpp>
+#include <com/sun/star/sdbc/FetchDirection.hpp>
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <comphelper/sequence.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <cppuhelper/typeprovider.hxx>
+#include <comphelper/types.hxx>
+#include <connectivity/dbexception.hxx>
+#include <strings.hrc>
+#include <algorithm>
+#include <cstddef>
+
+namespace connectivity::file
+{
+
+
+using namespace dbtools;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::sdbc;
+using namespace com::sun::star::sdbcx;
+using namespace com::sun::star::container;
+
+OStatement_Base::OStatement_Base(OConnection* _pConnection )
+ :OStatement_BASE(m_aMutex)
+ ,::comphelper::OPropertyContainer(OStatement_BASE::rBHelper)
+ ,m_xDBMetaData(_pConnection->getMetaData())
+ ,m_aParser( _pConnection->getDriver()->getComponentContext() )
+ ,m_aSQLIterator( _pConnection, _pConnection->createCatalog()->getTables(), m_aParser )
+ ,m_pConnection(_pConnection)
+ ,m_pParseTree(nullptr)
+ ,m_nMaxFieldSize(0)
+ ,m_nMaxRows(0)
+ ,m_nQueryTimeOut(0)
+ ,m_nFetchSize(0)
+ ,m_nResultSetType(ResultSetType::FORWARD_ONLY)
+ ,m_nFetchDirection(FetchDirection::FORWARD)
+ ,m_nResultSetConcurrency(ResultSetConcurrency::UPDATABLE)
+ ,m_bEscapeProcessing(true)
+{
+ sal_Int32 nAttrib = 0;
+
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_CURSORNAME), PROPERTY_ID_CURSORNAME, nAttrib,&m_aCursorName, ::cppu::UnoType<OUString>::get());
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_MAXFIELDSIZE), PROPERTY_ID_MAXFIELDSIZE, nAttrib,&m_nMaxFieldSize, ::cppu::UnoType<sal_Int32>::get());
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_MAXROWS), PROPERTY_ID_MAXROWS, nAttrib,&m_nMaxRows, ::cppu::UnoType<sal_Int32>::get());
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_QUERYTIMEOUT), PROPERTY_ID_QUERYTIMEOUT, nAttrib,&m_nQueryTimeOut, ::cppu::UnoType<sal_Int32>::get());
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHSIZE), PROPERTY_ID_FETCHSIZE, nAttrib,&m_nFetchSize, ::cppu::UnoType<sal_Int32>::get());
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETTYPE), PROPERTY_ID_RESULTSETTYPE, nAttrib,&m_nResultSetType, ::cppu::UnoType<sal_Int32>::get());
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHDIRECTION), PROPERTY_ID_FETCHDIRECTION, nAttrib,&m_nFetchDirection, ::cppu::UnoType<sal_Int32>::get());
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ESCAPEPROCESSING),PROPERTY_ID_ESCAPEPROCESSING, nAttrib,&m_bEscapeProcessing,cppu::UnoType<bool>::get());
+
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETCONCURRENCY), PROPERTY_ID_RESULTSETCONCURRENCY, nAttrib,&m_nResultSetConcurrency, ::cppu::UnoType<sal_Int32>::get());
+}
+
+OStatement_Base::~OStatement_Base()
+{
+ osl_atomic_increment( &m_refCount );
+ disposing();
+}
+
+void OStatement_Base::disposeResultSet()
+{
+ SAL_INFO( "connectivity.drivers", "file Ocke.Janssen@sun.com OStatement_Base::disposeResultSet" );
+ // free the cursor if alive
+ Reference< XComponent > xComp(m_xResultSet.get(), UNO_QUERY);
+ assert(xComp.is() || !m_xResultSet.get().is());
+ if (xComp.is())
+ xComp->dispose();
+ m_xResultSet.clear();
+}
+
+void OStatement_BASE2::disposing()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+
+ disposeResultSet();
+
+ if(m_pSQLAnalyzer)
+ m_pSQLAnalyzer->dispose();
+
+ if(m_aRow.is())
+ {
+ m_aRow->clear();
+ m_aRow = nullptr;
+ }
+
+ m_aSQLIterator.dispose();
+
+ m_pTable.clear();
+
+ m_pConnection.clear();
+
+ if ( m_pParseTree )
+ {
+ delete m_pParseTree;
+ m_pParseTree = nullptr;
+ }
+
+ OStatement_Base::disposing();
+}
+
+void SAL_CALL OStatement_Base::acquire() noexcept
+{
+ OStatement_BASE::acquire();
+}
+
+void SAL_CALL OStatement_BASE2::release() noexcept
+{
+ OStatement_BASE::release();
+}
+
+Any SAL_CALL OStatement_Base::queryInterface( const Type & rType )
+{
+ const Any aRet = OStatement_BASE::queryInterface(rType);
+ return aRet.hasValue() ? aRet : OPropertySetHelper::queryInterface(rType);
+}
+
+Sequence< Type > SAL_CALL OStatement_Base::getTypes( )
+{
+ ::cppu::OTypeCollection aTypes( cppu::UnoType<css::beans::XMultiPropertySet>::get(),
+ cppu::UnoType<css::beans::XFastPropertySet>::get(),
+ cppu::UnoType<css::beans::XPropertySet>::get());
+
+ return ::comphelper::concatSequences(aTypes.getTypes(),OStatement_BASE::getTypes());
+}
+
+
+void SAL_CALL OStatement_Base::cancel( )
+{
+}
+
+void SAL_CALL OStatement_Base::close()
+{
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OStatement_BASE::rBHelper.bDisposed);
+ }
+ dispose();
+}
+
+void OStatement_Base::closeResultSet()
+{
+ SAL_INFO( "connectivity.drivers", "file Ocke.Janssen@sun.com OStatement_Base::clearMyResultSet " );
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OStatement_BASE::rBHelper.bDisposed);
+
+ Reference< XCloseable > xCloseable(m_xResultSet.get(), UNO_QUERY);
+ assert(xCloseable.is() || !m_xResultSet.get().is());
+ if (xCloseable.is())
+ {
+ try
+ {
+ xCloseable->close();
+ }
+ catch( const DisposedException& ) { }
+ }
+
+ m_xResultSet.clear();
+}
+
+Any SAL_CALL OStatement_Base::getWarnings( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OStatement_BASE::rBHelper.bDisposed);
+
+ return Any(m_aLastWarning);
+}
+
+void SAL_CALL OStatement_Base::clearWarnings( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OStatement_BASE::rBHelper.bDisposed);
+
+ m_aLastWarning = SQLWarning();
+}
+
+::cppu::IPropertyArrayHelper* OStatement_Base::createArrayHelper( ) const
+{
+ Sequence< Property > aProps;
+ describeProperties(aProps);
+ return new ::cppu::OPropertyArrayHelper(aProps);
+}
+
+
+::cppu::IPropertyArrayHelper & OStatement_Base::getInfoHelper()
+{
+ return *getArrayHelper();
+}
+
+rtl::Reference<OResultSet> OStatement::createResultSet()
+{
+ return new OResultSet(this,m_aSQLIterator);
+}
+
+IMPLEMENT_SERVICE_INFO(OStatement,"com.sun.star.sdbc.driver.file.Statement","com.sun.star.sdbc.Statement");
+
+void SAL_CALL OStatement::acquire() noexcept
+{
+ OStatement_BASE2::acquire();
+}
+
+void SAL_CALL OStatement::release() noexcept
+{
+ OStatement_BASE2::release();
+}
+
+
+sal_Bool SAL_CALL OStatement::execute( const OUString& sql )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ executeQuery(sql);
+
+ return m_aSQLIterator.getStatementType() == OSQLStatementType::Select;
+}
+
+
+Reference< XResultSet > SAL_CALL OStatement::executeQuery( const OUString& sql )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OStatement_BASE::rBHelper.bDisposed);
+
+ construct(sql);
+ Reference< XResultSet > xRS;
+ rtl::Reference<OResultSet> pResult = createResultSet();
+ xRS = pResult;
+ initializeResultSet(pResult.get());
+ m_xResultSet = xRS;
+
+ pResult->OpenImpl();
+
+ return xRS;
+}
+
+Reference< XConnection > SAL_CALL OStatement::getConnection( )
+{
+ return m_pConnection;
+}
+
+sal_Int32 SAL_CALL OStatement::executeUpdate( const OUString& sql )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OStatement_BASE::rBHelper.bDisposed);
+
+
+ construct(sql);
+ rtl::Reference<OResultSet> pResult = createResultSet();
+ initializeResultSet(pResult.get());
+ pResult->OpenImpl();
+
+ return pResult->getRowCountResult();
+}
+
+
+void SAL_CALL OStatement_Base::disposing()
+{
+ if(m_aEvaluateRow.is())
+ {
+ m_aEvaluateRow->clear();
+ m_aEvaluateRow = nullptr;
+ }
+ OStatement_BASE::disposing();
+}
+
+Reference< css::beans::XPropertySetInfo > SAL_CALL OStatement_Base::getPropertySetInfo( )
+{
+ return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper());
+}
+
+Any SAL_CALL OStatement::queryInterface( const Type & rType )
+{
+ Any aRet = OStatement_XStatement::queryInterface( rType);
+ return aRet.hasValue() ? aRet : OStatement_BASE2::queryInterface( rType);
+}
+
+void OStatement_Base::analyzeSQL()
+{
+ OSL_ENSURE(m_pSQLAnalyzer,"OResultSet::analyzeSQL: Analyzer isn't set!");
+ // start analysing the statement
+ m_pSQLAnalyzer->setOrigColumns(m_xColNames);
+ m_pSQLAnalyzer->start(m_pParseTree);
+
+ const OSQLParseNode* pOrderbyClause = m_aSQLIterator.getOrderTree();
+ if(!pOrderbyClause)
+ return;
+
+ OSQLParseNode * pOrderingSpecCommalist = pOrderbyClause->getChild(2);
+ OSL_ENSURE(SQL_ISRULE(pOrderingSpecCommalist,ordering_spec_commalist),"OResultSet: Error in Parse Tree");
+
+ for (size_t m = 0; m < pOrderingSpecCommalist->count(); m++)
+ {
+ OSQLParseNode * pOrderingSpec = pOrderingSpecCommalist->getChild(m);
+ OSL_ENSURE(SQL_ISRULE(pOrderingSpec,ordering_spec),"OResultSet: Error in Parse Tree");
+ OSL_ENSURE(pOrderingSpec->count() == 2,"OResultSet: Error in Parse Tree");
+
+ OSQLParseNode * pColumnRef = pOrderingSpec->getChild(0);
+ if(!SQL_ISRULE(pColumnRef,column_ref))
+ {
+ throw SQLException();
+ }
+ OSQLParseNode * pAscendingDescending = pOrderingSpec->getChild(1);
+ setOrderbyColumn(pColumnRef,pAscendingDescending);
+ }
+}
+
+void OStatement_Base::setOrderbyColumn( OSQLParseNode const * pColumnRef,
+ OSQLParseNode const * pAscendingDescending)
+{
+ OUString aColumnName;
+ if (pColumnRef->count() == 1)
+ aColumnName = pColumnRef->getChild(0)->getTokenValue();
+ else if (pColumnRef->count() == 3)
+ {
+ pColumnRef->getChild(2)->parseNodeToStr( aColumnName, getOwnConnection(), nullptr, false, false );
+ }
+ else
+ {
+ throw SQLException();
+ }
+
+ Reference<XColumnLocate> xColLocate(m_xColNames,UNO_QUERY);
+ if(!xColLocate.is())
+ return;
+ // Everything tested and we have the name of the Column.
+ // What number is the Column?
+ ::rtl::Reference<OSQLColumns> aSelectColumns = m_aSQLIterator.getSelectColumns();
+ ::comphelper::UStringMixEqual aCase;
+ OSQLColumns::const_iterator aFind = ::connectivity::find(aSelectColumns->begin(),aSelectColumns->end(),aColumnName,aCase);
+ if ( aFind == aSelectColumns->end() )
+ throw SQLException();
+ m_aOrderbyColumnNumber.push_back((aFind - aSelectColumns->begin()) + 1);
+
+ // Ascending or Descending?
+ m_aOrderbyAscending.push_back(SQL_ISTOKEN(pAscendingDescending,DESC) ? TAscendingOrder::DESC : TAscendingOrder::ASC);
+}
+
+void OStatement_Base::construct(const OUString& sql)
+{
+ OUString aErr;
+ m_pParseTree = m_aParser.parseTree(aErr,sql).release();
+ if(!m_pParseTree)
+ throw SQLException(aErr,*this,OUString(),0,Any());
+
+ m_aSQLIterator.setParseTree(m_pParseTree);
+ m_aSQLIterator.traverseAll();
+ const OSQLTables& rTabs = m_aSQLIterator.getTables();
+
+ // sanity checks
+ if ( rTabs.empty() )
+ // no tables -> nothing to operate on -> error
+ m_pConnection->throwGenericSQLException(STR_QUERY_NO_TABLE,*this);
+
+ if ( rTabs.size() > 1 || m_aSQLIterator.hasErrors() )
+ // more than one table -> can't operate on them -> error
+ m_pConnection->throwGenericSQLException(STR_QUERY_MORE_TABLES,*this);
+
+ if ( (m_aSQLIterator.getStatementType() == OSQLStatementType::Select) && m_aSQLIterator.getSelectColumns()->empty() )
+ // SELECT statement without columns -> error
+ m_pConnection->throwGenericSQLException(STR_QUERY_NO_COLUMN,*this);
+
+ switch(m_aSQLIterator.getStatementType())
+ {
+ case OSQLStatementType::CreateTable:
+ case OSQLStatementType::OdbcCall:
+ case OSQLStatementType::Unknown:
+ m_pConnection->throwGenericSQLException(STR_QUERY_TOO_COMPLEX,*this);
+ break;
+ case OSQLStatementType::Select:
+ if(SQL_ISRULE(m_aSQLIterator.getParseTree(), union_statement))
+ {
+ m_pConnection->throwGenericSQLException(STR_QUERY_TOO_COMPLEX, *this);
+ }
+ assert(SQL_ISRULE(m_aSQLIterator.getParseTree(), select_statement));
+ break;
+ default:
+ break;
+ }
+
+ // at this moment we support only one table per select statement
+ m_pTable = dynamic_cast<OFileTable*>(rTabs.begin()->second.get());
+ OSL_ENSURE(m_pTable.is(),"No table!");
+ if ( m_pTable.is() )
+ m_xColNames = m_pTable->getColumns();
+ Reference<XIndexAccess> xNames(m_xColNames,UNO_QUERY);
+ // set the binding of the resultrow
+ m_aRow = new OValueRefVector(xNames->getCount());
+ (*m_aRow)[0]->setBound(true);
+ std::for_each(m_aRow->begin()+1,m_aRow->end(),TSetRefBound(false));
+
+ // set the binding of the resultrow
+ m_aEvaluateRow = new OValueRefVector(xNames->getCount());
+
+ (*m_aEvaluateRow)[0]->setBound(true);
+ std::for_each(m_aEvaluateRow->begin()+1,m_aEvaluateRow->end(),TSetRefBound(false));
+
+ // set the select row
+ m_aSelectRow = new OValueRefVector(m_aSQLIterator.getSelectColumns()->size());
+ std::for_each(m_aSelectRow->begin(),m_aSelectRow->end(),TSetRefBound(true));
+
+ // create the column mapping
+ createColumnMapping();
+
+ m_pSQLAnalyzer.reset( new OSQLAnalyzer(m_pConnection.get()) );
+
+ analyzeSQL();
+}
+
+void OStatement_Base::createColumnMapping()
+{
+ // initialize the column index map (mapping select columns to table columns)
+ ::rtl::Reference<connectivity::OSQLColumns> xColumns = m_aSQLIterator.getSelectColumns();
+ m_aColMapping.resize(xColumns->size() + 1);
+ for (std::size_t i=0; i<m_aColMapping.size(); ++i)
+ m_aColMapping[i] = i;
+
+ Reference<XIndexAccess> xNames(m_xColNames,UNO_QUERY);
+ // now check which columns are bound
+ OResultSet::setBoundedColumns(m_aRow,m_aSelectRow,xColumns,xNames,true,m_xDBMetaData,m_aColMapping);
+}
+
+void OStatement_Base::initializeResultSet(OResultSet* _pResult)
+{
+ GetAssignValues();
+
+ _pResult->setSqlAnalyzer(m_pSQLAnalyzer.get());
+ _pResult->setOrderByColumns(std::vector(m_aOrderbyColumnNumber));
+ _pResult->setOrderByAscending(std::vector(m_aOrderbyAscending));
+ _pResult->setBindingRow(m_aRow);
+ _pResult->setColumnMapping(std::vector(m_aColMapping));
+ _pResult->setEvaluationRow(m_aEvaluateRow);
+ _pResult->setAssignValues(m_aAssignValues);
+ _pResult->setSelectRow(m_aSelectRow);
+
+ m_pSQLAnalyzer->bindSelectRow(m_aRow);
+ m_pSQLAnalyzer->bindEvaluationRow(m_aEvaluateRow); // Set values in the code of the Compiler
+}
+
+void OStatement_Base::GetAssignValues()
+{
+ if (m_pParseTree == nullptr)
+ {
+ ::dbtools::throwFunctionSequenceException(*this);
+ return;
+ }
+
+ if (SQL_ISRULE(m_pParseTree,select_statement))
+ // no values have to be set for SELECT
+ return;
+ else if (SQL_ISRULE(m_pParseTree,insert_statement))
+ {
+ // Create Row for the values to be set (Reference through new)
+ if(m_aAssignValues.is())
+ m_aAssignValues->clear();
+ sal_Int32 nCount = Reference<XIndexAccess>(m_xColNames,UNO_QUERY_THROW)->getCount();
+ m_aAssignValues = new OAssignValues(nCount);
+ // unbound all
+ std::for_each(m_aAssignValues->begin()+1,m_aAssignValues->end(),TSetRefBound(false));
+
+ m_aParameterIndexes.resize(nCount+1,SQL_NO_PARAMETER);
+
+ // List of Column-Names, that exist in the column_commalist (separated by ;):
+ std::vector<OUString> aColumnNameList;
+
+ OSL_ENSURE(m_pParseTree->count() >= 4,"OResultSet: Error in Parse Tree");
+
+ OSQLParseNode * pOptColumnCommalist = m_pParseTree->getChild(3);
+ OSL_ENSURE(pOptColumnCommalist != nullptr,"OResultSet: Error in Parse Tree");
+ OSL_ENSURE(SQL_ISRULE(pOptColumnCommalist,opt_column_commalist),"OResultSet: Error in Parse Tree");
+ if (pOptColumnCommalist->count() == 0)
+ {
+ const Sequence< OUString>& aNames = m_xColNames->getElementNames();
+ aColumnNameList.insert(aColumnNameList.end(), aNames.begin(), aNames.end());
+ }
+ else
+ {
+ OSL_ENSURE(pOptColumnCommalist->count() == 3,"OResultSet: Error in Parse Tree");
+
+ OSQLParseNode * pColumnCommalist = pOptColumnCommalist->getChild(1);
+ OSL_ENSURE(pColumnCommalist != nullptr,"OResultSet: Error in Parse Tree");
+ OSL_ENSURE(SQL_ISRULE(pColumnCommalist,column_commalist),"OResultSet: Error in Parse Tree");
+ OSL_ENSURE(pColumnCommalist->count() > 0,"OResultSet: Error in Parse Tree");
+
+ // All Columns in the column_commalist ...
+ for (size_t i = 0; i < pColumnCommalist->count(); i++)
+ {
+ OSQLParseNode * pCol = pColumnCommalist->getChild(i);
+ OSL_ENSURE(pCol != nullptr,"OResultSet: Error in Parse Tree");
+ aColumnNameList.push_back(pCol->getTokenValue());
+ }
+ }
+ if ( aColumnNameList.empty() )
+ throwFunctionSequenceException(*this);
+
+ // Values ...
+ OSQLParseNode * pValuesOrQuerySpec = m_pParseTree->getChild(4);
+ OSL_ENSURE(pValuesOrQuerySpec != nullptr,"OResultSet: pValuesOrQuerySpec must not be NULL!");
+ OSL_ENSURE(SQL_ISRULE(pValuesOrQuerySpec,values_or_query_spec),"OResultSet: ! SQL_ISRULE(pValuesOrQuerySpec,values_or_query_spec)");
+ OSL_ENSURE(pValuesOrQuerySpec->count() > 0,"OResultSet: pValuesOrQuerySpec->count() <= 0");
+
+ // just "VALUES" is allowed ...
+ if (! SQL_ISTOKEN(pValuesOrQuerySpec->getChild(0),VALUES))
+ throwFunctionSequenceException(*this);
+
+ OSL_ENSURE(pValuesOrQuerySpec->count() == 4,"OResultSet: pValuesOrQuerySpec->count() != 4");
+
+ // List of values
+ OSQLParseNode * pInsertAtomCommalist = pValuesOrQuerySpec->getChild(2);
+ OSL_ENSURE(pInsertAtomCommalist != nullptr,"OResultSet: pInsertAtomCommalist must not be NULL!");
+ OSL_ENSURE(pInsertAtomCommalist->count() > 0,"OResultSet: pInsertAtomCommalist <= 0");
+
+ sal_Int32 nIndex=0;
+ for (size_t i = 0; i < pInsertAtomCommalist->count(); i++)
+ {
+ OSQLParseNode * pRow_Value_Const = pInsertAtomCommalist->getChild(i); // row_value_constructor
+ OSL_ENSURE(pRow_Value_Const != nullptr,"OResultSet: pRow_Value_Const must not be NULL!");
+ if(SQL_ISRULE(pRow_Value_Const,parameter))
+ {
+ ParseAssignValues(aColumnNameList,pRow_Value_Const,nIndex++); // only one Columnname allowed per loop
+ }
+ else if(pRow_Value_Const->isToken())
+ ParseAssignValues(aColumnNameList,pRow_Value_Const,i);
+ else
+ {
+ if(pRow_Value_Const->count() == aColumnNameList.size())
+ {
+ for (size_t j = 0; j < pRow_Value_Const->count(); ++j)
+ ParseAssignValues(aColumnNameList,pRow_Value_Const->getChild(j),nIndex++);
+ }
+ else
+ throwFunctionSequenceException(*this);
+ }
+ }
+ }
+ else if (SQL_ISRULE(m_pParseTree,update_statement_searched))
+ {
+ if(m_aAssignValues.is())
+ m_aAssignValues->clear();
+ sal_Int32 nCount = Reference<XIndexAccess>(m_xColNames,UNO_QUERY_THROW)->getCount();
+ m_aAssignValues = new OAssignValues(nCount);
+ // unbound all
+ std::for_each(m_aAssignValues->begin()+1,m_aAssignValues->end(),TSetRefBound(false));
+
+ m_aParameterIndexes.resize(nCount+1,SQL_NO_PARAMETER);
+
+ OSL_ENSURE(m_pParseTree->count() >= 4,"OResultSet: Error in Parse Tree");
+
+ OSQLParseNode * pAssignmentCommalist = m_pParseTree->getChild(3);
+ OSL_ENSURE(pAssignmentCommalist != nullptr,"OResultSet: pAssignmentCommalist == NULL");
+ OSL_ENSURE(SQL_ISRULE(pAssignmentCommalist,assignment_commalist),"OResultSet: Error in Parse Tree");
+ OSL_ENSURE(pAssignmentCommalist->count() > 0,"OResultSet: pAssignmentCommalist->count() <= 0");
+
+ // work on all assignments (commalist) ...
+ std::vector< OUString> aList(1);
+ for (size_t i = 0; i < pAssignmentCommalist->count(); i++)
+ {
+ OSQLParseNode * pAssignment = pAssignmentCommalist->getChild(i);
+ OSL_ENSURE(pAssignment != nullptr,"OResultSet: pAssignment == NULL");
+ OSL_ENSURE(SQL_ISRULE(pAssignment,assignment),"OResultSet: Error in Parse Tree");
+ OSL_ENSURE(pAssignment->count() == 3,"OResultSet: pAssignment->count() != 3");
+
+ OSQLParseNode * pCol = pAssignment->getChild(0);
+ OSL_ENSURE(pCol != nullptr,"OResultSet: pCol == NULL");
+
+ OSQLParseNode * pComp = pAssignment->getChild(1);
+ OSL_ENSURE(pComp != nullptr,"OResultSet: pComp == NULL");
+ OSL_ENSURE(pComp->getNodeType() == SQLNodeType::Equal,"OResultSet: pComp->getNodeType() != SQLNodeType::Comparison");
+ if (pComp->getTokenValue().toChar() != '=')
+ {
+ throwFunctionSequenceException(*this);
+ }
+
+ OSQLParseNode * pVal = pAssignment->getChild(2);
+ OSL_ENSURE(pVal != nullptr,"OResultSet: pVal == NULL");
+ aList[0] = pCol->getTokenValue();
+ ParseAssignValues(aList,pVal,0);
+ }
+
+ }
+}
+
+void OStatement_Base::ParseAssignValues(const std::vector< OUString>& aColumnNameList,OSQLParseNode* pRow_Value_Constructor_Elem, sal_Int32 nIndex)
+{
+ OSL_ENSURE(o3tl::make_unsigned(nIndex) <= aColumnNameList.size(),"SdbFileCursor::ParseAssignValues: nIndex > aColumnNameList.GetTokenCount()");
+ OUString aColumnName(aColumnNameList[nIndex]);
+ OSL_ENSURE(aColumnName.getLength() > 0,"OResultSet: Column-Name not found");
+ OSL_ENSURE(pRow_Value_Constructor_Elem != nullptr,"OResultSet: pRow_Value_Constructor_Elem must not be NULL!");
+
+ if (pRow_Value_Constructor_Elem->getNodeType() == SQLNodeType::String ||
+ pRow_Value_Constructor_Elem->getNodeType() == SQLNodeType::IntNum ||
+ pRow_Value_Constructor_Elem->getNodeType() == SQLNodeType::ApproxNum)
+ {
+ // set value:
+ SetAssignValue(aColumnName, pRow_Value_Constructor_Elem->getTokenValue());
+ }
+ else if (SQL_ISTOKEN(pRow_Value_Constructor_Elem,NULL))
+ {
+ // set NULL
+ SetAssignValue(aColumnName, OUString(), true);
+ }
+ else if (SQL_ISRULE(pRow_Value_Constructor_Elem,parameter))
+ parseParamterElem(aColumnName,pRow_Value_Constructor_Elem);
+ else
+ {
+ throwFunctionSequenceException(*this);
+ }
+}
+
+void OStatement_Base::SetAssignValue(const OUString& aColumnName,
+ const OUString& aValue,
+ bool bSetNull,
+ sal_uInt32 nParameter)
+{
+ Reference<XPropertySet> xCol;
+ m_xColNames->getByName(aColumnName) >>= xCol;
+ sal_Int32 nId = Reference<XColumnLocate>(m_xColNames,UNO_QUERY_THROW)->findColumn(aColumnName);
+ // does this column actually exist in the file?
+
+ if (!xCol.is())
+ {
+ // This Column doesn't exist!
+ throwFunctionSequenceException(*this);
+ }
+
+
+ // Everything tested and we have the names of the Column.
+ // Now allocate one Value, set the value and tie the value to the Row.
+ if (bSetNull)
+ (*m_aAssignValues)[nId]->setNull();
+ else
+ {
+ switch (::comphelper::getINT32(xCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE))))
+ {
+ // put criteria depending on the Type as String or double in the variable
+ case DataType::CHAR:
+ case DataType::VARCHAR:
+ case DataType::LONGVARCHAR:
+ *(*m_aAssignValues)[nId] = ORowSetValue(aValue);
+ //Characterset is already converted, since the entire statement was converted
+ break;
+
+ case DataType::BIT:
+ if (aValue.equalsIgnoreAsciiCase("TRUE") || aValue[0] == '1')
+ *(*m_aAssignValues)[nId] = true;
+ else if (aValue.equalsIgnoreAsciiCase("FALSE") || aValue[0] == '0')
+ *(*m_aAssignValues)[nId] = false;
+ else
+ throwFunctionSequenceException(*this);
+ break;
+ case DataType::TINYINT:
+ case DataType::SMALLINT:
+ case DataType::INTEGER:
+ case DataType::DECIMAL:
+ case DataType::NUMERIC:
+ case DataType::REAL:
+ case DataType::DOUBLE:
+ case DataType::DATE:
+ case DataType::TIME:
+ case DataType::TIMESTAMP:
+ *(*m_aAssignValues)[nId] = ORowSetValue(aValue);
+ break;
+ default:
+ throwFunctionSequenceException(*this);
+ }
+ }
+
+ // save Parameter-No. (as User Data)
+ // SQL_NO_PARAMETER = no Parameter.
+ m_aAssignValues->setParameterIndex(nId,nParameter);
+ if(nParameter != SQL_NO_PARAMETER)
+ m_aParameterIndexes[nParameter] = nId;
+}
+
+void OStatement_Base::parseParamterElem(const OUString& /*_sColumnName*/,OSQLParseNode* /*pRow_Value_Constructor_Elem*/)
+{
+ // do nothing here
+}
+
+}// namespace
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/file/FStringFunctions.cxx b/connectivity/source/drivers/file/FStringFunctions.cxx
new file mode 100644
index 0000000000..d02c7cce17
--- /dev/null
+++ b/connectivity/source/drivers/file/FStringFunctions.cxx
@@ -0,0 +1,226 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <file/FStringFunctions.hxx>
+
+#include <comphelper/string.hxx>
+#include <rtl/ustrbuf.hxx>
+
+using namespace connectivity;
+using namespace connectivity::file;
+
+ORowSetValue OOp_Upper::operate(const ORowSetValue& lhs) const
+{
+ if (lhs.isNull())
+ return lhs;
+
+ return lhs.getString().toAsciiUpperCase();
+}
+
+ORowSetValue OOp_Lower::operate(const ORowSetValue& lhs) const
+{
+ if (lhs.isNull())
+ return lhs;
+
+ return lhs.getString().toAsciiLowerCase();
+}
+
+ORowSetValue OOp_Ascii::operate(const ORowSetValue& lhs) const
+{
+ if (lhs.isNull())
+ return lhs;
+ OString sStr(OUStringToOString(lhs.getString(), RTL_TEXTENCODING_ASCII_US));
+ sal_Int32 nAscii = sStr.toChar();
+ return nAscii;
+}
+
+ORowSetValue OOp_CharLength::operate(const ORowSetValue& lhs) const
+{
+ if (lhs.isNull())
+ return lhs;
+
+ return lhs.getString().getLength();
+}
+
+ORowSetValue OOp_Char::operate(const std::vector<ORowSetValue>& lhs) const
+{
+ if (lhs.empty())
+ return ORowSetValue();
+
+ OUStringBuffer sRet(static_cast<sal_Int32>(lhs.size()));
+ std::vector<ORowSetValue>::const_reverse_iterator aIter = lhs.rbegin();
+ std::vector<ORowSetValue>::const_reverse_iterator aEnd = lhs.rend();
+ for (; aIter != aEnd; ++aIter)
+ {
+ if (!aIter->isNull())
+ {
+ char c = static_cast<char>(aIter->getInt32());
+
+ sRet.appendAscii(&c, 1);
+ }
+ }
+
+ return sRet.makeStringAndClear();
+}
+
+ORowSetValue OOp_Concat::operate(const std::vector<ORowSetValue>& lhs) const
+{
+ if (lhs.empty())
+ return ORowSetValue();
+
+ OUStringBuffer sRet;
+ std::vector<ORowSetValue>::const_reverse_iterator aIter = lhs.rbegin();
+ std::vector<ORowSetValue>::const_reverse_iterator aEnd = lhs.rend();
+ for (; aIter != aEnd; ++aIter)
+ {
+ if (aIter->isNull())
+ return ORowSetValue();
+
+ sRet.append(aIter->getString());
+ }
+
+ return sRet.makeStringAndClear();
+}
+
+ORowSetValue OOp_Locate::operate(const std::vector<ORowSetValue>& lhs) const
+{
+ if (std::any_of(lhs.begin(), lhs.end(),
+ [](const ORowSetValue& rValue) { return rValue.isNull(); }))
+ return ORowSetValue();
+
+ if (lhs.size() == 2)
+ return OUString(OUString::number(lhs[0].getString().indexOf(lhs[1].getString()) + 1));
+
+ else if (lhs.size() != 3)
+ return ORowSetValue();
+
+ return lhs[1].getString().indexOf(lhs[2].getString(), lhs[0].getInt32()) + 1;
+}
+
+ORowSetValue OOp_SubString::operate(const std::vector<ORowSetValue>& lhs) const
+{
+ if (std::any_of(lhs.begin(), lhs.end(),
+ [](const ORowSetValue& rValue) { return rValue.isNull(); }))
+ return ORowSetValue();
+
+ if (lhs.size() == 2 && lhs[0].getInt32() >= sal_Int32(0))
+ return lhs[1].getString().copy(lhs[0].getInt32() - 1);
+
+ else if (lhs.size() != 3 || lhs[1].getInt32() < sal_Int32(0))
+ return ORowSetValue();
+
+ return lhs[2].getString().copy(lhs[1].getInt32() - 1, lhs[0].getInt32());
+}
+
+ORowSetValue OOp_LTrim::operate(const ORowSetValue& lhs) const
+{
+ if (lhs.isNull())
+ return lhs;
+
+ OUString sRet = lhs.getString();
+ OUString sNew = sRet.trim();
+ return sRet.copy(sRet.indexOf(sNew));
+}
+
+ORowSetValue OOp_RTrim::operate(const ORowSetValue& lhs) const
+{
+ if (lhs.isNull())
+ return lhs;
+
+ OUString sRet = lhs.getString();
+ OUString sNew = sRet.trim();
+ return sRet.copy(0, sRet.lastIndexOf(sNew[sNew.getLength() - 1]) + 1);
+}
+
+ORowSetValue OOp_Space::operate(const ORowSetValue& lhs) const
+{
+ if (lhs.isNull())
+ return lhs;
+
+ sal_Int32 nCount = std::max(lhs.getInt32(), sal_Int32(0));
+ OUStringBuffer sRet(nCount);
+ comphelper::string::padToLength(sRet, nCount, ' ');
+ return sRet.makeStringAndClear();
+}
+
+ORowSetValue OOp_Replace::operate(const std::vector<ORowSetValue>& lhs) const
+{
+ if (lhs.size() != 3)
+ return ORowSetValue();
+
+ OUString sStr = lhs[2].getString();
+ OUString sFrom = lhs[1].getString();
+ OUString sTo = lhs[0].getString();
+ return sStr.replaceAll(sFrom, sTo);
+}
+
+ORowSetValue OOp_Repeat::operate(const ORowSetValue& lhs, const ORowSetValue& rhs) const
+{
+ if (lhs.isNull() || rhs.isNull())
+ return lhs;
+
+ const OUString s = lhs.getString();
+ const sal_Int32 nCount = std::max(rhs.getInt32(), sal_Int32(0));
+ OUStringBuffer sRet(s.getLength() * nCount);
+ for (sal_Int32 i = 0; i < nCount; ++i)
+ {
+ sRet.append(s);
+ }
+ return sRet.makeStringAndClear();
+}
+
+ORowSetValue OOp_Insert::operate(const std::vector<ORowSetValue>& lhs) const
+{
+ if (lhs.size() != 4)
+ return ORowSetValue();
+
+ OUString sStr = lhs[3].getString();
+
+ sal_Int32 nStart = lhs[2].getInt32();
+ if (nStart < 1)
+ nStart = 1;
+ return sStr.replaceAt(nStart - 1, lhs[1].getInt32(), lhs[0].getString());
+}
+
+ORowSetValue OOp_Left::operate(const ORowSetValue& lhs, const ORowSetValue& rhs) const
+{
+ if (lhs.isNull() || rhs.isNull())
+ return lhs;
+
+ OUString sRet = lhs.getString();
+ sal_Int32 nCount = rhs.getInt32();
+ if (nCount < 0)
+ return ORowSetValue();
+ return sRet.copy(0, nCount);
+}
+
+ORowSetValue OOp_Right::operate(const ORowSetValue& lhs, const ORowSetValue& rhs) const
+{
+ if (lhs.isNull() || rhs.isNull())
+ return lhs;
+
+ sal_Int32 nCount = rhs.getInt32();
+ OUString sRet = lhs.getString();
+ if (nCount < 0 || nCount >= sRet.getLength())
+ return ORowSetValue();
+
+ return sRet.copy(sRet.getLength() - nCount, nCount);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/file/FTable.cxx b/connectivity/source/drivers/file/FTable.cxx
new file mode 100644
index 0000000000..06dc187fa2
--- /dev/null
+++ b/connectivity/source/drivers/file/FTable.cxx
@@ -0,0 +1,171 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <file/FTable.hxx>
+#include <file/FColumns.hxx>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XResultSet.hpp>
+#include <comphelper/servicehelper.hxx>
+#include <unotools/ucbstreamhelper.hxx>
+
+using namespace connectivity;
+using namespace connectivity::file;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::container;
+
+OFileTable::OFileTable(sdbcx::OCollection* _pTables,OConnection* _pConnection)
+: OTable_TYPEDEF(_pTables,_pConnection->getMetaData()->supportsMixedCaseQuotedIdentifiers())
+ ,m_pConnection(_pConnection)
+ ,m_nFilePos(0)
+ ,m_nBufferSize(0)
+ ,m_bWriteable(false)
+{
+ construct();
+ m_aColumns = new OSQLColumns();
+}
+
+OFileTable::OFileTable( sdbcx::OCollection* _pTables,OConnection* _pConnection,
+ const OUString& Name,
+ const OUString& Type,
+ const OUString& Description ,
+ const OUString& SchemaName,
+ const OUString& CatalogName )
+ : OTable_TYPEDEF(_pTables,_pConnection->getMetaData()->supportsMixedCaseQuotedIdentifiers(),
+ Name,
+ Type,
+ Description,
+ SchemaName,
+ CatalogName)
+ , m_pConnection(_pConnection)
+ , m_nFilePos(0)
+ , m_nBufferSize(0)
+ , m_bWriteable(false)
+{
+ m_aColumns = new OSQLColumns();
+ construct();
+ // refreshColumns();
+}
+
+OFileTable::~OFileTable( )
+{
+}
+
+void OFileTable::refreshColumns()
+{
+ ::std::vector< OUString> aVector;
+ Reference< XResultSet > xResult = m_pConnection->getMetaData()->getColumns(Any(),
+ m_SchemaName,m_Name, "%");
+
+ if(xResult.is())
+ {
+ Reference< XRow > xRow(xResult,UNO_QUERY);
+ while(xResult->next())
+ aVector.push_back(xRow->getString(4));
+ }
+
+ if(m_xColumns)
+ m_xColumns->reFill(aVector);
+ else
+ m_xColumns.reset(new OColumns(this,m_aMutex,aVector));
+}
+
+void OFileTable::refreshKeys()
+{
+}
+
+void OFileTable::refreshIndexes()
+{
+}
+
+Any SAL_CALL OFileTable::queryInterface( const Type & rType )
+{
+ if( rType == cppu::UnoType<XKeysSupplier>::get()||
+ rType == cppu::UnoType<XRename>::get()||
+ rType == cppu::UnoType<XAlterTable>::get()||
+ rType == cppu::UnoType<XIndexesSupplier>::get()||
+ rType == cppu::UnoType<XDataDescriptorFactory>::get())
+ return Any();
+
+ return OTable_TYPEDEF::queryInterface(rType);
+}
+
+void SAL_CALL OFileTable::disposing()
+{
+ OTable::disposing();
+
+ ::osl::MutexGuard aGuard(m_aMutex);
+
+ FileClose();
+}
+
+void OFileTable::FileClose()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+
+ m_pFileStream.reset();
+ m_pBuffer.reset();
+}
+
+bool OFileTable::InsertRow(OValueRefVector& /*rRow*/, const css::uno::Reference< css::container::XIndexAccess>& /*_xCols*/)
+{
+ return false;
+}
+
+bool OFileTable::DeleteRow(const OSQLColumns& /*_rCols*/)
+{
+ return false;
+}
+
+bool OFileTable::UpdateRow(OValueRefVector& /*rRow*/, OValueRefRow& /*pOrgRow*/,const css::uno::Reference< css::container::XIndexAccess>& /*_xCols*/)
+{
+ return false;
+}
+
+void OFileTable::addColumn(const css::uno::Reference< css::beans::XPropertySet>& /*descriptor*/)
+{
+ OSL_FAIL( "OFileTable::addColumn: not implemented!" );
+}
+
+void OFileTable::dropColumn(sal_Int32 /*_nPos*/)
+{
+ OSL_FAIL( "OFileTable::addColumn: not implemented!" );
+}
+
+
+std::unique_ptr<SvStream> OFileTable::createStream_simpleError( const OUString& _rFileName, StreamMode _eOpenMode)
+{
+ std::unique_ptr<SvStream> pReturn(::utl::UcbStreamHelper::CreateStream( _rFileName, _eOpenMode, bool(_eOpenMode & StreamMode::NOCREATE)));
+ if (pReturn && (ERRCODE_NONE != pReturn->GetErrorCode()))
+ {
+ pReturn.reset();
+ }
+ return pReturn;
+}
+
+
+void OFileTable::refreshHeader()
+{
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/file/FTables.cxx b/connectivity/source/drivers/file/FTables.cxx
new file mode 100644
index 0000000000..c063f4a890
--- /dev/null
+++ b/connectivity/source/drivers/file/FTables.cxx
@@ -0,0 +1,54 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <file/FTables.hxx>
+#include <file/FCatalog.hxx>
+
+using namespace connectivity;
+using namespace connectivity::file;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::container;
+
+sdbcx::ObjectType OTables::createObject(const OUString& /*_rName*/)
+{
+ return sdbcx::ObjectType();
+}
+
+void OTables::impl_refresh( )
+{
+ static_cast<OFileCatalog&>(m_rParent).refreshTables();
+}
+
+Any SAL_CALL OTables::queryInterface( const Type & rType )
+{
+ if( rType == cppu::UnoType<XColumnLocate>::get()||
+ rType == cppu::UnoType<XDataDescriptorFactory>::get()||
+ rType == cppu::UnoType<XAppend>::get()||
+ rType == cppu::UnoType<XDrop>::get())
+ return Any();
+
+ typedef sdbcx::OCollection OTables_BASE;
+ return OTables_BASE::queryInterface(rType);
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/file/fanalyzer.cxx b/connectivity/source/drivers/file/fanalyzer.cxx
new file mode 100644
index 0000000000..a0d1305f6f
--- /dev/null
+++ b/connectivity/source/drivers/file/fanalyzer.cxx
@@ -0,0 +1,207 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <file/fanalyzer.hxx>
+#include <connectivity/sqlparse.hxx>
+#include <tools/debug.hxx>
+#include <connectivity/sqlnode.hxx>
+#include <file/FConnection.hxx>
+#include <strings.hrc>
+
+using namespace ::connectivity;
+using namespace ::connectivity::file;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::container;
+
+OSQLAnalyzer::OSQLAnalyzer(OConnection* _pConnection)
+ :m_pConnection(_pConnection)
+ ,m_bHasSelectionCode(false)
+ ,m_bSelectionFirstTime(true)
+{
+ m_aCompiler = new OPredicateCompiler(this);
+ m_aInterpreter = new OPredicateInterpreter(m_aCompiler);
+}
+
+
+OSQLAnalyzer::~OSQLAnalyzer()
+{
+}
+
+
+void OSQLAnalyzer::start(OSQLParseNode const * pSQLParseNode)
+{
+ if (SQL_ISRULE(pSQLParseNode,select_statement))
+ {
+ DBG_ASSERT(pSQLParseNode->count() >= 4,"OFILECursor: Error in Parse Tree");
+
+ // check that we don't use anything other than count(*) as function
+ OSQLParseNode* pSelection = pSQLParseNode->getChild(2);
+ if ( SQL_ISRULE(pSelection,scalar_exp_commalist) )
+ {
+ for (size_t i = 0; i < pSelection->count(); i++)
+ {
+ OSQLParseNode *pColumnRef = pSelection->getChild(i)->getChild(0);
+ if ( ( SQL_ISRULE(pColumnRef,set_fct_spec) && pColumnRef->count() == 4 )
+ || SQL_ISRULE(pColumnRef,char_value_fct)
+ || SQL_ISRULE(pColumnRef,char_substring_fct)
+ || SQL_ISRULE(pColumnRef,position_exp)
+ || SQL_ISRULE(pColumnRef,fold)
+ || SQL_ISRULE(pColumnRef,length_exp)
+ || SQL_ISRULE(pColumnRef,num_value_exp)
+ || SQL_ISRULE(pColumnRef,term)
+ || SQL_ISRULE(pColumnRef,factor)
+ || SQL_ISRULE(pColumnRef,set_fct_spec) )
+ {
+ ::rtl::Reference<OPredicateCompiler> pCompiler = new OPredicateCompiler(this);
+ pCompiler->setOrigColumns(m_aCompiler->getOrigColumns());
+ ::rtl::Reference<OPredicateInterpreter> pInterpreter = new OPredicateInterpreter(pCompiler);
+ pCompiler->execute( pColumnRef );
+ m_aSelectionEvaluations.push_back( TPredicates(pCompiler,pInterpreter) );
+ }
+ else if ( SQL_ISRULE(pColumnRef,general_set_fct) && pColumnRef->count() != 4 )
+ {
+ m_pConnection->throwGenericSQLException(STR_QUERY_COMPLEX_COUNT,nullptr);
+ }
+ else
+ {
+ if ( SQL_ISPUNCTUATION( pColumnRef, "*" )
+ || ( SQL_ISRULE( pColumnRef, column_ref )
+ && ( pColumnRef->count() == 3 )
+ && ( pColumnRef->getChild(0)->getNodeType() == SQLNodeType::Name )
+ && SQL_ISPUNCTUATION( pColumnRef->getChild(1), "." )
+ && SQL_ISRULE( pColumnRef->getChild(2), column_val )
+ && SQL_ISPUNCTUATION( pColumnRef->getChild(2)->getChild(0), "*" )
+ )
+ )
+ {
+ // push one element for each column of our table
+ const Reference< XNameAccess > xColumnNames( m_aCompiler->getOrigColumns() );
+ const Sequence< OUString > aColumnNames( xColumnNames->getElementNames() );
+ for ( sal_Int32 j=0; j<aColumnNames.getLength(); ++j )
+ m_aSelectionEvaluations.push_back( TPredicates() );
+ }
+ else
+ m_aSelectionEvaluations.push_back( TPredicates() );
+ }
+ }
+ }
+ }
+
+ m_aCompiler->start(pSQLParseNode);
+}
+
+
+void OSQLAnalyzer::bindRow(OCodeList& rCodeList,const OValueRefRow& _pRow)
+{
+ for (auto const& code : rCodeList)
+ {
+ OOperandAttr* pAttr = dynamic_cast<OOperandAttr*>(code.get());
+ if (pAttr)
+ {
+ pAttr->bindValue(_pRow);
+ }
+ }
+}
+
+void OSQLAnalyzer::bindSelectRow(const OValueRefRow& _pRow)
+{
+ // first the select part
+ for (auto const& selectionEval : m_aSelectionEvaluations)
+ {
+ if ( selectionEval.first.is() )
+ bindRow(selectionEval.first->m_aCodeList,_pRow);
+ }
+}
+
+void OSQLAnalyzer::bindEvaluationRow(OValueRefRow const & _pRow)
+{
+ bindRow(m_aCompiler->m_aCodeList,_pRow);
+}
+
+OOperandAttr* OSQLAnalyzer::createOperandAttr(sal_Int32 _nPos,
+ const Reference< XPropertySet>& _xCol)
+{
+ return new OOperandAttr(static_cast<sal_uInt16>(_nPos),_xCol);
+}
+
+bool OSQLAnalyzer::hasRestriction() const
+{
+ return m_aCompiler->hasCode();
+}
+
+bool OSQLAnalyzer::hasFunctions() const
+{
+ if ( m_bSelectionFirstTime )
+ {
+ m_bSelectionFirstTime = false;
+ for (auto const& selectionEval : m_aSelectionEvaluations)
+ {
+ if ( selectionEval.first.is() )
+ {
+ m_bHasSelectionCode = selectionEval.first->hasCode();
+ if (m_bHasSelectionCode)
+ break;
+ }
+ }
+ }
+ return m_bHasSelectionCode;
+}
+
+void OSQLAnalyzer::setSelectionEvaluationResult(OValueRefRow const & _pRow,const std::vector<sal_Int32>& _rColumnMapping)
+{
+ sal_Int32 nPos = 1;
+ for (auto const& selectionEval : m_aSelectionEvaluations)
+ {
+ if ( selectionEval.second.is() )
+ {
+ // the first column (index 0) is for convenience only. The first real select column is no 1.
+ sal_Int32 map = nPos;
+ if ( nPos < static_cast< sal_Int32 >( _rColumnMapping.size() ) )
+ map = _rColumnMapping[nPos];
+ if ( map > 0 )
+ selectionEval.second->startSelection( (*_pRow)[map] );
+ }
+ ++nPos;
+ }
+}
+
+void OSQLAnalyzer::dispose()
+{
+ m_aCompiler->dispose();
+ for (auto const& selectionEval : m_aSelectionEvaluations)
+ {
+ if ( selectionEval.first.is() )
+ selectionEval.first->dispose();
+ }
+}
+
+void OSQLAnalyzer::setOrigColumns(const css::uno::Reference< css::container::XNameAccess>& rCols)
+{
+ m_aCompiler->setOrigColumns(rCols);
+ for (auto const& selectionEval : m_aSelectionEvaluations)
+ {
+ if ( selectionEval.first.is() )
+ selectionEval.first->setOrigColumns(rCols);
+ }
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/file/fcode.cxx b/connectivity/source/drivers/file/fcode.cxx
new file mode 100644
index 0000000000..d41d3e6077
--- /dev/null
+++ b/connectivity/source/drivers/file/fcode.cxx
@@ -0,0 +1,373 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <file/fcode.hxx>
+#include <osl/diagnose.h>
+#include <sal/log.hxx>
+#include <connectivity/sqlnode.hxx>
+#include <sqlbison.hxx>
+#include <com/sun/star/sdb/SQLFilterOperator.hpp>
+
+using namespace ::comphelper;
+using namespace connectivity;
+using namespace connectivity::file;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdb;
+
+OCode::~OCode() = default;
+
+OOperandRow::OOperandRow(sal_uInt16 _nPos, sal_Int32 _rType)
+ : OOperand(_rType)
+ , m_nRowPos(_nPos)
+{}
+
+void OOperandRow::bindValue(const OValueRefRow& _pRow)
+{
+ OSL_ENSURE(_pRow.is(),"NO EMPTY row allowed!");
+ m_pRow = _pRow;
+ OSL_ENSURE(m_pRow.is() && m_nRowPos < m_pRow->size(),"Invalid RowPos is >= vector.size()");
+ (*m_pRow)[m_nRowPos]->setBound(true);
+}
+
+void OOperandRow::setValue(const ORowSetValue& _rVal)
+{
+ OSL_ENSURE(m_pRow.is() && m_nRowPos < m_pRow->size(),"Invalid RowPos is >= vector.size()");
+ (*(*m_pRow)[m_nRowPos]) = _rVal;
+}
+
+const ORowSetValue& OOperandRow::getValue() const
+{
+ OSL_ENSURE(m_pRow.is() && m_nRowPos < m_pRow->size(),"Invalid RowPos is >= vector.size()");
+ return (*m_pRow)[m_nRowPos]->getValue();
+}
+
+
+void OOperandValue::setValue(const ORowSetValue& _rVal)
+{
+ m_aValue = _rVal;
+}
+
+OOperandParam::OOperandParam(sal_Int32 _nPos)
+ : OOperandRow(static_cast<sal_uInt16>(_nPos), DataType::VARCHAR) // Standard-Type
+{
+ //TODO: Actually do something here (the current state of OOperandParam appears to be "the
+ // remains of the very beginnings of a never finished implementation of support for parameters
+ // in this code", as Lionel put it in the comments at <https://gerrit.libreoffice.org/c/core/+/
+ // 116839/1#message-7b2bbf3543f559a0b67dc35cd940e2ab8829c274> "-Werror,-Wunused-but-set-variable
+ // (Clang 13 trunk)").
+}
+
+
+const ORowSetValue& OOperandValue::getValue() const
+{
+ return m_aValue;
+}
+
+
+OOperandConst::OOperandConst(const OSQLParseNode& rColumnRef, const OUString& aStrValue)
+{
+ switch (rColumnRef.getNodeType())
+ {
+ case SQLNodeType::String:
+ m_aValue = aStrValue;
+ m_eDBType = DataType::VARCHAR;
+ m_aValue.setBound(true);
+ return;
+ case SQLNodeType::IntNum:
+ case SQLNodeType::ApproxNum:
+ m_aValue = aStrValue.toDouble();
+ m_eDBType = DataType::DOUBLE;
+ m_aValue.setBound(true);
+ return;
+ default:
+ break;
+ }
+
+ if (SQL_ISTOKEN(&rColumnRef, TRUE))
+ {
+ m_aValue = 1.0;
+ m_eDBType = DataType::BIT;
+ }
+ else if (SQL_ISTOKEN(&rColumnRef, FALSE))
+ {
+ m_aValue = 0.0;
+ m_eDBType = DataType::BIT;
+ }
+ else
+ {
+ SAL_WARN( "connectivity.drivers", "Parse Error");
+ }
+ m_aValue.setBound(true);
+}
+
+
+// Implementation of the operators
+
+
+bool OBoolOperator::operate(const OOperand*, const OOperand*) const
+{
+ return false;
+}
+
+
+void OBoolOperator::Exec(OCodeStack& rCodeStack)
+{
+ OOperand *pRight = rCodeStack.top();
+ rCodeStack.pop();
+ OOperand *pLeft = rCodeStack.top();
+ rCodeStack.pop();
+
+ rCodeStack.push(new OOperandResultBOOL(operate(pLeft, pRight)));
+ if( typeid(OOperandResult) == typeid(*pLeft))
+ delete pLeft;
+ if( typeid(OOperandResult) == typeid(*pRight))
+ delete pRight;
+}
+
+bool OOp_NOT::operate(const OOperand* pLeft, const OOperand* ) const
+{
+ return !pLeft->isValid();
+}
+
+void OOp_NOT::Exec(OCodeStack& rCodeStack)
+{
+ OOperand* pOperand = rCodeStack.top();
+ rCodeStack.pop();
+
+ rCodeStack.push(new OOperandResultBOOL(operate(pOperand, nullptr)));
+
+ if( typeid(OOperandResult) == typeid(*pOperand))
+ delete pOperand;
+}
+
+bool OOp_AND::operate(const OOperand* pLeft, const OOperand* pRight) const
+{
+ return pLeft->isValid() && pRight->isValid();
+}
+
+
+bool OOp_OR::operate(const OOperand* pLeft, const OOperand* pRight) const
+{
+ return pLeft->isValid() || pRight->isValid();
+}
+
+
+void OOp_ISNULL::Exec(OCodeStack& rCodeStack)
+{
+ OOperand* pOperand = rCodeStack.top();
+ rCodeStack.pop();
+
+ rCodeStack.push(new OOperandResultBOOL(operate(pOperand, nullptr)));
+ if( typeid(OOperandResult) == typeid(*pOperand))
+ delete pOperand;
+}
+
+
+bool OOp_ISNULL::operate(const OOperand* pOperand, const OOperand*) const
+{
+ return pOperand->getValue().isNull();
+}
+
+
+bool OOp_ISNOTNULL::operate(const OOperand* pOperand, const OOperand*) const
+{
+ return !OOp_ISNULL::operate(pOperand, nullptr);
+}
+
+
+bool OOp_LIKE::operate(const OOperand* pLeft, const OOperand* pRight) const
+{
+ bool bMatch;
+ const ORowSetValue& aLH(pLeft->getValue());
+ const ORowSetValue& aRH(pRight->getValue());
+
+ if (aLH.isNull() || aRH.isNull())
+ bMatch = false;
+ else
+ {
+ bMatch = match(aRH.getString(), aLH.getString(), cEscape);
+ }
+ return bMatch;
+}
+
+
+bool OOp_NOTLIKE::operate(const OOperand* pLeft, const OOperand* pRight) const
+{
+ return !OOp_LIKE::operate(pLeft, pRight);
+}
+
+
+bool OOp_COMPARE::operate(const OOperand* pLeft, const OOperand* pRight) const
+{
+ const ORowSetValue& aLH(pLeft->getValue());
+ const ORowSetValue& aRH(pRight->getValue());
+
+ if (aLH.isNull() || aRH.isNull()) // if (!aLH.getValue() || !aRH.getValue())
+ return false;
+
+ bool bResult = false;
+ sal_Int32 eDBType = pLeft->getDBType();
+
+ // Comparison (depending on Data-type):
+ switch (eDBType)
+ {
+ case DataType::CHAR:
+ case DataType::VARCHAR:
+ case DataType::LONGVARCHAR:
+ {
+ OUString sLH = aLH.getString(), sRH = aRH.getString();
+ sal_Int32 nRes = sLH.compareToIgnoreAsciiCase(sRH);
+ switch(aPredicateType)
+ {
+ case SQLFilterOperator::EQUAL: bResult = (nRes == 0); break;
+ case SQLFilterOperator::NOT_EQUAL: bResult = (nRes != 0); break;
+ case SQLFilterOperator::LESS: bResult = (nRes < 0); break;
+ case SQLFilterOperator::LESS_EQUAL: bResult = (nRes <= 0); break;
+ case SQLFilterOperator::GREATER: bResult = (nRes > 0); break;
+ case SQLFilterOperator::GREATER_EQUAL: bResult = (nRes >= 0); break;
+ default: bResult = false;
+ }
+ } break;
+ case DataType::TINYINT:
+ case DataType::SMALLINT:
+ case DataType::INTEGER:
+ case DataType::DECIMAL:
+ case DataType::NUMERIC:
+ case DataType::REAL:
+ case DataType::DOUBLE:
+ case DataType::BIT:
+ case DataType::TIMESTAMP:
+ case DataType::DATE:
+ case DataType::TIME:
+ {
+ double n = aLH.getDouble(), m = aRH.getDouble();
+
+ switch (aPredicateType)
+ {
+ case SQLFilterOperator::EQUAL: bResult = (n == m); break;
+ case SQLFilterOperator::LIKE: bResult = (n == m); break;
+ case SQLFilterOperator::NOT_EQUAL: bResult = (n != m); break;
+ case SQLFilterOperator::NOT_LIKE: bResult = (n != m); break;
+ case SQLFilterOperator::LESS: bResult = (n < m); break;
+ case SQLFilterOperator::LESS_EQUAL: bResult = (n <= m); break;
+ case SQLFilterOperator::GREATER: bResult = (n > m); break;
+ case SQLFilterOperator::GREATER_EQUAL: bResult = (n >= m); break;
+ default: bResult = false;
+ }
+ } break;
+ default:
+ bResult = aLH == aRH;
+ }
+ return bResult;
+}
+
+
+void ONumOperator::Exec(OCodeStack& rCodeStack)
+{
+ OOperand *pRight = rCodeStack.top();
+ rCodeStack.pop();
+ OOperand *pLeft = rCodeStack.top();
+ rCodeStack.pop();
+
+ rCodeStack.push(new OOperandResultNUM(operate(pLeft->getValue().getDouble(), pRight->getValue().getDouble())));
+ if( typeid(OOperandResult) == typeid(*pLeft))
+ delete pLeft;
+ if( typeid(OOperandResult) == typeid(*pRight))
+ delete pRight;
+}
+
+double OOp_ADD::operate(const double& fLeft,const double& fRight) const
+{
+ return fLeft + fRight;
+}
+
+
+double OOp_SUB::operate(const double& fLeft,const double& fRight) const
+{
+ return fLeft - fRight;
+}
+
+
+double OOp_MUL::operate(const double& fLeft,const double& fRight) const
+{
+ return fLeft * fRight;
+}
+
+
+double OOp_DIV::operate(const double& fLeft,const double& fRight) const
+{
+ return fLeft / fRight;
+}
+
+void ONthOperator::Exec(OCodeStack& rCodeStack)
+{
+ std::vector<ORowSetValue> aValues;
+ std::vector<OOperand*> aOperands;
+ OOperand* pOperand;
+ do
+ {
+ OSL_ENSURE(!rCodeStack.empty(),"Stack must be none empty!");
+ pOperand = rCodeStack.top();
+ rCodeStack.pop();
+ assert(pOperand);
+ if (pOperand && typeid(OStopOperand) != typeid(*pOperand))
+ aValues.push_back( pOperand->getValue() );
+ aOperands.push_back( pOperand );
+ }
+ while (pOperand && typeid(OStopOperand) != typeid(*pOperand));
+
+ rCodeStack.push(new OOperandResult(operate(aValues)));
+
+ for (const auto& rpOperand : aOperands)
+ {
+ if (typeid(OOperandResult) == typeid(*rpOperand))
+ delete rpOperand;
+ }
+}
+
+void OBinaryOperator::Exec(OCodeStack& rCodeStack)
+{
+ OOperand *pRight = rCodeStack.top();
+ rCodeStack.pop();
+ OOperand *pLeft = rCodeStack.top();
+ rCodeStack.pop();
+
+ if ( !rCodeStack.empty() && typeid(OStopOperand) == typeid(*rCodeStack.top()) )
+ rCodeStack.pop();
+
+ rCodeStack.push(new OOperandResult(operate(pLeft->getValue(),pRight->getValue())));
+ if(typeid(OOperandResult) == typeid(*pRight))
+ delete pRight;
+ if(typeid(OOperandResult) == typeid(*pLeft))
+ delete pLeft;
+}
+
+void OUnaryOperator::Exec(OCodeStack& rCodeStack)
+{
+ OSL_ENSURE(!rCodeStack.empty(),"Stack is empty!");
+ OOperand* pOperand = rCodeStack.top();
+ rCodeStack.pop();
+
+ rCodeStack.push(new OOperandResult(operate(pOperand->getValue())));
+ if (typeid(OOperandResult) == typeid(*pOperand))
+ delete pOperand;
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/file/fcomp.cxx b/connectivity/source/drivers/file/fcomp.cxx
new file mode 100644
index 0000000000..45c9022340
--- /dev/null
+++ b/connectivity/source/drivers/file/fcomp.cxx
@@ -0,0 +1,886 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <file/fcomp.hxx>
+#include <tools/debug.hxx>
+#include <connectivity/sqlparse.hxx>
+#include <file/fanalyzer.hxx>
+#include <com/sun/star/sdbc/XColumnLocate.hpp>
+#include <connectivity/dbexception.hxx>
+#include <connectivity/dbconversion.hxx>
+#include <com/sun/star/sdb/SQLFilterOperator.hpp>
+#include <file/FStringFunctions.hxx>
+#include <file/FDateFunctions.hxx>
+#include <file/FNumericFunctions.hxx>
+#include <file/FConnection.hxx>
+#include <comphelper/diagnose_ex.hxx>
+#include <sqlbison.hxx>
+#include <strings.hrc>
+
+using namespace connectivity;
+using namespace connectivity::file;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::sdbc;
+using namespace com::sun::star::sdb;
+using namespace ::com::sun::star::container;
+using namespace com::sun::star;
+
+OPredicateCompiler::OPredicateCompiler(OSQLAnalyzer* pAnalyzer)//,OCursor& rCurs)
+ : m_pAnalyzer(pAnalyzer)
+ , m_nParamCounter(0)
+{
+}
+
+
+OPredicateCompiler::~OPredicateCompiler()
+{
+ Clean();
+}
+
+void OPredicateCompiler::dispose()
+{
+ Clean();
+ m_orgColumns = nullptr;
+}
+
+void OPredicateCompiler::start(OSQLParseNode const * pSQLParseNode)
+{
+ if (!pSQLParseNode)
+ return;
+
+ m_nParamCounter = 0;
+ // analyse Parse Tree (depending on Statement-type)
+ // and set pointer on WHERE-clause:
+ OSQLParseNode * pWhereClause = nullptr;
+
+ if (SQL_ISRULE(pSQLParseNode,select_statement))
+ {
+ OSQLParseNode * pOrderbyClause = nullptr;
+ DBG_ASSERT(pSQLParseNode->count() >= 4,"OFILECursor: Error in Parse Tree");
+
+ OSQLParseNode * pTableExp = pSQLParseNode->getChild(3);
+ DBG_ASSERT(pTableExp != nullptr,"Error in Parse Tree");
+ DBG_ASSERT(SQL_ISRULE(pTableExp,table_exp)," Error in Parse Tree");
+ DBG_ASSERT(pTableExp->count() == TABLE_EXPRESSION_CHILD_COUNT,"Error in Parse Tree");
+
+ // check that we don't use anything other than count(*) as function
+ OSQLParseNode* pSelection = pSQLParseNode->getChild(2);
+ if ( SQL_ISRULE(pSelection,scalar_exp_commalist) )
+ {
+ for (size_t i = 0; i < pSelection->count(); i++)
+ {
+ OSQLParseNode *pColumnRef = pSelection->getChild(i)->getChild(0);
+ if ( SQL_ISRULE(pColumnRef,general_set_fct) && pColumnRef->count() != 4 )
+ {
+ m_pAnalyzer->getConnection()->throwGenericSQLException(STR_QUERY_COMPLEX_COUNT,nullptr);
+ }
+ }
+ }
+
+
+ pWhereClause = pTableExp->getChild(1);
+ pOrderbyClause = pTableExp->getChild(ORDER_BY_CHILD_POS);
+ (void)pOrderbyClause;
+ }
+ else if (SQL_ISRULE(pSQLParseNode,update_statement_searched))
+ {
+ DBG_ASSERT(pSQLParseNode->count() == 5,"OFILECursor: Error in Parse Tree");
+ pWhereClause = pSQLParseNode->getChild(4);
+ }
+ else if (SQL_ISRULE(pSQLParseNode,delete_statement_searched))
+ {
+ DBG_ASSERT(pSQLParseNode->count() == 4,"Error in Parse Tree");
+ pWhereClause = pSQLParseNode->getChild(3);
+ }
+ else
+ // Other Statement. no selection-criteria
+ return;
+
+ if (SQL_ISRULE(pWhereClause,where_clause))
+ {
+ // a where-clause is not allowed to be empty:
+ DBG_ASSERT(pWhereClause->count() == 2,"OFILECursor: Error in Parse Tree");
+
+ OSQLParseNode * pComparisonPredicate = pWhereClause->getChild(1);
+ DBG_ASSERT(pComparisonPredicate != nullptr,"OFILECursor: Error in Parse Tree");
+
+ execute( pComparisonPredicate );
+ }
+ else
+ {
+ // The where-clause is optionally in the majority of cases, i.e. it might be an "optional-where-clause".
+ DBG_ASSERT(SQL_ISRULE(pWhereClause,opt_where_clause),"OPredicateCompiler: Error in Parse Tree");
+ }
+}
+
+
+OOperand* OPredicateCompiler::execute(OSQLParseNode const * pPredicateNode)
+{
+ OOperand* pOperand = nullptr;
+ if (pPredicateNode->count() == 3 && // Expression is bracketed
+ SQL_ISPUNCTUATION(pPredicateNode->getChild(0),"(") &&
+ SQL_ISPUNCTUATION(pPredicateNode->getChild(2),")"))
+ {
+ execute(pPredicateNode->getChild(1));
+ }
+ else if ((SQL_ISRULE(pPredicateNode,search_condition) || SQL_ISRULE(pPredicateNode,boolean_term))
+ && // AND/OR-linkage:
+ pPredicateNode->count() == 3)
+ {
+ execute(pPredicateNode->getChild(0)); // process the left branch
+ execute(pPredicateNode->getChild(2)); // process the right branch
+
+ if (SQL_ISTOKEN(pPredicateNode->getChild(1),OR)) // OR-Operator
+ {
+ m_aCodeList.emplace_back(new OOp_OR);
+ }
+ else if (SQL_ISTOKEN(pPredicateNode->getChild(1),AND)) // AND-Operator
+ m_aCodeList.emplace_back(new OOp_AND);
+ else
+ {
+ OSL_FAIL("OPredicateCompiler: Error in Parse Tree");
+ }
+ }
+ else if (SQL_ISRULE(pPredicateNode,boolean_factor))
+ {
+ execute(pPredicateNode->getChild(1));
+ m_aCodeList.emplace_back(new OOp_NOT);
+ }
+ else if (SQL_ISRULE(pPredicateNode,comparison_predicate))
+ {
+ execute_COMPARE(pPredicateNode);
+ }
+ else if (SQL_ISRULE(pPredicateNode,like_predicate))
+ {
+ execute_LIKE(pPredicateNode);
+ }
+ else if (SQL_ISRULE(pPredicateNode,between_predicate))
+ {
+ execute_BETWEEN(pPredicateNode);
+ }
+ else if (SQL_ISRULE(pPredicateNode,test_for_null))
+ {
+ execute_ISNULL(pPredicateNode);
+ }
+ else if(SQL_ISRULE(pPredicateNode,num_value_exp))
+ {
+ execute(pPredicateNode->getChild(0)); // process the left branch
+ execute(pPredicateNode->getChild(2)); // process the right branch
+ if (SQL_ISPUNCTUATION(pPredicateNode->getChild(1),"+"))
+ {
+ m_aCodeList.emplace_back(new OOp_ADD);
+ }
+ else if (SQL_ISPUNCTUATION(pPredicateNode->getChild(1),"-"))
+ m_aCodeList.emplace_back(new OOp_SUB);
+ else
+ {
+ OSL_FAIL("OPredicateCompiler: Error in Parse Tree num_value_exp");
+ }
+ }
+ else if(SQL_ISRULE(pPredicateNode,term))
+ {
+ execute(pPredicateNode->getChild(0)); // process the left branch
+ execute(pPredicateNode->getChild(2)); // process the right branch
+ if (SQL_ISPUNCTUATION(pPredicateNode->getChild(1),"*"))
+ {
+ m_aCodeList.emplace_back(new OOp_MUL);
+ }
+ else if (SQL_ISPUNCTUATION(pPredicateNode->getChild(1),"/"))
+ m_aCodeList.emplace_back(new OOp_DIV);
+ else
+ {
+ OSL_FAIL("OPredicateCompiler: Error in Parse Tree num_value_exp");
+ }
+ }
+ else
+ pOperand = execute_Operand(pPredicateNode); // now only simple operands will be processed
+
+ return pOperand;
+}
+
+
+void OPredicateCompiler::execute_COMPARE(OSQLParseNode const * pPredicateNode)
+{
+ DBG_ASSERT(pPredicateNode->count() == 3,"OFILECursor: Error in Parse Tree");
+
+ if ( !(SQL_ISRULE(pPredicateNode->getChild(0),column_ref) ||
+ pPredicateNode->getChild(2)->getNodeType() == SQLNodeType::String ||
+ pPredicateNode->getChild(2)->getNodeType() == SQLNodeType::IntNum ||
+ pPredicateNode->getChild(2)->getNodeType() == SQLNodeType::ApproxNum ||
+ SQL_ISTOKEN(pPredicateNode->getChild(2),TRUE) ||
+ SQL_ISTOKEN(pPredicateNode->getChild(2),FALSE) ||
+ SQL_ISRULE(pPredicateNode->getChild(2),parameter) ||
+ // odbc date
+ SQL_ISRULE(pPredicateNode->getChild(2),set_fct_spec) ||
+ SQL_ISRULE(pPredicateNode->getChild(2),position_exp) ||
+ SQL_ISRULE(pPredicateNode->getChild(2),char_substring_fct) ||
+ // upper, lower etc.
+ SQL_ISRULE(pPredicateNode->getChild(2),fold)) )
+ {
+ m_pAnalyzer->getConnection()->throwGenericSQLException(STR_QUERY_TOO_COMPLEX,nullptr);
+ return;
+ }
+
+ sal_Int32 ePredicateType( SQLFilterOperator::EQUAL );
+ OSQLParseNode *pPrec = pPredicateNode->getChild(1);
+
+ if (pPrec->getNodeType() == SQLNodeType::Equal)
+ ePredicateType = SQLFilterOperator::EQUAL;
+ else if (pPrec->getNodeType() == SQLNodeType::NotEqual)
+ ePredicateType = SQLFilterOperator::NOT_EQUAL;
+ else if (pPrec->getNodeType() == SQLNodeType::Less)
+ ePredicateType = SQLFilterOperator::LESS;
+ else if (pPrec->getNodeType() == SQLNodeType::LessEq)
+ ePredicateType = SQLFilterOperator::LESS_EQUAL;
+ else if (pPrec->getNodeType() == SQLNodeType::GreatEq)
+ ePredicateType = SQLFilterOperator::GREATER_EQUAL;
+ else if (pPrec->getNodeType() == SQLNodeType::Great)
+ ePredicateType = SQLFilterOperator::GREATER;
+ else
+ OSL_FAIL( "OPredicateCompiler::execute_COMPARE: unexpected node type!" );
+
+ execute(pPredicateNode->getChild(0));
+ execute(pPredicateNode->getChild(2));
+ m_aCodeList.emplace_back( new OOp_COMPARE(ePredicateType) );
+}
+
+
+void OPredicateCompiler::execute_LIKE(OSQLParseNode const * pPredicateNode)
+{
+ DBG_ASSERT(pPredicateNode->count() == 2,"OFILECursor: Error in Parse Tree");
+ const OSQLParseNode* pPart2 = pPredicateNode->getChild(1);
+
+ sal_Unicode cEscape = L'\0';
+ const bool bNotLike = pPart2->getChild(0)->isToken();
+
+ OSQLParseNode* pAtom = pPart2->getChild(pPart2->count()-2);
+ OSQLParseNode* pOptEscape = pPart2->getChild(pPart2->count()-1);
+
+ if (!(pAtom->getNodeType() == SQLNodeType::String ||
+ SQL_ISRULE(pAtom,parameter) ||
+ // odbc date
+ SQL_ISRULE(pAtom,set_fct_spec) ||
+ SQL_ISRULE(pAtom,position_exp) ||
+ SQL_ISRULE(pAtom,char_substring_fct) ||
+ // upper, lower etc.
+ SQL_ISRULE(pAtom,fold)) )
+ {
+ m_pAnalyzer->getConnection()->throwGenericSQLException(STR_QUERY_TOO_COMPLEX,nullptr);
+ return;
+ }
+
+ if (pOptEscape->count() != 0)
+ {
+ if (pOptEscape->count() != 2)
+ {
+ m_pAnalyzer->getConnection()->throwGenericSQLException(STR_QUERY_INVALID_LIKE_STRING,nullptr);
+ }
+ OSQLParseNode *pEscNode = pOptEscape->getChild(1);
+ if (pEscNode->getNodeType() != SQLNodeType::String)
+ {
+ m_pAnalyzer->getConnection()->throwGenericSQLException(STR_QUERY_INVALID_LIKE_STRING,nullptr);
+ }
+ else
+ cEscape = pEscNode->getTokenValue().toChar();
+ }
+
+ execute(pPredicateNode->getChild(0));
+ execute(pAtom);
+
+ OBoolOperator* pOperator = bNotLike
+ ? new OOp_NOTLIKE(cEscape)
+ : new OOp_LIKE(cEscape);
+ m_aCodeList.emplace_back(pOperator);
+}
+
+void OPredicateCompiler::execute_BETWEEN(OSQLParseNode const * pPredicateNode)
+{
+ DBG_ASSERT(pPredicateNode->count() == 2,"OFILECursor: Error in Parse Tree");
+
+ OSQLParseNode* pColumn = pPredicateNode->getChild(0);
+ const OSQLParseNode* pPart2 = pPredicateNode->getChild(1);
+ OSQLParseNode* p1stValue = pPart2->getChild(2);
+ OSQLParseNode* p2ndtValue = pPart2->getChild(4);
+
+ if (
+ !(p1stValue->getNodeType() == SQLNodeType::String || SQL_ISRULE(p1stValue,parameter))
+ && !(p2ndtValue->getNodeType() == SQLNodeType::String || SQL_ISRULE(p2ndtValue,parameter))
+ )
+ {
+ m_pAnalyzer->getConnection()->throwGenericSQLException(STR_QUERY_INVALID_BETWEEN,nullptr);
+ }
+
+ bool bNot = SQL_ISTOKEN(pPart2->getChild(0),NOT);
+
+ OOperand* pColumnOp = execute(pColumn);
+ OOperand* pOb1 = execute(p1stValue);
+ OBoolOperator* pOperator = new OOp_COMPARE(bNot ? SQLFilterOperator::LESS_EQUAL : SQLFilterOperator::GREATER);
+ m_aCodeList.emplace_back(pOperator);
+
+ execute(pColumn);
+ OOperand* pOb2 = execute(p2ndtValue);
+ pOperator = new OOp_COMPARE(bNot ? SQLFilterOperator::GREATER_EQUAL : SQLFilterOperator::LESS);
+ m_aCodeList.emplace_back(pOperator);
+
+ if ( pColumnOp && pOb1 && pOb2 )
+ {
+ switch(pColumnOp->getDBType())
+ {
+ case DataType::CHAR:
+ case DataType::VARCHAR:
+ case DataType::LONGVARCHAR:
+ pOb1->setValue(pOb1->getValue().getString());
+ pOb2->setValue(pOb2->getValue().getString());
+ break;
+ case DataType::DECIMAL:
+ case DataType::NUMERIC:
+ pOb1->setValue(pOb1->getValue().getDouble());
+ pOb2->setValue(pOb2->getValue().getDouble());
+ break;
+ case DataType::FLOAT:
+ pOb1->setValue(pOb1->getValue().getFloat());
+ pOb2->setValue(pOb2->getValue().getFloat());
+ break;
+ case DataType::DOUBLE:
+ case DataType::REAL:
+ pOb1->setValue(pOb1->getValue().getDouble());
+ pOb2->setValue(pOb2->getValue().getDouble());
+ break;
+ case DataType::DATE:
+ pOb1->setValue(pOb1->getValue().getDate());
+ pOb2->setValue(pOb2->getValue().getDate());
+ break;
+ case DataType::TIME:
+ pOb1->setValue(pOb1->getValue().getTime());
+ pOb2->setValue(pOb2->getValue().getTime());
+ break;
+ case DataType::TIMESTAMP:
+ pOb1->setValue(pOb1->getValue().getDateTime());
+ pOb2->setValue(pOb2->getValue().getDateTime());
+ break;
+ }
+ }
+
+
+ OBoolOperator* pBoolOp = nullptr;
+ if ( bNot )
+ pBoolOp = new OOp_OR;
+ else
+ pBoolOp = new OOp_AND;
+ m_aCodeList.emplace_back(pBoolOp);
+}
+
+void OPredicateCompiler::execute_ISNULL(OSQLParseNode const * pPredicateNode)
+{
+ DBG_ASSERT(pPredicateNode->count() == 2,"OFILECursor: Error in Parse Tree");
+ const OSQLParseNode* pPart2 = pPredicateNode->getChild(1);
+ DBG_ASSERT(SQL_ISTOKEN(pPart2->getChild(0),IS),"OFILECursor: Error in Parse Tree");
+
+ sal_Int32 ePredicateType;
+ if (SQL_ISTOKEN(pPart2->getChild(1),NOT))
+ ePredicateType = SQLFilterOperator::NOT_SQLNULL;
+ else
+ ePredicateType = SQLFilterOperator::SQLNULL;
+
+ execute(pPredicateNode->getChild(0));
+ OBoolOperator* pOperator = (ePredicateType == SQLFilterOperator::SQLNULL) ?
+ new OOp_ISNULL : new OOp_ISNOTNULL;
+ m_aCodeList.emplace_back(pOperator);
+}
+
+OOperand* OPredicateCompiler::execute_Operand(OSQLParseNode const * pPredicateNode)
+{
+ OOperand* pOperand = nullptr;
+
+ if (SQL_ISRULE(pPredicateNode,column_ref))
+ {
+ OUString aColumnName;
+ if (pPredicateNode->count() == 1)
+ {
+ aColumnName = pPredicateNode->getChild(0)->getTokenValue();
+ }
+ else if (pPredicateNode->count() == 3)
+ {
+ if(SQL_ISRULE(pPredicateNode->getChild(2),column_val))
+ aColumnName = pPredicateNode->getChild(2)->getChild(0)->getTokenValue();
+ else
+ aColumnName = pPredicateNode->getChild(2)->getTokenValue();
+ }
+
+ if(!m_orgColumns->hasByName(aColumnName))
+ {
+ const OUString sError( m_pAnalyzer->getConnection()->getResources().getResourceStringWithSubstitution(
+ STR_INVALID_COLUMNNAME,
+ "$columnname$", aColumnName
+ ) );
+ ::dbtools::throwGenericSQLException( sError, nullptr );
+ }
+ css::uno::Reference< css::beans::XPropertySet> xCol;
+ try
+ {
+ if (m_orgColumns->getByName(aColumnName) >>= xCol)
+ {
+ pOperand = OSQLAnalyzer::createOperandAttr(Reference< XColumnLocate>(m_orgColumns,UNO_QUERY_THROW)->findColumn(aColumnName),xCol);
+ }
+ else
+ {// Column doesn't exist in the Result-set
+ const OUString sError( m_pAnalyzer->getConnection()->getResources().getResourceStringWithSubstitution(
+ STR_INVALID_COLUMNNAME,
+ "$columnname$", aColumnName
+ ) );
+ ::dbtools::throwGenericSQLException( sError, nullptr );
+ }
+ }
+ catch(Exception &)
+ {
+ TOOLS_WARN_EXCEPTION( "connectivity.drivers", "OPredicateCompiler::execute_Operand Exception");
+ }
+ }
+ else if (SQL_ISRULE(pPredicateNode,parameter))
+ {
+ pOperand = new OOperandParam(++m_nParamCounter);
+ }
+ else if (pPredicateNode->getNodeType() == SQLNodeType::String ||
+ pPredicateNode->getNodeType() == SQLNodeType::IntNum ||
+ pPredicateNode->getNodeType() == SQLNodeType::ApproxNum ||
+ pPredicateNode->getNodeType() == SQLNodeType::Name ||
+ SQL_ISTOKEN(pPredicateNode,TRUE) ||
+ SQL_ISTOKEN(pPredicateNode,FALSE) ||
+ SQL_ISRULE(pPredicateNode,parameter))
+ {
+ pOperand = new OOperandConst(*pPredicateNode, pPredicateNode->getTokenValue());
+ }
+ else if((pPredicateNode->count() == 2) &&
+ (SQL_ISPUNCTUATION(pPredicateNode->getChild(0),"+") || SQL_ISPUNCTUATION(pPredicateNode->getChild(0),"-")) &&
+ pPredicateNode->getChild(1)->getNodeType() == SQLNodeType::IntNum)
+ { // if -1 or +1 is there
+ OUString aValue = pPredicateNode->getChild(0)->getTokenValue() + pPredicateNode->getChild(1)->getTokenValue();
+ pOperand = new OOperandConst(*pPredicateNode->getChild(1), aValue);
+ }
+ else if( SQL_ISRULE(pPredicateNode,set_fct_spec) && SQL_ISPUNCTUATION(pPredicateNode->getChild(0),"{") )
+ {
+ const OSQLParseNode* pODBCNode = pPredicateNode->getChild(1);
+ const OSQLParseNode* pODBCNodeChild = pODBCNode->getChild(0);
+
+ // Odbc Date or time
+ if (pODBCNodeChild->getNodeType() == SQLNodeType::Keyword && (
+ SQL_ISTOKEN(pODBCNodeChild,D) ||
+ SQL_ISTOKEN(pODBCNodeChild,T) ||
+ SQL_ISTOKEN(pODBCNodeChild,TS) ))
+ {
+ OUString sDateTime = pODBCNode->getChild(1)->getTokenValue();
+ pOperand = new OOperandConst(*pODBCNode->getChild(1), sDateTime);
+ if(SQL_ISTOKEN(pODBCNodeChild,D))
+ {
+ pOperand->setValue(::dbtools::DBTypeConversion::toDouble(::dbtools::DBTypeConversion::toDate(sDateTime)));
+ }
+ else if(SQL_ISTOKEN(pODBCNodeChild,T))
+ {
+ pOperand->setValue(::dbtools::DBTypeConversion::toDouble(::dbtools::DBTypeConversion::toTime(sDateTime)));
+ }
+ else if(SQL_ISTOKEN(pODBCNodeChild,TS))
+ {
+ pOperand->setValue(::dbtools::DBTypeConversion::toDouble(::dbtools::DBTypeConversion::toDateTime(sDateTime)));
+ }
+ }
+ else
+ m_pAnalyzer->getConnection()->throwGenericSQLException(STR_QUERY_TOO_COMPLEX,nullptr);
+
+ }
+ else if( SQL_ISRULE(pPredicateNode,fold) )
+ {
+ execute_Fold(pPredicateNode);
+ }
+ else if( SQL_ISRULE(pPredicateNode,set_fct_spec)
+ || SQL_ISRULE(pPredicateNode,position_exp)
+ || SQL_ISRULE(pPredicateNode,char_substring_fct)
+ )
+ {
+ executeFunction(pPredicateNode);
+ }
+ else if( SQL_ISRULE(pPredicateNode,length_exp) )
+ {
+ executeFunction(pPredicateNode->getChild(0));
+ }
+ else
+ {
+ m_pAnalyzer->getConnection()->throwGenericSQLException(STR_QUERY_TOO_COMPLEX,nullptr);
+ }
+ if (pOperand)
+ m_aCodeList.emplace_back(pOperand);
+ return pOperand;
+}
+
+
+bool OPredicateInterpreter::evaluate(OCodeList& rCodeList)
+{
+ if (!(rCodeList[0]))
+ return true; // no Predicate
+
+ for (auto const& code : rCodeList)
+ {
+ OOperand* pOperand = dynamic_cast<OOperand* >(code.get());
+ if (pOperand)
+ m_aStack.push(pOperand);
+ else
+ static_cast<OOperator *>(code.get())->Exec(m_aStack);
+ }
+
+ OOperand* pOperand = m_aStack.top();
+ m_aStack.pop();
+
+ DBG_ASSERT(m_aStack.empty(), "Stack error");
+ DBG_ASSERT(pOperand, "Stack error");
+
+ const bool bResult = pOperand->isValid();
+ if (typeid(OOperandResult) == typeid(*pOperand))
+ delete pOperand;
+ return bResult;
+}
+
+void OPredicateInterpreter::evaluateSelection(OCodeList& rCodeList, ORowSetValueDecoratorRef const & _rVal)
+{
+ if (!(rCodeList[0]))
+ return ; // no Predicate
+
+ for (auto const& code : rCodeList)
+ {
+ OOperand* pOperand = dynamic_cast<OOperand* >(code.get());
+ if (pOperand)
+ m_aStack.push(pOperand);
+ else
+ static_cast<OOperator *>(code.get())->Exec(m_aStack);
+ }
+
+ OOperand* pOperand = m_aStack.top();
+ m_aStack.pop();
+
+ DBG_ASSERT(m_aStack.empty(), "Stack error");
+ DBG_ASSERT(pOperand, "Stack error");
+
+ (*_rVal) = pOperand->getValue();
+ if (typeid(OOperandResult) == typeid(*pOperand))
+ delete pOperand;
+}
+
+void OPredicateCompiler::execute_Fold(OSQLParseNode const * pPredicateNode)
+{
+ DBG_ASSERT(pPredicateNode->count() >= 4,"OFILECursor: Error in Parse Tree");
+
+ bool bUpper = SQL_ISTOKEN(pPredicateNode->getChild(0),UPPER);
+
+ execute(pPredicateNode->getChild(2));
+ OOperator* pOperator = nullptr;
+ if ( bUpper )
+ pOperator = new OOp_Upper;
+ else
+ pOperator = new OOp_Lower;
+
+ m_aCodeList.emplace_back(pOperator);
+}
+
+void OPredicateCompiler::executeFunction(OSQLParseNode const * pPredicateNode)
+{
+ OOperator* pOperator = nullptr;
+
+ OSL_ENSURE(pPredicateNode->getChild(0)->isToken(),"The first one must be the name of the function!");
+ sal_Int32 nTokenId = pPredicateNode->getChild(0)->getTokenID();
+ switch ( nTokenId )
+ {
+ case SQL_TOKEN_CHAR_LENGTH:
+ case SQL_TOKEN_LENGTH:
+ case SQL_TOKEN_OCTET_LENGTH:
+ case SQL_TOKEN_ASCII:
+ case SQL_TOKEN_LCASE:
+ case SQL_TOKEN_LTRIM:
+ case SQL_TOKEN_RTRIM:
+ case SQL_TOKEN_SPACE:
+ case SQL_TOKEN_UCASE:
+ case SQL_TOKEN_ABS:
+ case SQL_TOKEN_ACOS:
+ case SQL_TOKEN_ASIN:
+ case SQL_TOKEN_ATAN:
+ case SQL_TOKEN_CEILING:
+ case SQL_TOKEN_COS:
+ case SQL_TOKEN_DEGREES:
+ case SQL_TOKEN_EXP:
+ case SQL_TOKEN_FLOOR:
+ case SQL_TOKEN_LOG10:
+ case SQL_TOKEN_LN:
+ case SQL_TOKEN_RADIANS:
+ case SQL_TOKEN_SIGN:
+ case SQL_TOKEN_SIN:
+ case SQL_TOKEN_SQRT:
+ case SQL_TOKEN_TAN:
+ case SQL_TOKEN_DAYNAME:
+ case SQL_TOKEN_DAYOFMONTH:
+ case SQL_TOKEN_DAYOFWEEK:
+ case SQL_TOKEN_DAYOFYEAR:
+ case SQL_TOKEN_HOUR:
+ case SQL_TOKEN_MINUTE:
+ case SQL_TOKEN_MONTH:
+ case SQL_TOKEN_MONTHNAME:
+ case SQL_TOKEN_QUARTER:
+ case SQL_TOKEN_SECOND:
+ case SQL_TOKEN_YEAR:
+
+ execute(pPredicateNode->getChild(2));
+
+ switch( nTokenId )
+ {
+ case SQL_TOKEN_CHAR_LENGTH:
+ case SQL_TOKEN_LENGTH:
+ case SQL_TOKEN_OCTET_LENGTH:
+ pOperator = new OOp_CharLength;
+ break;
+ case SQL_TOKEN_ASCII:
+ pOperator = new OOp_Ascii;
+ break;
+ case SQL_TOKEN_LCASE:
+ pOperator = new OOp_Lower;
+ break;
+
+ case SQL_TOKEN_LTRIM:
+ pOperator = new OOp_LTrim;
+ break;
+ case SQL_TOKEN_RTRIM:
+ pOperator = new OOp_RTrim;
+ break;
+ case SQL_TOKEN_SPACE:
+ pOperator = new OOp_Space;
+ break;
+ case SQL_TOKEN_UCASE:
+ pOperator = new OOp_Upper;
+ break;
+ case SQL_TOKEN_ABS:
+ pOperator = new OOp_Abs;
+ break;
+ case SQL_TOKEN_ACOS:
+ pOperator = new OOp_ACos;
+ break;
+ case SQL_TOKEN_ASIN:
+ pOperator = new OOp_ASin;
+ break;
+ case SQL_TOKEN_ATAN:
+ pOperator = new OOp_ATan;
+ break;
+ case SQL_TOKEN_CEILING:
+ pOperator = new OOp_Ceiling;
+ break;
+ case SQL_TOKEN_COS:
+ pOperator = new OOp_Cos;
+ break;
+ case SQL_TOKEN_DEGREES:
+ pOperator = new OOp_Degrees;
+ break;
+ case SQL_TOKEN_EXP:
+ pOperator = new OOp_Exp;
+ break;
+ case SQL_TOKEN_FLOOR:
+ pOperator = new OOp_Floor;
+ break;
+ case SQL_TOKEN_LOG10:
+ pOperator = new OOp_Log10;
+ break;
+ case SQL_TOKEN_LN:
+ pOperator = new OOp_Ln;
+ break;
+ case SQL_TOKEN_RADIANS:
+ pOperator = new OOp_Radians;
+ break;
+ case SQL_TOKEN_SIGN:
+ pOperator = new OOp_Sign;
+ break;
+ case SQL_TOKEN_SIN:
+ pOperator = new OOp_Sin;
+ break;
+ case SQL_TOKEN_SQRT:
+ pOperator = new OOp_Sqrt;
+ break;
+ case SQL_TOKEN_TAN:
+ pOperator = new OOp_Tan;
+ break;
+ case SQL_TOKEN_DAYOFWEEK:
+ pOperator = new OOp_DayOfWeek;
+ break;
+ case SQL_TOKEN_DAYOFMONTH:
+ pOperator = new OOp_DayOfMonth;
+ break;
+ case SQL_TOKEN_DAYOFYEAR:
+ pOperator = new OOp_DayOfYear;
+ break;
+ case SQL_TOKEN_MONTH:
+ pOperator = new OOp_Month;
+ break;
+ case SQL_TOKEN_DAYNAME:
+ pOperator = new OOp_DayName;
+ break;
+ case SQL_TOKEN_MONTHNAME:
+ pOperator = new OOp_MonthName;
+ break;
+ case SQL_TOKEN_QUARTER:
+ pOperator = new OOp_Quarter;
+ break;
+ case SQL_TOKEN_YEAR:
+ pOperator = new OOp_Year;
+ break;
+ case SQL_TOKEN_HOUR:
+ pOperator = new OOp_Hour;
+ break;
+ case SQL_TOKEN_MINUTE:
+ pOperator = new OOp_Minute;
+ break;
+ case SQL_TOKEN_SECOND:
+ pOperator = new OOp_Second;
+ break;
+ default:
+ OSL_FAIL("Error in switch!");
+ }
+ break;
+ case SQL_TOKEN_CHAR:
+ case SQL_TOKEN_CONCAT:
+ case SQL_TOKEN_INSERT:
+ case SQL_TOKEN_LEFT:
+ case SQL_TOKEN_LOCATE:
+ case SQL_TOKEN_LOCATE_2:
+ case SQL_TOKEN_REPEAT:
+ case SQL_TOKEN_REPLACE:
+ case SQL_TOKEN_RIGHT:
+ case SQL_TOKEN_MOD:
+ case SQL_TOKEN_ROUND:
+ case SQL_TOKEN_LOGF:
+ case SQL_TOKEN_LOG:
+ case SQL_TOKEN_POWER:
+ case SQL_TOKEN_ATAN2:
+ case SQL_TOKEN_PI:
+ case SQL_TOKEN_CURDATE:
+ case SQL_TOKEN_CURTIME:
+ case SQL_TOKEN_NOW:
+ case SQL_TOKEN_WEEK:
+ {
+ m_aCodeList.emplace_back(new OStopOperand);
+ OSQLParseNode* pList = pPredicateNode->getChild(2);
+ for (size_t i=0; i < pList->count(); ++i)
+ execute(pList->getChild(i));
+
+ switch( nTokenId )
+ {
+ case SQL_TOKEN_CHAR:
+ pOperator = new OOp_Char;
+ break;
+ case SQL_TOKEN_CONCAT:
+ pOperator = new OOp_Concat;
+ break;
+ case SQL_TOKEN_INSERT:
+ pOperator = new OOp_Insert;
+ break;
+ case SQL_TOKEN_LEFT:
+ pOperator = new OOp_Left;
+ break;
+ case SQL_TOKEN_LOCATE:
+ case SQL_TOKEN_LOCATE_2:
+ pOperator = new OOp_Locate;
+ break;
+ case SQL_TOKEN_REPEAT:
+ pOperator = new OOp_Repeat;
+ break;
+ case SQL_TOKEN_REPLACE:
+ pOperator = new OOp_Replace;
+ break;
+ case SQL_TOKEN_RIGHT:
+ pOperator = new OOp_Right;
+ break;
+ case SQL_TOKEN_MOD:
+ pOperator = new OOp_Mod;
+ break;
+ case SQL_TOKEN_ROUND:
+ pOperator = new OOp_Round;
+ break;
+ case SQL_TOKEN_LOGF:
+ case SQL_TOKEN_LOG:
+ pOperator = new OOp_Log;
+ break;
+ case SQL_TOKEN_POWER:
+ pOperator = new OOp_Pow;
+ break;
+ case SQL_TOKEN_ATAN2:
+ pOperator = new OOp_ATan2;
+ break;
+ case SQL_TOKEN_PI:
+ pOperator = new OOp_Pi;
+ break;
+ case SQL_TOKEN_CURDATE:
+ pOperator = new OOp_CurDate;
+ break;
+ case SQL_TOKEN_CURTIME:
+ pOperator = new OOp_CurTime;
+ break;
+ case SQL_TOKEN_NOW:
+ pOperator = new OOp_Now;
+ break;
+ case SQL_TOKEN_WEEK:
+ pOperator = new OOp_Week;
+ break;
+ default:
+ OSL_FAIL("Error in switch!");
+ }
+ }
+ break;
+
+ case SQL_TOKEN_SUBSTRING:
+ m_aCodeList.emplace_back(new OStopOperand);
+ if ( pPredicateNode->count() == 4 ) //char_substring_fct
+ {
+ OSQLParseNode* pList = pPredicateNode->getChild(2);
+ for (size_t i=0; i < pList->count(); ++i)
+ execute(pList->getChild(i));
+ }
+ else
+ {
+ execute(pPredicateNode->getChild(2));
+ execute(pPredicateNode->getChild(4));
+ execute(pPredicateNode->getChild(5)->getChild(1));
+ }
+ pOperator = new OOp_SubString;
+ break;
+
+ case SQL_TOKEN_POSITION:
+ m_aCodeList.emplace_back(new OStopOperand);
+ if ( pPredicateNode->count() == 4 ) //position_exp
+ {
+ OSQLParseNode* pList = pPredicateNode->getChild(2);
+ for (size_t i=0; i < pList->count(); ++i)
+ execute(pList->getChild(i));
+ }
+ else
+ {
+ execute(pPredicateNode->getChild(2));
+ execute(pPredicateNode->getChild(4));
+ }
+ pOperator = new OOp_Locate;
+ break;
+ default:
+ m_pAnalyzer->getConnection()->throwGenericSQLException(STR_QUERY_FUNCTION_NOT_SUPPORTED,nullptr);
+ }
+
+ m_aCodeList.emplace_back(pOperator);
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/file/quotedstring.cxx b/connectivity/source/drivers/file/quotedstring.cxx
new file mode 100644
index 0000000000..f654c709ec
--- /dev/null
+++ b/connectivity/source/drivers/file/quotedstring.cxx
@@ -0,0 +1,146 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <file/quotedstring.hxx>
+#include <rtl/ustrbuf.hxx>
+
+namespace connectivity
+{
+
+ sal_Int32 QuotedTokenizedString::GetTokenCount( sal_Unicode cTok, sal_Unicode cStrDel ) const
+ {
+ const sal_Int32 nLen = m_sString.getLength();
+ if ( !nLen )
+ return 0;
+
+ sal_Int32 nTokCount = 1;
+ bool bStart = true; // Are we on the first character in the Token?
+ bool bInString = false; // Are we WITHIN a (cStrDel delimited) String?
+
+ // Search for String-end after the first not matching character
+ for( sal_Int32 i = 0; i < nLen; ++i )
+ {
+ const sal_Unicode cChar = m_sString[i];
+ if (bStart)
+ {
+ bStart = false;
+ // First character a String-Delimiter?
+ if ( cChar == cStrDel )
+ {
+ bInString = true; // then we are now WITHIN the string!
+ continue; // skip this character!
+ }
+ }
+
+ if (bInString)
+ {
+ // when now the String-Delimiter-character occurs...
+ if ( cChar == cStrDel )
+ {
+ if ((i+1 < nLen) && (m_sString[i+1] == cStrDel))
+ {
+ // double String-Delimiter-character:
+ ++i; // no string-end, skip next character.
+ }
+ else
+ {
+ // String-End
+ bInString = false;
+ }
+ }
+ } // if (bInString)
+ else
+ {
+ // does the Token-character match, then raise TokCount
+ if ( cChar == cTok )
+ {
+ ++nTokCount;
+ bStart = true;
+ }
+ }
+ }
+
+ return nTokCount;
+ }
+
+
+ OUString QuotedTokenizedString::GetTokenSpecial(sal_Int32& nStartPos, sal_Unicode cTok, sal_Unicode cStrDel) const
+ {
+ const sal_Int32 nLen = m_sString.getLength();
+ if ( nLen )
+ {
+ bool bInString = (nStartPos < nLen) && (m_sString[nStartPos] == cStrDel); // are we WITHIN a (cStrDel delimited) String?
+
+ // First character a String-Delimiter?
+ if (bInString )
+ ++nStartPos; // skip this character!
+ if ( nStartPos >= nLen )
+ return OUString();
+
+ OUStringBuffer sBuff( nLen - nStartPos + 1 );
+
+ // Search until end of string for the first not matching character
+ for( sal_Int32 i = nStartPos; i < nLen; ++i )
+ {
+ const sal_Unicode cChar = m_sString[i];
+ if (bInString)
+ {
+ // when now the String-Delimiter-character occurs ...
+ if ( cChar == cStrDel )
+ {
+ if ((i+1 < nLen) && (m_sString[i+1] == cStrDel))
+ {
+ // double String Delimiter-character
+ // no end of string, skip next character.
+ ++i;
+ sBuff.append(m_sString[i]); // character belongs to Result-String
+ }
+ else
+ {
+ //end of String
+ bInString = false;
+ }
+ }
+ else
+ {
+ sBuff.append(cChar);
+ }
+ }
+ else
+ {
+ // does the Token-sign match, then raise nTok
+ if ( cChar == cTok )
+ {
+ // premature break of loop possible, because we found what we were looking for
+ nStartPos = i+1;
+ break;
+ }
+ else
+ {
+ sBuff.append(cChar);
+ }
+ }
+ } // for( sal_Int32 i = nStartPos; i < nLen; ++i )
+ return sBuff.makeStringAndClear();
+ }
+ return OUString();
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/firebird/Blob.cxx b/connectivity/source/drivers/firebird/Blob.cxx
new file mode 100644
index 0000000000..26a5deaca0
--- /dev/null
+++ b/connectivity/source/drivers/firebird/Blob.cxx
@@ -0,0 +1,391 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "Blob.hxx"
+#include "Util.hxx"
+
+#include <com/sun/star/io/BufferSizeExceededException.hpp>
+#include <com/sun/star/io/NotConnectedException.hpp>
+#include <com/sun/star/io/IOException.hpp>
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <connectivity/CommonTools.hxx>
+#include <connectivity/dbexception.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+#include <comphelper/diagnose_ex.hxx>
+
+using namespace ::connectivity::firebird;
+
+using namespace ::cppu;
+using namespace ::osl;
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::io;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::uno;
+
+Blob::Blob(isc_db_handle* pDatabaseHandle,
+ isc_tr_handle* pTransactionHandle,
+ ISC_QUAD const & aBlobID):
+ Blob_BASE(m_aMutex),
+ m_pDatabaseHandle(pDatabaseHandle),
+ m_pTransactionHandle(pTransactionHandle),
+ m_blobID(aBlobID),
+#if SAL_TYPES_SIZEOFPOINTER == 8
+ m_blobHandle(0),
+#else
+ m_blobHandle(nullptr),
+#endif
+ m_bBlobOpened(false),
+ m_nBlobLength(0),
+ m_nMaxSegmentSize(0),
+ m_nBlobPosition(0)
+{
+}
+
+void Blob::ensureBlobIsOpened()
+{
+ MutexGuard aGuard(m_aMutex);
+
+ if (m_bBlobOpened)
+ return;
+
+ ISC_STATUS aErr;
+ aErr = isc_open_blob2(m_statusVector,
+ m_pDatabaseHandle,
+ m_pTransactionHandle,
+ &m_blobHandle,
+ &m_blobID,
+ 0,
+ nullptr);
+
+ if (aErr)
+ evaluateStatusVector(m_statusVector, u"isc_open_blob2", *this);
+
+ m_bBlobOpened = true;
+ m_nBlobPosition = 0;
+
+ char aBlobItems[] = {
+ isc_info_blob_total_length,
+ isc_info_blob_max_segment
+ };
+
+ // Assuming a data (e.g. length of blob) is maximum 64 bit.
+ // That means we need 8 bytes for data + 2 for length of data + 1 for item
+ // identifier for each item.
+ char aResultBuffer[11 + 11];
+
+ aErr = isc_blob_info(m_statusVector,
+ &m_blobHandle,
+ sizeof(aBlobItems),
+ aBlobItems,
+ sizeof(aResultBuffer),
+ aResultBuffer);
+
+ if (aErr)
+ evaluateStatusVector(m_statusVector, u"isc_blob_info", *this);
+
+ char* pIt = aResultBuffer;
+ while( *pIt != isc_info_end ) // info is in clusters
+ {
+ char item = *pIt++;
+ short aResultLength = static_cast<short>(isc_vax_integer(pIt, 2));
+
+ pIt += 2;
+ switch(item)
+ {
+ case isc_info_blob_total_length:
+ m_nBlobLength = isc_vax_integer(pIt, aResultLength);
+ break;
+ case isc_info_blob_max_segment:
+ m_nMaxSegmentSize = isc_vax_integer(pIt, aResultLength);
+ break;
+ default:
+ assert(false);
+ break;
+ }
+ pIt += aResultLength;
+ }
+}
+
+sal_uInt16 Blob::getMaximumSegmentSize()
+{
+ ensureBlobIsOpened();
+
+ return m_nMaxSegmentSize;
+}
+
+bool Blob::readOneSegment(std::vector<char>& rDataOut)
+{
+ checkDisposed(Blob_BASE::rBHelper.bDisposed);
+ ensureBlobIsOpened();
+
+ sal_uInt16 nMaxSize = getMaximumSegmentSize();
+
+ if(rDataOut.size() < nMaxSize)
+ rDataOut.resize(nMaxSize);
+
+ sal_uInt16 nActualSize = 0;
+ ISC_STATUS aRet = isc_get_segment(m_statusVector,
+ &m_blobHandle,
+ &nActualSize,
+ nMaxSize,
+ rDataOut.data() );
+
+ if (aRet && aRet != isc_segstr_eof && IndicatesError(m_statusVector))
+ {
+ OUString sError(StatusVectorToString(m_statusVector, u"isc_get_segment"));
+ throw IOException(sError, *this);
+ }
+
+ if (rDataOut.size() > nActualSize)
+ rDataOut.resize(nActualSize);
+ m_nBlobPosition += nActualSize;
+ return aRet == isc_segstr_eof; // last segment read
+}
+
+
+void Blob::closeBlob()
+{
+ MutexGuard aGuard(m_aMutex);
+
+ if (!m_bBlobOpened)
+ return;
+
+ ISC_STATUS aErr;
+ aErr = isc_close_blob(m_statusVector,
+ &m_blobHandle);
+ if (aErr)
+ evaluateStatusVector(m_statusVector, u"isc_close_blob", *this);
+
+ m_bBlobOpened = false;
+#if SAL_TYPES_SIZEOFPOINTER == 8
+ m_blobHandle = 0;
+#else
+ m_blobHandle = nullptr;
+#endif
+}
+
+void SAL_CALL Blob::disposing()
+{
+ try
+ {
+ closeBlob();
+ }
+ catch (const SQLException &)
+ {
+ // we cannot throw any exceptions here...
+ TOOLS_WARN_EXCEPTION("connectivity.firebird", "isc_close_blob failed");
+ assert(false);
+ }
+ Blob_BASE::disposing();
+}
+
+sal_Int64 SAL_CALL Blob::length()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(Blob_BASE::rBHelper.bDisposed);
+ ensureBlobIsOpened();
+
+ return m_nBlobLength;
+}
+
+uno::Sequence< sal_Int8 > SAL_CALL Blob::getBytes(sal_Int64 nPosition,
+ sal_Int32 nBytes)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(Blob_BASE::rBHelper.bDisposed);
+ ensureBlobIsOpened();
+
+ if (nPosition > m_nBlobLength || nPosition < 1)
+ throw lang::IllegalArgumentException("nPosition out of range", *this, 0);
+ // We only have to read as many bytes as are available, i.e. nPosition+nBytes
+ // can legally be greater than the total length, hence we don't bother to check.
+
+ if (nPosition -1 < m_nBlobPosition)
+ {
+ // Resets to the beginning (we can't seek these blobs)
+ closeBlob();
+ ensureBlobIsOpened();
+ }
+
+ // nPosition is indexed from 1.
+ skipBytes(nPosition - m_nBlobPosition -1 );
+
+ // Don't bother preallocating: readBytes does the appropriate calculations
+ // and reallocates for us.
+ uno::Sequence< sal_Int8 > aBytes;
+ readBytes(aBytes, nBytes);
+ return aBytes;
+}
+
+uno::Reference< XInputStream > SAL_CALL Blob::getBinaryStream()
+{
+ return this;
+}
+
+sal_Int64 SAL_CALL Blob::position(const uno::Sequence< sal_Int8 >& /*rPattern*/,
+ sal_Int64 /*nStart*/)
+{
+ ::dbtools::throwFeatureNotImplementedSQLException("Blob::position", *this);
+ return 0;
+}
+
+sal_Int64 SAL_CALL Blob::positionOfBlob(const uno::Reference< XBlob >& /*rPattern*/,
+ sal_Int64 /*aStart*/)
+{
+ ::dbtools::throwFeatureNotImplementedSQLException("Blob::positionOfBlob", *this);
+ return 0;
+}
+
+// ---- XInputStream ----------------------------------------------------------
+
+sal_Int32 SAL_CALL Blob::readBytes(uno::Sequence< sal_Int8 >& rDataOut,
+ sal_Int32 nBytes)
+{
+ MutexGuard aGuard(m_aMutex);
+
+ try
+ {
+ checkDisposed(Blob_BASE::rBHelper.bDisposed);
+ ensureBlobIsOpened();
+ }
+ catch (const NotConnectedException&)
+ {
+ throw;
+ }
+ catch (const BufferSizeExceededException&)
+ {
+ throw;
+ }
+ catch (const IOException&)
+ {
+ throw;
+ }
+ catch (const RuntimeException&)
+ {
+ throw;
+ }
+ catch (const Exception& e)
+ {
+ css::uno::Any a(cppu::getCaughtException());
+ throw css::lang::WrappedTargetRuntimeException(
+ "wrapped Exception " + e.Message,
+ css::uno::Reference<css::uno::XInterface>(), a);
+ }
+
+ // Ensure we have enough space for the amount of data we can actually read.
+ const sal_Int64 nBytesAvailable = m_nBlobLength - m_nBlobPosition;
+ const sal_Int32 nBytesToRead = std::min<sal_Int64>(nBytes, nBytesAvailable);
+
+ if (rDataOut.getLength() < nBytesToRead)
+ rDataOut.realloc(nBytesToRead);
+
+ sal_Int32 nTotalBytesRead = 0;
+ ISC_STATUS aErr;
+ while (nTotalBytesRead < nBytesToRead)
+ {
+ sal_uInt16 nBytesRead = 0;
+ sal_uInt64 nDataRemaining = nBytesToRead - nTotalBytesRead;
+ sal_uInt16 nReadSize = std::min<sal_uInt64>(nDataRemaining, SAL_MAX_UINT16);
+ aErr = isc_get_segment(m_statusVector,
+ &m_blobHandle,
+ &nBytesRead,
+ nReadSize,
+ reinterpret_cast<char*>(rDataOut.getArray()) + nTotalBytesRead);
+ if (aErr && IndicatesError(m_statusVector))
+ {
+ OUString sError(StatusVectorToString(m_statusVector, u"isc_get_segment"));
+ throw IOException(sError, *this);
+ }
+ nTotalBytesRead += nBytesRead;
+ m_nBlobPosition += nBytesRead;
+ }
+
+ return nTotalBytesRead;
+}
+
+sal_Int32 SAL_CALL Blob::readSomeBytes(uno::Sequence< sal_Int8 >& rDataOut,
+ sal_Int32 nMaximumBytes)
+{
+ // We don't have any way of verifying how many bytes are immediately available,
+ // hence we just pass through direct to readBytes
+ // (Spec: "reads the available number of bytes, at maximum nMaxBytesToRead.")
+ return readBytes(rDataOut, nMaximumBytes);
+}
+
+void SAL_CALL Blob::skipBytes(sal_Int32 nBytesToSkip)
+{
+ // There is no way of directly skipping, hence we have to pretend to skip
+ // by reading & discarding the data.
+ uno::Sequence< sal_Int8 > aBytes;
+ readBytes(aBytes, nBytesToSkip);
+}
+
+sal_Int32 SAL_CALL Blob::available()
+{
+ MutexGuard aGuard(m_aMutex);
+
+ try
+ {
+ checkDisposed(Blob_BASE::rBHelper.bDisposed);
+ ensureBlobIsOpened();
+ }
+ catch (const NotConnectedException&)
+ {
+ throw;
+ }
+ catch (const IOException&)
+ {
+ throw;
+ }
+ catch (const RuntimeException&)
+ {
+ throw;
+ }
+ catch (const Exception& e)
+ {
+ css::uno::Any a(cppu::getCaughtException());
+ throw css::lang::WrappedTargetRuntimeException(
+ "wrapped Exception " + e.Message,
+ css::uno::Reference<css::uno::XInterface>(), a);
+ }
+
+ return m_nBlobLength - m_nBlobPosition;
+}
+
+void SAL_CALL Blob::closeInput()
+{
+ try
+ {
+ closeBlob();
+ }
+ catch (const NotConnectedException&)
+ {
+ throw;
+ }
+ catch (const IOException&)
+ {
+ throw;
+ }
+ catch (const RuntimeException&)
+ {
+ throw;
+ }
+ catch (const Exception& e)
+ {
+ css::uno::Any a(cppu::getCaughtException());
+ throw css::lang::WrappedTargetRuntimeException(
+ "wrapped Exception " + e.Message,
+ css::uno::Reference<css::uno::XInterface>(), a);
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/connectivity/source/drivers/firebird/Blob.hxx b/connectivity/source/drivers/firebird/Blob.hxx
new file mode 100644
index 0000000000..990108934b
--- /dev/null
+++ b/connectivity/source/drivers/firebird/Blob.hxx
@@ -0,0 +1,100 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include <ibase.h>
+
+#include <cppuhelper/compbase.hxx>
+
+#include <com/sun/star/io/XInputStream.hpp>
+#include <com/sun/star/sdbc/XBlob.hpp>
+
+#include <vector>
+
+namespace connectivity::firebird
+ {
+ typedef ::cppu::WeakComponentImplHelper< css::sdbc::XBlob,
+ css::io::XInputStream >
+ Blob_BASE;
+
+ class Blob :
+ public Blob_BASE
+ {
+ protected:
+ ::osl::Mutex m_aMutex;
+
+ isc_db_handle* m_pDatabaseHandle;
+ isc_tr_handle* m_pTransactionHandle;
+ // We store our own copy of the blob id as typically the statement
+ // manages its own blob id, and blobs are independent of a statement
+ // in firebird.
+ ISC_QUAD m_blobID;
+ isc_blob_handle m_blobHandle;
+
+ bool m_bBlobOpened;
+ sal_Int64 m_nBlobLength;
+ sal_uInt16 m_nMaxSegmentSize;
+ sal_Int64 m_nBlobPosition;
+
+ ISC_STATUS_ARRAY m_statusVector;
+
+ /// @throws css::sdbc::SQLException
+ void ensureBlobIsOpened();
+ /**
+ * Closes the blob and cleans up resources -- can be used to reset
+ * the blob if we e.g. want to read from the beginning again.
+ *
+ * @throws css::sdbc::SQLException
+ */
+ void closeBlob();
+ sal_uInt16 getMaximumSegmentSize();
+
+ public:
+ Blob(isc_db_handle* pDatabaseHandle,
+ isc_tr_handle* pTransactionHandle,
+ ISC_QUAD const & aBlobID);
+
+ bool readOneSegment(std::vector<char>& rDataOut);
+
+ // ---- XBlob ----------------------------------------------------
+ virtual sal_Int64 SAL_CALL
+ length() override;
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL
+ getBytes(sal_Int64 aPosition, sal_Int32 aLength) override;
+ virtual css::uno::Reference< css::io::XInputStream > SAL_CALL
+ getBinaryStream() override;
+ virtual sal_Int64 SAL_CALL
+ position(const css::uno::Sequence< sal_Int8 >& rPattern,
+ sal_Int64 aStart) override;
+ virtual sal_Int64 SAL_CALL
+ positionOfBlob(const css::uno::Reference< css::sdbc::XBlob >& rPattern,
+ sal_Int64 aStart) override;
+
+ // ---- XInputStream ----------------------------------------------
+ virtual sal_Int32 SAL_CALL
+ readBytes(css::uno::Sequence< sal_Int8 >& rDataOut,
+ sal_Int32 nBytes) override;
+ virtual sal_Int32 SAL_CALL
+ readSomeBytes(css::uno::Sequence< sal_Int8 >& rDataOut,
+ sal_Int32 nMaximumBytes) override;
+ virtual void SAL_CALL
+ skipBytes(sal_Int32 nBytes) override;
+ virtual sal_Int32 SAL_CALL
+ available() override;
+ virtual void SAL_CALL
+ closeInput() override;
+
+ // ---- OComponentHelper ------------------------------------------
+ virtual void SAL_CALL disposing() override;
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/connectivity/source/drivers/firebird/Catalog.cxx b/connectivity/source/drivers/firebird/Catalog.cxx
new file mode 100644
index 0000000000..2ef4f514b1
--- /dev/null
+++ b/connectivity/source/drivers/firebird/Catalog.cxx
@@ -0,0 +1,105 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "Catalog.hxx"
+#include "Tables.hxx"
+#include "Users.hxx"
+#include "Views.hxx"
+
+#include <com/sun/star/sdbc/XRow.hpp>
+
+using namespace ::connectivity::firebird;
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::uno;
+
+Catalog::Catalog(const uno::Reference< XConnection >& rConnection):
+ OCatalog(rConnection),
+ m_xConnection(rConnection)
+{
+}
+
+//----- OCatalog -------------------------------------------------------------
+void Catalog::refreshTables()
+{
+ Sequence< OUString > aTypes {"TABLE", "VIEW"};
+
+ uno::Reference< XResultSet > xTables = m_xMetaData->getTables(Any(),
+ "%",
+ "%",
+ aTypes);
+
+ if (!xTables.is())
+ return;
+
+ ::std::vector< OUString> aTableNames;
+
+ fillNames(xTables, aTableNames);
+
+ if (!m_pTables)
+ m_pTables.reset( new Tables(m_xConnection->getMetaData(),
+ *this,
+ m_aMutex,
+ aTableNames) );
+ else
+ m_pTables->reFill(aTableNames);
+
+}
+
+void Catalog::refreshViews()
+{
+ css::uno::Reference<css::sdbc::XResultSet> xViews
+ = m_xMetaData->getTables(css::uno::Any(), "%", "%", { "VIEW" });
+
+ if (!xViews.is())
+ return;
+
+ ::std::vector<OUString> aViewNames;
+
+ fillNames(xViews, aViewNames);
+
+ if (!m_pViews)
+ m_pViews.reset(new Views(m_xConnection, *this, m_aMutex, aViewNames));
+ else
+ m_pViews->reFill(aViewNames);
+}
+
+//----- IRefreshableGroups ---------------------------------------------------
+void Catalog::refreshGroups()
+{
+ // TODO: implement me
+}
+
+//----- IRefreshableUsers ----------------------------------------------------
+void Catalog::refreshUsers()
+{
+ Reference<XStatement> xStmt= m_xMetaData->getConnection()->createStatement();
+ uno::Reference< XResultSet > xUsers = xStmt->executeQuery("SELECT DISTINCT RDB$USER FROM RDB$USER_PRIVILEGES");
+
+ if (!xUsers.is())
+ return;
+
+ ::std::vector< OUString> aUserNames;
+
+ uno::Reference< XRow > xRow(xUsers,UNO_QUERY);
+ while (xUsers->next())
+ {
+ aUserNames.push_back(xRow->getString(1));
+ }
+
+ if (!m_pUsers)
+ m_pUsers.reset( new Users(m_xConnection->getMetaData(),
+ *this,
+ m_aMutex,
+ aUserNames) );
+ else
+ m_pUsers->reFill(aUserNames);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/connectivity/source/drivers/firebird/Catalog.hxx b/connectivity/source/drivers/firebird/Catalog.hxx
new file mode 100644
index 0000000000..3ffb9238ed
--- /dev/null
+++ b/connectivity/source/drivers/firebird/Catalog.hxx
@@ -0,0 +1,40 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include <sdbcx/VCatalog.hxx>
+
+namespace connectivity::firebird
+ {
+ class Catalog: public ::connectivity::sdbcx::OCatalog
+ {
+ css::uno::Reference< css::sdbc::XConnection >
+ m_xConnection;
+
+ public:
+ explicit Catalog(const css::uno::Reference< css::sdbc::XConnection >& rConnection);
+
+ // OCatalog
+ virtual void refreshTables() override;
+ virtual void refreshViews() override;
+
+ // IRefreshableGroups
+ virtual void refreshGroups() override;
+
+ // IRefreshableUsers
+ virtual void refreshUsers() override;
+
+ sdbcx::OCollection* getPrivateTables() const { return m_pTables.get(); }
+ sdbcx::OCollection* getPrivateViews() const { return m_pViews.get(); }
+ };
+
+} // namespace connectivity::firebird
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/connectivity/source/drivers/firebird/Clob.cxx b/connectivity/source/drivers/firebird/Clob.cxx
new file mode 100644
index 0000000000..dde050edee
--- /dev/null
+++ b/connectivity/source/drivers/firebird/Clob.cxx
@@ -0,0 +1,141 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <sal/config.h>
+
+#include "Clob.hxx"
+#include "Blob.hxx"
+
+#include <connectivity/CommonTools.hxx>
+#include <connectivity/dbexception.hxx>
+
+using namespace ::connectivity::firebird;
+
+using namespace ::osl;
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::io;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::uno;
+
+Clob::Clob(isc_db_handle* pDatabaseHandle,
+ isc_tr_handle* pTransactionHandle,
+ ISC_QUAD const & aBlobID):
+ Clob_BASE(m_aMutex),
+ m_aBlob(new connectivity::firebird::Blob(pDatabaseHandle, pTransactionHandle, aBlobID)),
+ m_nCharCount(-1)
+{
+}
+
+void SAL_CALL Clob::disposing()
+{
+ m_aBlob->dispose();
+ m_aBlob.clear();
+ Clob_BASE::disposing();
+}
+
+sal_Int64 SAL_CALL Clob::length()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(Clob_BASE::rBHelper.bDisposed);
+
+ if( m_nCharCount >= 0 )
+ return m_nCharCount;
+ m_nCharCount = 0;
+
+ // Read each segment, and calculate it's size by interpreting it as a
+ // character stream. Assume that no characters are split by the segments.
+ bool bLastSegmRead = false;
+ std::vector<char> aSegmentBytes;
+ do
+ {
+ bLastSegmRead = m_aBlob->readOneSegment( aSegmentBytes );
+ OUString sSegment(aSegmentBytes.data(), aSegmentBytes.size(), RTL_TEXTENCODING_UTF8);
+
+ if( !bLastSegmRead)
+ m_nCharCount += sSegment.getLength();
+ }while( !bLastSegmRead );
+
+ m_aBlob->closeInput(); // reset position
+ return m_nCharCount;
+}
+
+OUString SAL_CALL Clob::getSubString(sal_Int64 nPosition,
+ sal_Int32 nLength)
+{
+ if (nPosition < 1) // XClob is indexed from 1
+ throw lang::IllegalArgumentException("nPosition < 1", *this, 0);
+ --nPosition; // make 0-based
+
+ if (nLength < 0)
+ throw lang::IllegalArgumentException("nLength < 0", *this, 0);
+
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(Clob_BASE::rBHelper.bDisposed);
+ // TODO do not reset position if it is not necessary
+ m_aBlob->closeInput(); // reset position
+
+ OUStringBuffer sSegmentBuffer;
+ std::vector<char> aSegmentBytes;
+
+ for (;;)
+ {
+ bool bLastRead = m_aBlob->readOneSegment( aSegmentBytes );
+ // TODO: handle possible case of split UTF-8 character
+ OUString sSegment(aSegmentBytes.data(), aSegmentBytes.size(), RTL_TEXTENCODING_UTF8);
+
+ // skip irrelevant parts
+ if (sSegment.getLength() < nPosition)
+ {
+ if (bLastRead)
+ throw lang::IllegalArgumentException("nPosition out of range", *this, 0);
+ nPosition -= sSegment.getLength();
+ continue;
+ }
+
+ // Getting here for the first time, nPosition may be > 0, meaning copy start offset.
+ // This also handles sSegment.getLength() == nPosition case, including nLength == 0.
+ const sal_Int32 nCharsToCopy = std::min<sal_Int32>(sSegment.getLength() - nPosition,
+ nLength - sSegmentBuffer.getLength());
+ sSegmentBuffer.append(sSegment.subView(nPosition, nCharsToCopy));
+ if (sSegmentBuffer.getLength() == nLength)
+ return sSegmentBuffer.makeStringAndClear();
+
+ assert(sSegmentBuffer.getLength() < nLength);
+
+ if (bLastRead)
+ throw lang::IllegalArgumentException("out of range", *this, 0);
+
+ nPosition = 0; // No offset after first append
+ }
+}
+
+uno::Reference< XInputStream > SAL_CALL Clob::getCharacterStream()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(Clob_BASE::rBHelper.bDisposed);
+
+ return m_aBlob->getBinaryStream();
+}
+
+sal_Int64 SAL_CALL Clob::position(const OUString& /*rPattern*/,
+ sal_Int32 /*nStart*/)
+{
+ ::dbtools::throwFeatureNotImplementedSQLException("Clob::position", *this);
+ return 0;
+}
+
+sal_Int64 SAL_CALL Clob::positionOfClob(const Reference <XClob >& /*rPattern*/,
+ sal_Int64 /*aStart*/)
+{
+ ::dbtools::throwFeatureNotImplementedSQLException("Clob::positionOfClob", *this);
+ return 0;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/connectivity/source/drivers/firebird/Clob.hxx b/connectivity/source/drivers/firebird/Clob.hxx
new file mode 100644
index 0000000000..7fc5459d5d
--- /dev/null
+++ b/connectivity/source/drivers/firebird/Clob.hxx
@@ -0,0 +1,64 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include "Blob.hxx"
+
+#include <cppuhelper/compbase.hxx>
+
+#include <com/sun/star/io/XInputStream.hpp>
+#include <com/sun/star/sdbc/XClob.hpp>
+#include <rtl/ref.hxx>
+
+namespace connectivity::firebird
+ {
+ typedef ::cppu::WeakComponentImplHelper< css::sdbc::XClob >
+ Clob_BASE;
+
+ class Clob :
+ public Clob_BASE
+ {
+ protected:
+ ::osl::Mutex m_aMutex;
+
+ /*
+ * In Firebird Clob (textual Blob) is a subtype of blob,
+ * hence we store the data in a Blob, and the Clob class is
+ * a wrapper around that.
+ */
+ rtl::Reference<connectivity::firebird::Blob> m_aBlob;
+
+ sal_Int64 m_nCharCount;
+
+ public:
+ Clob(isc_db_handle* pDatabaseHandle,
+ isc_tr_handle* pTransactionHandle,
+ ISC_QUAD const & aBlobID);
+
+ // ---- XClob ----------------------------------------------------
+ virtual sal_Int64 SAL_CALL
+ length() override;
+ virtual OUString SAL_CALL
+ getSubString(sal_Int64 aPosition, sal_Int32 aLength) override;
+ virtual css::uno::Reference< css::io::XInputStream > SAL_CALL
+ getCharacterStream() override;
+ virtual sal_Int64 SAL_CALL
+ position(const OUString& rPattern,
+ sal_Int32 aStart) override;
+ virtual sal_Int64 SAL_CALL
+ positionOfClob(const ::css::uno::Reference< ::css::sdbc::XClob >& rPattern,
+ sal_Int64 aStart) override;
+ // ---- OComponentHelper ------------------------------------------
+ virtual void SAL_CALL disposing() override;
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/connectivity/source/drivers/firebird/Column.cxx b/connectivity/source/drivers/firebird/Column.cxx
new file mode 100644
index 0000000000..0a18ebe5b4
--- /dev/null
+++ b/connectivity/source/drivers/firebird/Column.cxx
@@ -0,0 +1,51 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "Column.hxx"
+
+#include <TConnection.hxx>
+
+using namespace connectivity;
+using namespace connectivity::firebird;
+using namespace connectivity::sdbcx;
+
+Column::Column()
+ : OColumn( true ) // case sensitive
+{
+ construct();
+}
+
+void Column::construct()
+{
+ m_sAutoIncrement = "GENERATED BY DEFAULT AS IDENTITY";
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(
+ PROPERTY_ID_AUTOINCREMENTCREATION),
+ PROPERTY_ID_AUTOINCREMENTCREATION,
+ 0,
+ &m_sAutoIncrement,
+ cppu::UnoType<decltype(m_sAutoIncrement)>::get()
+ );
+}
+
+::cppu::IPropertyArrayHelper* Column::createArrayHelper( sal_Int32 /*_nId*/ ) const
+{
+ return doCreateArrayHelper();
+}
+
+::cppu::IPropertyArrayHelper & SAL_CALL Column::getInfoHelper()
+{
+ return *Column_PROP::getArrayHelper(isNew() ? 1 : 0);
+}
+
+css::uno::Sequence< OUString > SAL_CALL Column::getSupportedServiceNames( )
+{
+ return { "com.sun.star.sdbc.Firebird" };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/connectivity/source/drivers/firebird/Column.hxx b/connectivity/source/drivers/firebird/Column.hxx
new file mode 100644
index 0000000000..c66287ce56
--- /dev/null
+++ b/connectivity/source/drivers/firebird/Column.hxx
@@ -0,0 +1,32 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+#pragma once
+
+#include <connectivity/sdbcx/VColumn.hxx>
+
+namespace connectivity::firebird
+ {
+ class Column;
+ typedef ::comphelper::OIdPropertyArrayUsageHelper<Column> Column_PROP;
+ class Column : public sdbcx::OColumn,
+ public Column_PROP
+ {
+ OUString m_sAutoIncrement;
+ protected:
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper( sal_Int32 _nId) const override;
+ virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override;
+ public:
+ Column();
+ virtual void construct() override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/connectivity/source/drivers/firebird/Columns.cxx b/connectivity/source/drivers/firebird/Columns.cxx
new file mode 100644
index 0000000000..200eec1fb5
--- /dev/null
+++ b/connectivity/source/drivers/firebird/Columns.cxx
@@ -0,0 +1,41 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "Columns.hxx"
+#include "Column.hxx"
+
+using namespace ::connectivity;
+using namespace ::connectivity::firebird;
+using namespace ::connectivity::sdbcx;
+
+using namespace ::cppu;
+using namespace ::osl;
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::uno;
+
+Columns::Columns(Table& rTable,
+ Mutex& rMutex,
+ const ::std::vector< OUString>& rVector):
+ OColumnsHelper(rTable,
+ true, // TODO: is this case sensitivity?
+ rMutex,
+ rVector,
+ /*bUseHardRef*/true)
+{
+ OColumnsHelper::setParent(&rTable);
+}
+
+Reference< css::beans::XPropertySet > Columns::createDescriptor()
+{
+ return new Column;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/connectivity/source/drivers/firebird/Columns.hxx b/connectivity/source/drivers/firebird/Columns.hxx
new file mode 100644
index 0000000000..a211f70d18
--- /dev/null
+++ b/connectivity/source/drivers/firebird/Columns.hxx
@@ -0,0 +1,30 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include "Table.hxx"
+
+#include <connectivity/TColumnsHelper.hxx>
+
+namespace connectivity::firebird
+{
+ class Columns: public ::connectivity::OColumnsHelper
+ {
+ protected:
+ virtual css::uno::Reference< css::beans::XPropertySet > createDescriptor() override;
+ public:
+ Columns(Table& rTable,
+ ::osl::Mutex& rMutex,
+ const ::std::vector< OUString> &_rVector);
+ };
+
+} // namespace connectivity::firebird
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/connectivity/source/drivers/firebird/Connection.cxx b/connectivity/source/drivers/firebird/Connection.cxx
new file mode 100644
index 0000000000..d0008272e1
--- /dev/null
+++ b/connectivity/source/drivers/firebird/Connection.cxx
@@ -0,0 +1,979 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "Blob.hxx"
+#include "Catalog.hxx"
+#include "Clob.hxx"
+#include "Connection.hxx"
+#include "DatabaseMetaData.hxx"
+#include "PreparedStatement.hxx"
+#include "Statement.hxx"
+#include "Util.hxx"
+
+#include <stdexcept>
+
+#include <com/sun/star/document/XDocumentEventBroadcaster.hpp>
+#include <com/sun/star/embed/ElementModes.hpp>
+#include <com/sun/star/io/XStream.hpp>
+#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/TransactionIsolation.hpp>
+#include <com/sun/star/ucb/SimpleFileAccess.hpp>
+#include <com/sun/star/ucb/XSimpleFileAccess2.hpp>
+
+#include <connectivity/dbexception.hxx>
+#include <strings.hrc>
+#include <resource/sharedresources.hxx>
+
+#include <comphelper/processfactory.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <comphelper/storagehelper.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+#include <unotools/tempfile.hxx>
+
+#include <osl/file.hxx>
+#include <rtl/strbuf.hxx>
+#include <sal/log.hxx>
+
+using namespace connectivity::firebird;
+using namespace connectivity;
+
+using namespace ::osl;
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::document;
+using namespace ::com::sun::star::embed;
+using namespace ::com::sun::star::io;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::uno;
+
+/**
+ * Location within the .odb that an embedded .fdb will be stored.
+ * Only relevant for embedded dbs.
+ */
+constexpr OUString our_sFDBLocation( u"firebird.fdb"_ustr );
+/**
+ * Older version of LO may store the database in a .fdb file
+ */
+constexpr OUString our_sFBKLocation( u"firebird.fbk"_ustr );
+
+Connection::Connection()
+ : Connection_BASE(m_aMutex)
+ , m_bIsEmbedded(false)
+ , m_bIsFile(false)
+ , m_bIsAutoCommit(true)
+ , m_bIsReadOnly(false)
+ , m_aTransactionIsolation(TransactionIsolation::REPEATABLE_READ)
+#if SAL_TYPES_SIZEOFPOINTER == 8
+ , m_aDBHandle(0)
+ , m_aTransactionHandle(0)
+#else
+ , m_aDBHandle(nullptr)
+ , m_aTransactionHandle(nullptr)
+#endif
+ , m_xCatalog(nullptr)
+ , m_xMetaData(nullptr)
+{
+}
+
+Connection::~Connection()
+{
+ if(!isClosed())
+ close();
+}
+
+namespace {
+
+struct ConnectionGuard
+{
+ oslInterlockedCount& m_refCount;
+ explicit ConnectionGuard(oslInterlockedCount& refCount)
+ : m_refCount(refCount)
+ {
+ osl_atomic_increment(&m_refCount);
+ }
+ ~ConnectionGuard()
+ {
+ osl_atomic_decrement(&m_refCount);
+ }
+};
+
+}
+
+void Connection::construct(const OUString& url, const Sequence< PropertyValue >& info)
+{
+ ConnectionGuard aGuard(m_refCount);
+
+ try
+ {
+ m_sConnectionURL = url;
+
+ bool bIsNewDatabase = false;
+ // the database may be stored as an
+ // fdb file in older versions
+ bool bIsFdbStored = false;
+ if (url == "sdbc:embedded:firebird")
+ {
+ m_bIsEmbedded = true;
+
+ const PropertyValue* pIter = info.getConstArray();
+ const PropertyValue* pEnd = pIter + info.getLength();
+
+ for (;pIter != pEnd; ++pIter)
+ {
+ if ( pIter->Name == "Storage" )
+ {
+ m_xEmbeddedStorage.set(pIter->Value,UNO_QUERY);
+ }
+ else if ( pIter->Name == "Document" )
+ {
+ pIter->Value >>= m_xParentDocument;
+ }
+ }
+
+ if ( !m_xEmbeddedStorage.is() )
+ {
+ ::connectivity::SharedResources aResources;
+ const OUString sMessage = aResources.getResourceString(STR_NO_STORAGE);
+ ::dbtools::throwGenericSQLException(sMessage ,*this);
+ }
+
+ bIsNewDatabase = !m_xEmbeddedStorage->hasElements();
+
+ m_pDatabaseFileDir.reset(new ::utl::TempFileNamed(nullptr, true));
+ m_pDatabaseFileDir->EnableKillingFile();
+ m_sFirebirdURL = m_pDatabaseFileDir->GetFileName() + "/firebird.fdb";
+ m_sFBKPath = m_pDatabaseFileDir->GetFileName() + "/firebird.fbk";
+
+ SAL_INFO("connectivity.firebird", "Temporary .fdb location: " << m_sFirebirdURL);
+
+ if (!bIsNewDatabase)
+ {
+ if (m_xEmbeddedStorage->hasByName(our_sFBKLocation) &&
+ m_xEmbeddedStorage->isStreamElement(our_sFBKLocation))
+ {
+ SAL_INFO("connectivity.firebird", "Extracting* .fbk from .odb" );
+ loadDatabaseFile(our_sFBKLocation, m_sFBKPath);
+ }
+ else if(m_xEmbeddedStorage->hasByName(our_sFDBLocation) &&
+ m_xEmbeddedStorage->isStreamElement(our_sFDBLocation))
+ {
+ SAL_INFO("connectivity.firebird", "Found .fdb instead of .fbk");
+ bIsFdbStored = true;
+ loadDatabaseFile(our_sFDBLocation, m_sFirebirdURL);
+ }
+ else
+ {
+ // There might be files which are not firebird databases.
+ // This is not a problem.
+ bIsNewDatabase = true;
+ }
+ }
+ // TODO: Get DB properties from XML
+
+ }
+ // External file AND/OR remote connection
+ else if (url.startsWith("sdbc:firebird:"))
+ {
+ m_sFirebirdURL = url.copy(strlen("sdbc:firebird:"));
+ if (m_sFirebirdURL.startsWith("file://"))
+ {
+ m_bIsFile = true;
+ uno::Reference< ucb::XSimpleFileAccess > xFileAccess =
+ ucb::SimpleFileAccess::create(comphelper::getProcessComponentContext());
+ if (!xFileAccess->exists(m_sFirebirdURL))
+ bIsNewDatabase = true;
+
+ osl::FileBase::getSystemPathFromFileURL(m_sFirebirdURL, m_sFirebirdURL);
+ }
+ }
+
+ std::string dpbBuffer;
+ {
+ OString userName;
+ OString userPassword;
+
+ dpbBuffer.push_back(isc_dpb_version1);
+ dpbBuffer.push_back(isc_dpb_sql_dialect);
+ dpbBuffer.push_back(1); // 1 byte long
+ dpbBuffer.push_back(SQL_DIALECT_CURRENT);
+
+ // set UTF8 as default character set of the database
+ const char sCharset[] = "UTF8";
+ dpbBuffer.push_back(isc_dpb_set_db_charset);
+ dpbBuffer.push_back(sizeof(sCharset) - 1);
+ dpbBuffer.append(sCharset);
+ // set UTF8 as default character set of the connection
+ dpbBuffer.push_back(isc_dpb_lc_ctype);
+ dpbBuffer.push_back(sizeof(sCharset) - 1);
+ dpbBuffer.append(sCharset);
+
+ // Do any more dpbBuffer additions here
+
+ if (m_bIsEmbedded || m_bIsFile)
+ {
+ userName = "sysdba"_ostr;
+ userPassword = "masterkey"_ostr;
+ }
+ else
+ {
+ for (const auto& rIter : info)
+ {
+ if (rIter.Name == "user")
+ {
+ if (OUString value; rIter.Value >>= value)
+ userName = OUStringToOString(value, RTL_TEXTENCODING_UTF8);
+ }
+ else if (rIter.Name == "password")
+ {
+ if (OUString value; rIter.Value >>= value)
+ userPassword = OUStringToOString(value, RTL_TEXTENCODING_UTF8);
+ }
+ }
+ }
+
+ if (!userName.isEmpty())
+ {
+ const sal_Int32 nMaxUsername = 255; //max size
+ int nUsernameLength = std::min(userName.getLength(), nMaxUsername);
+ dpbBuffer.push_back(isc_dpb_user_name);
+ dpbBuffer.push_back(nUsernameLength);
+ dpbBuffer.append(userName.getStr(), nUsernameLength);
+ }
+
+ if (!userPassword.isEmpty())
+ {
+ const sal_Int32 nMaxPassword = 255; //max size
+ int nPasswordLength = std::min(userPassword.getLength(), nMaxPassword);
+ dpbBuffer.push_back(isc_dpb_password);
+ dpbBuffer.push_back(nPasswordLength);
+ dpbBuffer.append(userPassword.getStr(), nPasswordLength);
+ }
+ }
+
+ // use isc_dpb_utf8_filename to identify encoding of filenames
+ dpbBuffer.push_back(isc_dpb_utf8_filename);
+ dpbBuffer.push_back(0); // no filename here, it is passed to functions directly
+
+ ISC_STATUS_ARRAY status; /* status vector */
+ ISC_STATUS aErr;
+ const OString sFirebirdURL = OUStringToOString(m_sFirebirdURL, RTL_TEXTENCODING_UTF8);
+ if (bIsNewDatabase)
+ {
+ aErr = isc_create_database(status,
+ sFirebirdURL.getLength(),
+ sFirebirdURL.getStr(),
+ &m_aDBHandle,
+ dpbBuffer.size(),
+ dpbBuffer.c_str(),
+ 0);
+ if (aErr)
+ {
+ evaluateStatusVector(status, u"isc_create_database", *this);
+ }
+ }
+ else
+ {
+ if (m_bIsEmbedded && !bIsFdbStored) // We need to restore the .fbk first
+ {
+ runBackupService(isc_action_svc_restore);
+ }
+
+ aErr = isc_attach_database(status,
+ sFirebirdURL.getLength(),
+ sFirebirdURL.getStr(),
+ &m_aDBHandle,
+ dpbBuffer.size(),
+ dpbBuffer.c_str());
+ if (aErr)
+ {
+ evaluateStatusVector(status, u"isc_attach_database", *this);
+ }
+ }
+
+ if (m_bIsEmbedded) // Add DocumentEventListener to save the .fdb as needed
+ {
+ // We need to attach as a document listener in order to be able to store
+ // the temporary db back into the .odb when saving
+ uno::Reference<XDocumentEventBroadcaster> xBroadcaster(m_xParentDocument, UNO_QUERY);
+
+ if (xBroadcaster.is())
+ xBroadcaster->addDocumentEventListener(this);
+ else
+ assert(false);
+ }
+ }
+ catch (const Exception&)
+ {
+ throw;
+ }
+ catch (const std::exception&)
+ {
+ throw;
+ }
+ catch (...) // const Firebird::Exception& firebird throws this, but doesn't install the fb_exception.h that declares it
+
+ {
+ throw std::runtime_error("Generic Firebird::Exception");
+ }
+}
+
+void Connection::notifyDatabaseModified()
+{
+ if (m_xParentDocument.is()) // Only true in embedded mode
+ m_xParentDocument->setModified(true);
+}
+
+//----- XServiceInfo ---------------------------------------------------------
+IMPLEMENT_SERVICE_INFO(Connection, "com.sun.star.sdbc.drivers.firebird.Connection",
+ "com.sun.star.sdbc.Connection")
+
+Reference< XBlob> Connection::createBlob(ISC_QUAD const * pBlobId)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(Connection_BASE::rBHelper.bDisposed);
+
+ Reference< XBlob > xReturn = new Blob(&m_aDBHandle,
+ &m_aTransactionHandle,
+ *pBlobId);
+
+ m_aStatements.push_back(WeakReferenceHelper(xReturn));
+ return xReturn;
+}
+
+Reference< XClob> Connection::createClob(ISC_QUAD const * pBlobId)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(Connection_BASE::rBHelper.bDisposed);
+
+ Reference< XClob > xReturn = new Clob(&m_aDBHandle,
+ &m_aTransactionHandle,
+ *pBlobId);
+
+ m_aStatements.push_back(WeakReferenceHelper(xReturn));
+ return xReturn;
+}
+
+//----- XUnoTunnel ----------------------------------------------------------
+// virtual
+sal_Int64 SAL_CALL Connection::getSomething(const css::uno::Sequence<sal_Int8>& rId)
+{
+ return comphelper::getSomethingImpl(rId, this);
+}
+
+// static
+const css::uno::Sequence<sal_Int8> & Connection::getUnoTunnelId()
+{
+ static const comphelper::UnoIdInit implId;
+ return implId.getSeq();
+}
+
+//----- XConnection ----------------------------------------------------------
+Reference< XStatement > SAL_CALL Connection::createStatement( )
+{
+ MutexGuard aGuard( m_aMutex );
+ checkDisposed(Connection_BASE::rBHelper.bDisposed);
+
+ // the pre
+ if(m_aTypeInfo.empty())
+ buildTypeInfo();
+
+ // create a statement
+ // the statement can only be executed once
+ Reference< XStatement > xReturn = new OStatement(this);
+ m_aStatements.push_back(WeakReferenceHelper(xReturn));
+ return xReturn;
+}
+
+Reference< XPreparedStatement > SAL_CALL Connection::prepareStatement(
+ const OUString& _sSql)
+{
+ SAL_INFO("connectivity.firebird", "prepareStatement() "
+ "called with sql: " << _sSql);
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(Connection_BASE::rBHelper.bDisposed);
+
+ if(m_aTypeInfo.empty())
+ buildTypeInfo();
+
+ Reference< XPreparedStatement > xReturn = new OPreparedStatement(this, _sSql);
+ m_aStatements.push_back(WeakReferenceHelper(xReturn));
+
+ return xReturn;
+}
+
+Reference< XPreparedStatement > SAL_CALL Connection::prepareCall(
+ const OUString& _sSql )
+{
+ SAL_INFO("connectivity.firebird", "prepareCall(). "
+ "_sSql: " << _sSql);
+
+ MutexGuard aGuard( m_aMutex );
+ checkDisposed(Connection_BASE::rBHelper.bDisposed);
+
+ // OUString sSqlStatement (transformPreparedStatement( _sSql ));
+
+ // not implemented yet :-) a task to do
+ return nullptr;
+}
+
+OUString SAL_CALL Connection::nativeSQL( const OUString& _sSql )
+{
+ // We do not need to adapt the SQL for Firebird atm.
+ return _sSql;
+}
+
+void SAL_CALL Connection::setAutoCommit( sal_Bool autoCommit )
+{
+ MutexGuard aGuard( m_aMutex );
+ checkDisposed(Connection_BASE::rBHelper.bDisposed);
+
+ m_bIsAutoCommit = autoCommit;
+
+ if (m_aTransactionHandle)
+ {
+ setupTransaction();
+ }
+}
+
+sal_Bool SAL_CALL Connection::getAutoCommit()
+{
+ MutexGuard aGuard( m_aMutex );
+ checkDisposed(Connection_BASE::rBHelper.bDisposed);
+
+ return m_bIsAutoCommit;
+}
+
+void Connection::setupTransaction()
+{
+ MutexGuard aGuard( m_aMutex );
+ ISC_STATUS status_vector[20];
+
+ // TODO: is this sensible? If we have changed parameters then transaction
+ // is lost...
+ if (m_aTransactionHandle)
+ {
+ disposeStatements();
+ isc_rollback_transaction(status_vector, &m_aTransactionHandle);
+ }
+
+ char aTransactionIsolation = 0;
+ switch (m_aTransactionIsolation)
+ {
+ // TODO: confirm that these are correct.
+ case TransactionIsolation::READ_UNCOMMITTED:
+ aTransactionIsolation = isc_tpb_concurrency;
+ break;
+ case TransactionIsolation::READ_COMMITTED:
+ aTransactionIsolation = isc_tpb_read_committed;
+ break;
+ case TransactionIsolation::REPEATABLE_READ:
+ aTransactionIsolation = isc_tpb_consistency;
+ break;
+ case TransactionIsolation::SERIALIZABLE:
+ aTransactionIsolation = isc_tpb_consistency;
+ break;
+ default:
+ assert( false ); // We must have a valid TransactionIsolation.
+ }
+
+ // You cannot pass an empty tpb parameter so we have to do some pointer
+ // arithmetic to avoid problems. (i.e. aTPB[x] = 0 is invalid)
+ char aTPB[5];
+ char* pTPB = aTPB;
+
+ *pTPB++ = isc_tpb_version3;
+ if (m_bIsAutoCommit)
+ *pTPB++ = isc_tpb_autocommit;
+ *pTPB++ = (!m_bIsReadOnly ? isc_tpb_write : isc_tpb_read);
+ *pTPB++ = aTransactionIsolation;
+ *pTPB++ = isc_tpb_wait;
+
+ isc_start_transaction(status_vector,
+ &m_aTransactionHandle,
+ 1,
+ &m_aDBHandle,
+ pTPB - aTPB, // bytes used in TPB
+ aTPB);
+
+ evaluateStatusVector(status_vector,
+ u"isc_start_transaction",
+ *this);
+}
+
+isc_tr_handle& Connection::getTransaction()
+{
+ MutexGuard aGuard( m_aMutex );
+ if (!m_aTransactionHandle)
+ {
+ setupTransaction();
+ }
+ return m_aTransactionHandle;
+}
+
+void SAL_CALL Connection::commit()
+{
+ MutexGuard aGuard( m_aMutex );
+ checkDisposed(Connection_BASE::rBHelper.bDisposed);
+
+ ISC_STATUS status_vector[20];
+
+ if (!m_bIsAutoCommit && m_aTransactionHandle)
+ {
+ disposeStatements();
+ isc_commit_transaction(status_vector, &m_aTransactionHandle);
+ evaluateStatusVector(status_vector,
+ u"isc_commit_transaction",
+ *this);
+ }
+}
+
+void Connection::loadDatabaseFile(const OUString& srcLocation, const OUString& tmpLocation)
+{
+ Reference< XStream > xDBStream(m_xEmbeddedStorage->openStreamElement(srcLocation,
+ ElementModes::READ));
+
+ uno::Reference< ucb::XSimpleFileAccess2 > xFileAccess =
+ ucb::SimpleFileAccess::create( comphelper::getProcessComponentContext() );
+ if ( !xFileAccess.is() )
+ {
+ ::connectivity::SharedResources aResources;
+ // TODO FIXME: this does _not_ look like the right error message
+ const OUString sMessage = aResources.getResourceString(STR_ERROR_NEW_VERSION);
+ ::dbtools::throwGenericSQLException(sMessage ,*this);
+ }
+ xFileAccess->writeFile(tmpLocation,xDBStream->getInputStream());
+}
+
+isc_svc_handle Connection::attachServiceManager()
+{
+ ISC_STATUS_ARRAY aStatusVector;
+#if SAL_TYPES_SIZEOFPOINTER == 8
+ isc_svc_handle aServiceHandle = 0;
+#else
+ isc_svc_handle aServiceHandle = nullptr;
+#endif
+
+ char aSPBBuffer[256];
+ char* pSPB = aSPBBuffer;
+ *pSPB++ = isc_spb_version;
+ *pSPB++ = isc_spb_current_version;
+ *pSPB++ = isc_spb_user_name;
+ OUString sUserName("SYSDBA");
+ char aLength = static_cast<char>(sUserName.getLength());
+ *pSPB++ = aLength;
+ strncpy(pSPB,
+ OUStringToOString(sUserName,
+ RTL_TEXTENCODING_UTF8).getStr(),
+ aLength);
+ pSPB += aLength;
+ // TODO: do we need ", isc_dpb_trusted_auth, 1, 1" -- probably not but ...
+ if (isc_service_attach(aStatusVector,
+ 0, // Denotes null-terminated string next
+ "service_mgr",
+ &aServiceHandle,
+ pSPB - aSPBBuffer,
+ aSPBBuffer))
+ {
+ evaluateStatusVector(aStatusVector,
+ u"isc_service_attach",
+ *this);
+ }
+
+ return aServiceHandle;
+}
+
+void Connection::detachServiceManager(isc_svc_handle aServiceHandle)
+{
+ ISC_STATUS_ARRAY aStatusVector;
+ if (isc_service_detach(aStatusVector,
+ &aServiceHandle))
+ {
+ evaluateStatusVector(aStatusVector,
+ u"isc_service_detach",
+ *this);
+ }
+}
+
+void Connection::runBackupService(const short nAction)
+{
+ assert(nAction == isc_action_svc_backup
+ || nAction == isc_action_svc_restore);
+
+ ISC_STATUS_ARRAY aStatusVector;
+
+ // convert paths to 8-Bit strings
+ OString sFDBPath = OUStringToOString(m_sFirebirdURL, RTL_TEXTENCODING_UTF8);
+ OString sFBKPath = OUStringToOString(m_sFBKPath, RTL_TEXTENCODING_UTF8);
+
+
+ sal_uInt16 nFDBLength = sFDBPath.getLength();
+ sal_uInt16 nFBKLength = sFBKPath.getLength();
+ OStringBuffer aRequest( // byte array
+ OStringChar(static_cast<char>(nAction))
+ + OStringChar(char(isc_spb_dbname)) // .fdb
+ + OStringChar(static_cast<char>(nFDBLength & 0xFF)) // least significant byte first
+ + OStringChar(static_cast<char>((nFDBLength >> 8) & 0xFF))
+ + sFDBPath
+ + OStringChar(char(isc_spb_bkp_file)) // .fbk
+ + OStringChar(static_cast<char>(nFBKLength & 0xFF))
+ + OStringChar(static_cast<char>((nFBKLength >> 8) & 0xFF))
+ + sFBKPath);
+
+ if (nAction == isc_action_svc_restore)
+ {
+ aRequest.append(char(isc_spb_options)); // 4-Byte bitmask
+ char sOptions[4];
+ char * pOptions = sOptions;
+#ifdef _WIN32
+#pragma warning(push)
+#pragma warning(disable: 4310) // cast truncates data
+#endif
+ ADD_SPB_NUMERIC(pOptions, isc_spb_res_create);
+#ifdef _WIN32
+#pragma warning(pop)
+#endif
+ aRequest.append(sOptions, 4);
+ }
+
+ isc_svc_handle aServiceHandle;
+ aServiceHandle = attachServiceManager();
+
+ if (isc_service_start(aStatusVector,
+ &aServiceHandle,
+ nullptr,
+ aRequest.getLength(),
+ aRequest.getStr()))
+ {
+ evaluateStatusVector(aStatusVector, u"isc_service_start", *this);
+ }
+
+ char aInfoSPB = isc_info_svc_line;
+ char aResults[256];
+
+ // query blocks until success or error
+ if(isc_service_query(aStatusVector,
+ &aServiceHandle,
+ nullptr, // Reserved null
+ 0,nullptr, // "send" spb -- size and spb -- not needed?
+ 1,
+ &aInfoSPB,
+ sizeof(aResults),
+ aResults))
+ {
+ evaluateStatusVector(aStatusVector, u"isc_service_query", *this);
+ }
+
+ detachServiceManager(aServiceHandle);
+}
+
+
+void SAL_CALL Connection::rollback()
+{
+ MutexGuard aGuard( m_aMutex );
+ checkDisposed(Connection_BASE::rBHelper.bDisposed);
+
+ ISC_STATUS status_vector[20];
+
+ if (!m_bIsAutoCommit && m_aTransactionHandle)
+ {
+ isc_rollback_transaction(status_vector, &m_aTransactionHandle);
+ }
+}
+
+sal_Bool SAL_CALL Connection::isClosed( )
+{
+ MutexGuard aGuard( m_aMutex );
+
+ // just simple -> we are close when we are disposed that means someone called dispose(); (XComponent)
+ return Connection_BASE::rBHelper.bDisposed;
+}
+
+Reference< XDatabaseMetaData > SAL_CALL Connection::getMetaData( )
+{
+ MutexGuard aGuard( m_aMutex );
+ checkDisposed(Connection_BASE::rBHelper.bDisposed);
+
+ // here we have to create the class with biggest interface
+ // The answer is 42 :-)
+ Reference< XDatabaseMetaData > xMetaData = m_xMetaData;
+ if(!xMetaData.is())
+ {
+ xMetaData = new ODatabaseMetaData(this); // need the connection because it can return it
+ m_xMetaData = xMetaData;
+ }
+
+ return xMetaData;
+}
+
+void SAL_CALL Connection::setReadOnly(sal_Bool readOnly)
+{
+ MutexGuard aGuard( m_aMutex );
+ checkDisposed(Connection_BASE::rBHelper.bDisposed);
+
+ m_bIsReadOnly = readOnly;
+ setupTransaction();
+}
+
+sal_Bool SAL_CALL Connection::isReadOnly()
+{
+ MutexGuard aGuard( m_aMutex );
+ checkDisposed(Connection_BASE::rBHelper.bDisposed);
+
+ return m_bIsReadOnly;
+}
+
+void SAL_CALL Connection::setCatalog(const OUString& /*catalog*/)
+{
+ ::dbtools::throwFunctionNotSupportedSQLException("setCatalog", *this);
+}
+
+OUString SAL_CALL Connection::getCatalog()
+{
+ ::dbtools::throwFunctionNotSupportedSQLException("getCatalog", *this);
+ return OUString();
+}
+
+void SAL_CALL Connection::setTransactionIsolation( sal_Int32 level )
+{
+ MutexGuard aGuard( m_aMutex );
+ checkDisposed(Connection_BASE::rBHelper.bDisposed);
+
+ m_aTransactionIsolation = level;
+ setupTransaction();
+}
+
+sal_Int32 SAL_CALL Connection::getTransactionIsolation( )
+{
+ MutexGuard aGuard( m_aMutex );
+ checkDisposed(Connection_BASE::rBHelper.bDisposed);
+
+ return m_aTransactionIsolation;
+}
+
+Reference< XNameAccess > SAL_CALL Connection::getTypeMap()
+{
+ ::dbtools::throwFeatureNotImplementedSQLException( "XConnection::getTypeMap", *this );
+ return nullptr;
+}
+
+void SAL_CALL Connection::setTypeMap(const Reference< XNameAccess >&)
+{
+ ::dbtools::throwFeatureNotImplementedSQLException( "XConnection::setTypeMap", *this );
+}
+
+//----- XCloseable -----------------------------------------------------------
+void SAL_CALL Connection::close( )
+{
+ // we just dispose us
+ {
+ MutexGuard aGuard( m_aMutex );
+ checkDisposed(Connection_BASE::rBHelper.bDisposed);
+
+ }
+ dispose();
+}
+
+// XWarningsSupplier
+Any SAL_CALL Connection::getWarnings( )
+{
+ // when you collected some warnings -> return it
+ return Any();
+}
+
+void SAL_CALL Connection::clearWarnings( )
+{
+ // you should clear your collected warnings here
+}
+
+// XDocumentEventListener
+void SAL_CALL Connection::documentEventOccured( const DocumentEvent& Event )
+{
+ MutexGuard aGuard(m_aMutex);
+
+ if (!m_bIsEmbedded)
+ return;
+
+ if (Event.EventName != "OnSave" && Event.EventName != "OnSaveAs")
+ return;
+
+ commit(); // Commit and close transaction
+ if ( !(m_bIsEmbedded && m_xEmbeddedStorage.is()) )
+ return;
+
+ SAL_INFO("connectivity.firebird", "Writing .fbk from running db");
+ try
+ {
+ runBackupService(isc_action_svc_backup);
+ }
+ catch (const SQLException& e)
+ {
+ auto a = cppu::getCaughtException();
+ throw WrappedTargetRuntimeException(e.Message, e.Context, a);
+ }
+
+
+ Reference< XStream > xDBStream(m_xEmbeddedStorage->openStreamElement(our_sFBKLocation,
+ ElementModes::WRITE));
+
+ // TODO: verify the backup actually exists -- the backup service
+ // can fail without giving any sane error messages / telling us
+ // that it failed.
+ using namespace ::comphelper;
+ Reference< XComponentContext > xContext = comphelper::getProcessComponentContext();
+ Reference< XInputStream > xInputStream;
+ if (!xContext.is())
+ return;
+
+ xInputStream =
+ OStorageHelper::GetInputStreamFromURL(m_sFBKPath, xContext);
+ if (xInputStream.is())
+ OStorageHelper::CopyInputToOutput( xInputStream,
+ xDBStream->getOutputStream());
+
+ // remove old fdb file if exists
+ uno::Reference< ucb::XSimpleFileAccess > xFileAccess =
+ ucb::SimpleFileAccess::create(xContext);
+ if (xFileAccess->exists(m_sFirebirdURL))
+ xFileAccess->kill(m_sFirebirdURL);
+}
+// XEventListener
+void SAL_CALL Connection::disposing(const EventObject& /*rSource*/)
+{
+ MutexGuard aGuard( m_aMutex );
+
+ m_xEmbeddedStorage.clear();
+}
+
+void Connection::buildTypeInfo()
+{
+ MutexGuard aGuard( m_aMutex );
+
+ Reference< XResultSet> xRs = getMetaData ()->getTypeInfo ();
+ Reference< XRow> xRow(xRs,UNO_QUERY);
+ // Information for a single SQL type
+
+ // Loop on the result set until we reach end of file
+
+ while (xRs->next ())
+ {
+ OTypeInfo aInfo;
+ aInfo.aTypeName = xRow->getString (1);
+ aInfo.nType = xRow->getShort (2);
+ aInfo.nPrecision = xRow->getInt (3);
+ // aLiteralPrefix = xRow->getString (4);
+ // aLiteralSuffix = xRow->getString (5);
+ // aCreateParams = xRow->getString (6);
+ // bNullable = xRow->getBoolean (7);
+ // bCaseSensitive = xRow->getBoolean (8);
+ // nSearchType = xRow->getShort (9);
+ // bUnsigned = xRow->getBoolean (10);
+ // bCurrency = xRow->getBoolean (11);
+ // bAutoIncrement = xRow->getBoolean (12);
+ aInfo.aLocalTypeName = xRow->getString (13);
+ // nMinimumScale = xRow->getShort (14);
+ aInfo.nMaximumScale = xRow->getShort (15);
+ // nNumPrecRadix = (sal_Int16)xRow->getInt(18);
+
+
+ // Now that we have the type info, save it
+ // in the Hashtable if we don't already have an
+ // entry for this SQL type.
+
+ m_aTypeInfo.push_back(aInfo);
+ }
+
+ SAL_INFO("connectivity.firebird", "buildTypeInfo(). "
+ "Type info built.");
+
+ // Close the result set/statement.
+
+ Reference< XCloseable> xClose(xRs,UNO_QUERY);
+ xClose->close();
+
+ SAL_INFO("connectivity.firebird", "buildTypeInfo(). "
+ "Closed.");
+}
+
+void Connection::disposing()
+{
+ MutexGuard aGuard(m_aMutex);
+
+ disposeStatements();
+
+ m_xMetaData = css::uno::WeakReference< css::sdbc::XDatabaseMetaData>();
+
+ ISC_STATUS_ARRAY status; /* status vector */
+ if (m_aTransactionHandle)
+ {
+ // TODO: confirm whether we need to ask the user here.
+ isc_rollback_transaction(status, &m_aTransactionHandle);
+ }
+
+ if (m_aDBHandle)
+ {
+ if (isc_detach_database(status, &m_aDBHandle))
+ {
+ evaluateStatusVector(status, u"isc_detach_database", *this);
+ }
+ }
+ // TODO: write to storage again?
+
+ cppu::WeakComponentImplHelperBase::disposing();
+
+ m_pDatabaseFileDir.reset();
+}
+
+void Connection::disposeStatements()
+{
+ MutexGuard aGuard(m_aMutex);
+ for (auto const& statement : m_aStatements)
+ {
+ Reference< XComponent > xComp(statement.get(), UNO_QUERY);
+ if (xComp.is())
+ xComp->dispose();
+ }
+ m_aStatements.clear();
+}
+
+uno::Reference< XTablesSupplier > Connection::createCatalog()
+{
+ MutexGuard aGuard(m_aMutex);
+
+ // m_xCatalog is a weak reference. Reuse it if it still exists.
+ Reference< XTablesSupplier > xCatalog = m_xCatalog;
+ if (xCatalog.is())
+ {
+ return xCatalog;
+ }
+ else
+ {
+ xCatalog = new Catalog(this);
+ m_xCatalog = xCatalog;
+ return m_xCatalog;
+ }
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/connectivity/source/drivers/firebird/Connection.hxx b/connectivity/source/drivers/firebird/Connection.hxx
new file mode 100644
index 0000000000..fa896439c9
--- /dev/null
+++ b/connectivity/source/drivers/firebird/Connection.hxx
@@ -0,0 +1,247 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <ibase.h>
+
+#include <connectivity/CommonTools.hxx>
+#include <cppuhelper/compbase.hxx>
+#include <cppuhelper/weakref.hxx>
+#include <memory>
+#include <OTypeInfo.hxx>
+#include <unotools/tempfile.hxx>
+
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/document/DocumentEvent.hpp>
+#include <com/sun/star/document/XDocumentEventListener.hpp>
+#include <com/sun/star/embed/XStorage.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/lang/XUnoTunnel.hpp>
+#include <com/sun/star/sdbc/XBlob.hpp>
+#include <com/sun/star/sdbc/XClob.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <com/sun/star/sdbc/XWarningsSupplier.hpp>
+#include <com/sun/star/sdbcx/XTablesSupplier.hpp>
+#include <com/sun/star/util/XModifiable.hpp>
+
+namespace connectivity::firebird
+ {
+
+ typedef ::cppu::WeakComponentImplHelper< css::document::XDocumentEventListener,
+ css::lang::XServiceInfo,
+ css::lang::XUnoTunnel,
+ css::sdbc::XConnection,
+ css::sdbc::XWarningsSupplier
+ > Connection_BASE;
+
+ class OStatementCommonBase;
+ class FirebirdDriver;
+ class ODatabaseMetaData;
+
+
+ typedef std::vector< ::connectivity::OTypeInfo> TTypeInfoVector;
+ typedef std::vector< css::uno::WeakReferenceHelper > OWeakRefArray;
+
+ class Connection final : public Connection_BASE
+ {
+ ::osl::Mutex m_aMutex;
+
+ TTypeInfoVector m_aTypeInfo; // vector containing an entry
+ // for each row returned by
+ // DatabaseMetaData.getTypeInfo.
+
+ /** The URL passed to us when opening, i.e. of the form sdbc:* */
+ OUString m_sConnectionURL;
+ /**
+ * The URL passed to firebird, i.e. either a local file (for a
+ * temporary .fdb extracted from a .odb or a normal local file) or
+ * a remote url.
+ */
+ OUString m_sFirebirdURL;
+
+ /* EMBEDDED MODE DATA */
+ /** Denotes that we have a database stored within a .odb file. */
+ bool m_bIsEmbedded;
+
+ /**
+ * Handle for the parent DatabaseDocument. We need to notify this
+ * whenever any data is written to our temporary database so that
+ * the user is able to save this back to the .odb file.
+ *
+ * Note that this is ONLY set in embedded mode.
+ */
+ css::uno::Reference< css::util::XModifiable >
+ m_xParentDocument;
+
+ /**
+ * Handle for the folder within the .odb where we store our .fbk
+ * (Only used if m_bIsEmbedded is true).
+ */
+ css::uno::Reference< css::embed::XStorage >
+ m_xEmbeddedStorage;
+ /**
+ * The temporary folder where we extract the .fbk from a .odb,
+ * and also store the temporary .fdb
+ * It is only valid if m_bIsEmbedded is true.
+ *
+ * The extracted .fbk is written in firebird.fbk, the temporary
+ * .fdb is stored as firebird.fdb.
+ */
+ std::unique_ptr< ::utl::TempFileNamed > m_pDatabaseFileDir;
+ /**
+ * Path for our extracted .fbk file.
+ *
+ * (The temporary .fdb is our m_sFirebirdURL.)
+ */
+ OUString m_sFBKPath;
+
+ void loadDatabaseFile(const OUString& pSrcLocation, const OUString& pTmpLocation);
+
+ /**
+ * Run the backup service, use nAction =
+ * isc_action_svc_backup to backup, nAction = isc_action_svc_restore
+ * to restore.
+ */
+ void runBackupService(const short nAction);
+
+ isc_svc_handle attachServiceManager();
+
+ void detachServiceManager(isc_svc_handle pServiceHandle);
+
+ /** We are using an external (local) file */
+ bool m_bIsFile;
+
+ /* CONNECTION PROPERTIES */
+ bool m_bIsAutoCommit;
+ bool m_bIsReadOnly;
+ sal_Int32 m_aTransactionIsolation;
+
+ isc_db_handle m_aDBHandle;
+ isc_tr_handle m_aTransactionHandle;
+
+ css::uno::WeakReference< css::sdbcx::XTablesSupplier>
+ m_xCatalog;
+ css::uno::WeakReference< css::sdbc::XDatabaseMetaData >
+ m_xMetaData;
+ /** Statements owned by this connection. */
+ OWeakRefArray m_aStatements;
+
+ /// @throws css::sdbc::SQLException
+ void buildTypeInfo();
+
+ /**
+ * Creates a new transaction with the desired parameters, if
+ * necessary discarding an existing transaction. This has to be done
+ * anytime we change the transaction isolation, or autocommitting.
+ *
+ * @throws css::sdbc::SQLException
+ */
+ void setupTransaction();
+ void disposeStatements();
+
+ public:
+ explicit Connection();
+ virtual ~Connection() override;
+
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void construct( const OUString& url,
+ const css::uno::Sequence< css::beans::PropertyValue >& info);
+
+ const OUString& getConnectionURL() const {return m_sConnectionURL;}
+ bool isEmbedded() const {return m_bIsEmbedded;}
+ isc_db_handle& getDBHandle() {return m_aDBHandle;}
+ /// @throws css::sdbc::SQLException
+ isc_tr_handle& getTransaction();
+
+ /**
+ * Must be called anytime the underlying database is likely to have
+ * changed.
+ *
+ * This is used to notify the database document of any changes, so
+ * that the user is informed of any pending changes needing to be
+ * saved.
+ */
+ void notifyDatabaseModified();
+
+ /**
+ * Create a new Blob tied to this connection. Blobs are tied to a
+ * transaction and not to a statement, hence the connection should
+ * deal with their management.
+ *
+ * @throws css::sdbc::SQLException
+ * @throws css::uno::RuntimeException
+ */
+ css::uno::Reference< css::sdbc::XBlob>
+ createBlob(ISC_QUAD const * pBlobID);
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ css::uno::Reference< css::sdbc::XClob>
+ createClob(ISC_QUAD const * pBlobID);
+
+ /**
+ * Create and/or connect to the sdbcx Catalog. This is completely
+ * unrelated to the SQL "Catalog".
+ */
+ css::uno::Reference< css::sdbcx::XTablesSupplier >
+ createCatalog();
+
+ // OComponentHelper
+ virtual void SAL_CALL disposing() override;
+
+ // XServiceInfo
+ DECLARE_SERVICE_INFO();
+ // XUnoTunnel
+ virtual sal_Int64 SAL_CALL getSomething(const css::uno::Sequence<sal_Int8>& rId) override;
+ static const css::uno::Sequence<sal_Int8> & getUnoTunnelId();
+ // XConnection
+ virtual css::uno::Reference< css::sdbc::XStatement > SAL_CALL createStatement( ) override;
+ virtual css::uno::Reference< css::sdbc::XPreparedStatement > SAL_CALL prepareStatement( const OUString& sql ) override;
+ virtual css::uno::Reference< css::sdbc::XPreparedStatement > SAL_CALL prepareCall( const OUString& sql ) override;
+ virtual OUString SAL_CALL nativeSQL( const OUString& sql ) override;
+ virtual void SAL_CALL setAutoCommit( sal_Bool autoCommit ) override;
+ virtual sal_Bool SAL_CALL getAutoCommit( ) override;
+ virtual void SAL_CALL commit( ) override;
+ virtual void SAL_CALL rollback( ) override;
+ virtual sal_Bool SAL_CALL isClosed( ) override;
+ virtual css::uno::Reference< css::sdbc::XDatabaseMetaData > SAL_CALL getMetaData( ) override;
+ virtual void SAL_CALL setReadOnly( sal_Bool readOnly ) override;
+ virtual sal_Bool SAL_CALL isReadOnly( ) override;
+ virtual void SAL_CALL setCatalog( const OUString& catalog ) override;
+ virtual OUString SAL_CALL getCatalog( ) override;
+ virtual void SAL_CALL setTransactionIsolation( sal_Int32 level ) override;
+ virtual sal_Int32 SAL_CALL getTransactionIsolation( ) override;
+ virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getTypeMap( ) override;
+ virtual void SAL_CALL setTypeMap( const css::uno::Reference< css::container::XNameAccess >& typeMap ) override;
+ // XCloseable
+ virtual void SAL_CALL close( ) override;
+ // XWarningsSupplier
+ virtual css::uno::Any SAL_CALL getWarnings( ) override;
+ virtual void SAL_CALL clearWarnings( ) override;
+ // XDocumentEventListener
+ virtual void SAL_CALL documentEventOccured( const css::document::DocumentEvent& Event ) override;
+ // css.lang.XEventListener
+ virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override;
+
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/connectivity/source/drivers/firebird/DatabaseMetaData.cxx b/connectivity/source/drivers/firebird/DatabaseMetaData.cxx
new file mode 100644
index 0000000000..37c2ffe72c
--- /dev/null
+++ b/connectivity/source/drivers/firebird/DatabaseMetaData.cxx
@@ -0,0 +1,1803 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "DatabaseMetaData.hxx"
+#include "Util.hxx"
+
+#include <ibase.h>
+#include <rtl/ustrbuf.hxx>
+#include <sal/log.hxx>
+#include <FDatabaseMetaDataResultSet.hxx>
+
+#include <com/sun/star/sdbc/ColumnSearch.hpp>
+#include <com/sun/star/sdbc/ColumnValue.hpp>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <com/sun/star/sdbc/IndexType.hpp>
+#include <com/sun/star/sdbc/ResultSetType.hpp>
+#include <com/sun/star/sdbc/ResultSetConcurrency.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <com/sun/star/sdbc/TransactionIsolation.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/KeyRule.hpp>
+#include <com/sun/star/sdbc/Deferrability.hpp>
+
+using namespace connectivity::firebird;
+using namespace com::sun::star;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::sdbc;
+
+ODatabaseMetaData::ODatabaseMetaData(Connection* _pCon)
+: m_pConnection(_pCon)
+{
+ SAL_WARN_IF(!m_pConnection.is(), "connectivity.firebird",
+ "ODatabaseMetaData::ODatabaseMetaData: No connection set!");
+}
+
+ODatabaseMetaData::~ODatabaseMetaData()
+{
+}
+
+//----- Catalog Info -- UNSUPPORTED -------------------------------------------
+OUString SAL_CALL ODatabaseMetaData::getCatalogSeparator()
+{
+ return OUString();
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxCatalogNameLength()
+{
+ return -1;
+}
+
+OUString SAL_CALL ODatabaseMetaData::getCatalogTerm()
+{
+ return OUString();
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::isCatalogAtStart()
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsCatalogsInTableDefinitions()
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsCatalogsInIndexDefinitions()
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsCatalogsInDataManipulation( )
+{
+ return false;
+}
+
+uno::Reference< XResultSet > SAL_CALL ODatabaseMetaData::getCatalogs()
+{
+ OSL_FAIL("Not implemented yet!");
+ // TODO implement
+ return new ODatabaseMetaDataResultSet(ODatabaseMetaDataResultSet::eCatalogs);
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsCatalogsInProcedureCalls()
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsCatalogsInPrivilegeDefinitions()
+{
+ return false;
+}
+
+//----- Schema Info -- UNSUPPORTED --------------------------------------------
+sal_Bool SAL_CALL ODatabaseMetaData::supportsSchemasInProcedureCalls()
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsSchemasInPrivilegeDefinitions()
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsSchemasInDataManipulation()
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsSchemasInIndexDefinitions()
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsSchemasInTableDefinitions()
+{
+ return false;
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxSchemaNameLength()
+{
+ return -1;
+}
+
+OUString SAL_CALL ODatabaseMetaData::getSchemaTerm()
+{
+ return OUString();
+}
+
+uno::Reference< XResultSet > SAL_CALL ODatabaseMetaData::getSchemas()
+{
+ OSL_FAIL("Not implemented yet!");
+ // TODO implement
+ return new ODatabaseMetaDataResultSet(ODatabaseMetaDataResultSet::eSchemas);
+}
+
+//----- Max Sizes/Lengths -----------------------------------------------------
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxBinaryLiteralLength()
+{
+ return 32767;
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxRowSize()
+{
+ return 32767;
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxCharLiteralLength()
+{
+ return 32767;
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxColumnNameLength()
+{
+ return 31;
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxColumnsInIndex()
+{
+ // TODO: No idea.
+ // See: http://www.firebirdsql.org/en/firebird-technical-specifications/
+ return 16;
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxCursorNameLength()
+{
+ return 32;
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxConnections()
+{
+ return 100; // Arbitrary
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxColumnsInTable()
+{
+ // May however be smaller.
+ // See: http://www.firebirdsql.org/en/firebird-technical-specifications/
+ return 32767;
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxStatementLength()
+{
+ return 32767;
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxTableNameLength()
+{
+ return 31;
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxTablesInSelect( )
+{
+ return 0; // 0 means no limit
+}
+
+
+sal_Bool SAL_CALL ODatabaseMetaData::doesMaxRowSizeIncludeBlobs( )
+{
+ return false;
+}
+
+// ---- Identifiers -----------------------------------------------------------
+// Only quoted identifiers are case sensitive, unquoted are case insensitive
+OUString SAL_CALL ODatabaseMetaData::getIdentifierQuoteString()
+{
+ return "\"";
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsMixedCaseQuotedIdentifiers( )
+{
+ return true;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::storesLowerCaseQuotedIdentifiers()
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::storesMixedCaseQuotedIdentifiers()
+{
+ // TODO: confirm this -- the documentation is highly ambiguous
+ // However it seems this should be true as quoted identifiers ARE
+ // stored mixed case.
+ return true;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::storesUpperCaseQuotedIdentifiers()
+{
+ return false;
+}
+
+// ---- Unquoted Identifiers -------------------------------------------------
+// All unquoted identifiers are stored upper case.
+sal_Bool SAL_CALL ODatabaseMetaData::supportsMixedCaseIdentifiers()
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::storesLowerCaseIdentifiers()
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::storesMixedCaseIdentifiers()
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::storesUpperCaseIdentifiers()
+{
+ return true;
+}
+
+// ---- SQL Feature Support ---------------------------------------------------
+sal_Bool SAL_CALL ODatabaseMetaData::supportsCoreSQLGrammar()
+{
+ return true;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsMinimumSQLGrammar()
+{
+ return true;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsAlterTableWithAddColumn()
+{
+ return true;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsAlterTableWithDropColumn()
+{
+ return true;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsPositionedDelete()
+{
+ return true;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsPositionedUpdate()
+{
+ return true;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsOuterJoins()
+{
+ return true;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsSelectForUpdate()
+{
+ return true;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::allTablesAreSelectable()
+{
+ // TODO: true if embedded, but unsure about remote server
+ return true;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsConvert(sal_Int32,
+ sal_Int32)
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsTypeConversion()
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsColumnAliasing()
+{
+ return true;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsTableCorrelationNames()
+{
+ return true;
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxIndexLength( )
+{
+ return 0; // 0 means no limit
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsNonNullableColumns( )
+{
+ return true;
+}
+
+OUString SAL_CALL ODatabaseMetaData::getExtraNameCharacters( )
+{
+ return OUString();
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsDifferentTableCorrelationNames( )
+{
+ return false;
+}
+// ---- Data definition stuff -------------------------------------------------
+sal_Bool SAL_CALL ODatabaseMetaData::dataDefinitionIgnoredInTransactions()
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::dataDefinitionCausesTransactionCommit()
+{
+ return true;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsDataManipulationTransactionsOnly()
+{
+ return true;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::
+ supportsDataDefinitionAndDataManipulationTransactions()
+{
+ return false;
+}
+//----- Transaction Support --------------------------------------------------
+sal_Bool SAL_CALL ODatabaseMetaData::supportsTransactions()
+{
+ return true;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsOpenStatementsAcrossRollback()
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsOpenStatementsAcrossCommit()
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsOpenCursorsAcrossCommit()
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsOpenCursorsAcrossRollback()
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsMultipleTransactions()
+{
+ return true;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsTransactionIsolationLevel(
+ sal_Int32 aLevel)
+{
+ return aLevel == TransactionIsolation::READ_UNCOMMITTED
+ || aLevel == TransactionIsolation::READ_COMMITTED
+ || aLevel == TransactionIsolation::REPEATABLE_READ
+ || aLevel == TransactionIsolation::SERIALIZABLE;
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getDefaultTransactionIsolation()
+{
+ return TransactionIsolation::REPEATABLE_READ;
+}
+
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsANSI92FullSQL( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsANSI92EntryLevelSQL( )
+{
+ return true; // should be supported at least
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsIntegrityEnhancementFacility( )
+{
+ return true;
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxStatements( )
+{
+ return 0; // 0 means no limit
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxProcedureNameLength( )
+{
+ return 31; // TODO: confirm
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::allProceduresAreCallable( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsStoredProcedures( )
+{
+ return true;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::isReadOnly( )
+{
+ return m_pConnection->isReadOnly();
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::usesLocalFiles( )
+{
+ return m_pConnection->isEmbedded();
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::usesLocalFilePerTable( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::nullPlusNonNullIsNull( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsExpressionsInOrderBy( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsGroupBy( )
+{
+ return true;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsGroupByBeyondSelect( )
+{
+ // Unsure
+ return true;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsGroupByUnrelated( )
+{
+ // Unsure
+ return false;
+}
+
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsMultipleResultSets( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsLikeEscapeClause( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsOrderByUnrelated( )
+{
+ return true;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsUnion( )
+{
+ return true;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsUnionAll( )
+{
+ return true;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::nullsAreSortedAtEnd( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::nullsAreSortedAtStart( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::nullsAreSortedHigh( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::nullsAreSortedLow( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsCorrelatedSubqueries( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsSubqueriesInComparisons( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsSubqueriesInExists( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsSubqueriesInIns( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsSubqueriesInQuantifieds( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsANSI92IntermediateSQL( )
+{
+ return false;
+}
+
+OUString SAL_CALL ODatabaseMetaData::getURL()
+{
+ return m_pConnection->getConnectionURL();
+}
+
+OUString SAL_CALL ODatabaseMetaData::getUserName( )
+{
+ return OUString();
+}
+
+OUString SAL_CALL ODatabaseMetaData::getDriverName( )
+{
+ return OUString();
+}
+
+OUString SAL_CALL ODatabaseMetaData::getDriverVersion()
+{
+ return OUString();
+}
+
+OUString SAL_CALL ODatabaseMetaData::getDatabaseProductVersion( )
+{
+ uno::Reference< XStatement > xSelect = m_pConnection->createStatement();
+
+ uno::Reference< XResultSet > xRs = xSelect->executeQuery("SELECT rdb$get_context('SYSTEM', 'ENGINE_VERSION') as version from rdb$database");
+ (void)xRs->next(); // first and only row
+ uno::Reference< XRow > xRow( xRs, UNO_QUERY_THROW );
+ return xRow->getString(1);
+}
+
+OUString SAL_CALL ODatabaseMetaData::getDatabaseProductName( )
+{
+ return "Firebird (engine12)";
+}
+
+OUString SAL_CALL ODatabaseMetaData::getProcedureTerm( )
+{
+ return OUString();
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getDriverMajorVersion( )
+{
+ return 1;
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getDriverMinorVersion( )
+{
+ return 0;
+}
+
+OUString SAL_CALL ODatabaseMetaData::getSQLKeywords( )
+{
+ return OUString();
+}
+
+OUString SAL_CALL ODatabaseMetaData::getSearchStringEscape( )
+{
+ return OUString();
+}
+
+OUString SAL_CALL ODatabaseMetaData::getStringFunctions( )
+{
+ return "ASCII_CHAR,ASCII_VAL,BIT_LENGTH,CHAR_LENGTH,CHAR_TO_UUID,CHARACTER_LENGTH,"
+ "GEN_UUID,HASH,LEFT,LOWER,LPAD,OCTET_LENGTH,OVERLAY,POSITION,REPLACE,REVERSE,"
+ "RIGHT,RPAD,SUBSTRING,TRIM,UPPER,UUID_TO_CHAR";
+}
+
+OUString SAL_CALL ODatabaseMetaData::getTimeDateFunctions( )
+{
+ return "CURRENT_DATE,CURRENT_TIME,CURRENT_TIMESTAMP,DATEADD, DATEDIFF,"
+ "EXTRACT,'NOW','TODAY','TOMORROW','YESTERDAY'";
+}
+
+OUString SAL_CALL ODatabaseMetaData::getSystemFunctions( )
+{
+ return OUString();
+}
+
+OUString SAL_CALL ODatabaseMetaData::getNumericFunctions( )
+{
+ return "ABS,ACOS,ASIN,ATAN,ATAN2,BIN_AND,BIN_NOT,BIN_OR,BIN_SHL,"
+ "BIN_SHR,BIN_XOR,CEIL,CEILING,COS,COSH,COT,EXP,FLOOR,LN,"
+ "LOG,LOG10,MOD,PI,POWER,RAND,ROUND,SIGN,SIN,SINH,SQRT,TAN,TANH,TRUNC";
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsExtendedSQLGrammar( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsFullOuterJoins( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsLimitedOuterJoins( )
+{
+ return false;
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxColumnsInGroupBy( )
+{
+ return 0; // 0 means no limit
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxColumnsInOrderBy( )
+{
+ return 0; // 0 means no limit
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxColumnsInSelect( )
+{
+ return 0; // 0 means no limit
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxUserNameLength( )
+{
+ return 31;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsResultSetType(sal_Int32 setType)
+{
+ switch (setType)
+ {
+ case ResultSetType::FORWARD_ONLY:
+ return true;
+ default:
+ return false;
+ }
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsResultSetConcurrency(
+ sal_Int32 aResultSetType,
+ sal_Int32 aConcurrency)
+{
+ if (aResultSetType == ResultSetType::FORWARD_ONLY
+ && aConcurrency == ResultSetConcurrency::READ_ONLY)
+ return true;
+ else
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::ownUpdatesAreVisible( sal_Int32 )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::ownDeletesAreVisible( sal_Int32 )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::ownInsertsAreVisible( sal_Int32 )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::othersUpdatesAreVisible( sal_Int32 )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::othersDeletesAreVisible( sal_Int32 )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::othersInsertsAreVisible( sal_Int32 )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::updatesAreDetected( sal_Int32 )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::deletesAreDetected( sal_Int32 )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::insertsAreDetected( sal_Int32 )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsBatchUpdates()
+{
+ // No batch support in firebird
+ return false;
+}
+
+uno::Reference< XConnection > SAL_CALL ODatabaseMetaData::getConnection()
+{
+ return m_pConnection;
+}
+
+// here follow all methods which return a resultset
+// the first methods is an example implementation how to use this resultset
+// of course you could implement it on your and you should do this because
+// the general way is more memory expensive
+
+uno::Reference< XResultSet > SAL_CALL ODatabaseMetaData::getTableTypes( )
+{
+ rtl::Reference<ODatabaseMetaDataResultSet> pResultSet = new
+ ODatabaseMetaDataResultSet(ODatabaseMetaDataResultSet::eTableTypes);
+
+ ODatabaseMetaDataResultSet::ORows aResults;
+ ODatabaseMetaDataResultSet::ORow aRow(2);
+
+ aRow[0] = new ORowSetValueDecorator(); // unused
+
+ // TODO Put these statics to one place
+ // like postgreSQL's Statics class.
+
+ aRow[1] = new ORowSetValueDecorator(OUString("TABLE"));
+ aResults.push_back(aRow);
+
+ aRow[1] = new ORowSetValueDecorator(OUString("VIEW"));
+ aResults.push_back(aRow);
+
+ aRow[1] = new ORowSetValueDecorator(OUString("SYSTEM TABLE"));
+ aResults.push_back(aRow);
+
+ pResultSet->setRows(std::move(aResults));
+ return pResultSet;
+}
+
+uno::Reference< XResultSet > SAL_CALL ODatabaseMetaData::getTypeInfo()
+{
+ SAL_INFO("connectivity.firebird", "getTypeInfo()");
+
+ // this returns an empty resultset where the column-names are already set
+ // in special the metadata of the resultset already returns the right columns
+ rtl::Reference<ODatabaseMetaDataResultSet> pResultSet =
+ new ODatabaseMetaDataResultSet(ODatabaseMetaDataResultSet::eTypeInfo);
+ static ODatabaseMetaDataResultSet::ORows aResults = []()
+ {
+ ODatabaseMetaDataResultSet::ORows tmp;
+ ODatabaseMetaDataResultSet::ORow aRow(19);
+
+ // Common data
+ aRow[4] = ODatabaseMetaDataResultSet::getQuoteValue(); // Literal quote marks
+ aRow[5] = ODatabaseMetaDataResultSet::getQuoteValue(); // Literal quote marks
+ aRow[7] = new ORowSetValueDecorator(ORowSetValue(true)); // Nullable
+ aRow[8] = new ORowSetValueDecorator(ORowSetValue(true)); // Case sensitive
+ aRow[10] = new ORowSetValueDecorator(ORowSetValue(false)); // Is unsigned
+ // FIXED_PREC_SCALE: docs state "can it be a money value? " however
+ // in reality this causes Base to treat all numbers as money formatted
+ // by default which is wrong (and formatting as money value is still
+ // possible for all values).
+ aRow[11] = new ORowSetValueDecorator(ORowSetValue(false));
+ // Localised Type Name -- TODO: implement (but can be null):
+ aRow[13] = new ORowSetValueDecorator();
+ aRow[16] = new ORowSetValueDecorator(); // Unused
+ aRow[17] = new ORowSetValueDecorator(); // Unused
+ aRow[18] = new ORowSetValueDecorator(sal_Int16(10));// Radix
+
+ // Char
+ aRow[1] = new ORowSetValueDecorator(OUString("CHAR"));
+ aRow[2] = new ORowSetValueDecorator(DataType::CHAR);
+ aRow[3] = new ORowSetValueDecorator(sal_Int16(32765)); // Prevision = max length
+ aRow[6] = new ORowSetValueDecorator(OUString("length")); // Create Params
+ aRow[9] = new ORowSetValueDecorator(
+ sal_Int16(ColumnSearch::FULL)); // Searchable
+ aRow[12] = new ORowSetValueDecorator(ORowSetValue(false)); // Autoincrement
+ aRow[14] = ODatabaseMetaDataResultSet::get0Value(); // Minimum scale
+ aRow[15] = ODatabaseMetaDataResultSet::get0Value(); // Max scale
+ tmp.push_back(aRow);
+
+ // Varchar
+ aRow[1] = new ORowSetValueDecorator(OUString("VARCHAR"));
+ aRow[2] = new ORowSetValueDecorator(DataType::VARCHAR);
+ aRow[3] = new ORowSetValueDecorator(sal_Int16(32765)); // Prevision = max length
+ aRow[6] = new ORowSetValueDecorator(OUString("length")); // Create Params
+ aRow[9] = new ORowSetValueDecorator(
+ sal_Int16(ColumnSearch::FULL)); // Searchable
+ aRow[12] = new ORowSetValueDecorator(ORowSetValue(false)); // Autoincrement
+ aRow[14] = ODatabaseMetaDataResultSet::get0Value(); // Minimum scale
+ aRow[15] = ODatabaseMetaDataResultSet::get0Value(); // Max scale
+ tmp.push_back(aRow);
+
+ // Binary (CHAR); we use the Firebird synonym CHARACTER
+ // to fool LO into seeing it as different types.
+ // It is distinguished from Text type by its character set OCTETS;
+ // that will be added by Tables::createStandardColumnPart
+ aRow[1] = new ORowSetValueDecorator(OUString("CHARACTER"));
+ aRow[2] = new ORowSetValueDecorator(DataType::BINARY);
+ aRow[3] = new ORowSetValueDecorator(sal_Int16(32765)); // Prevision = max length
+ aRow[6] = new ORowSetValueDecorator(OUString("length")); // Create Params
+ aRow[9] = new ORowSetValueDecorator(
+ sal_Int16(ColumnSearch::NONE)); // Searchable
+ aRow[14] = ODatabaseMetaDataResultSet::get0Value(); // Minimum scale
+ aRow[15] = ODatabaseMetaDataResultSet::get0Value(); // Max scale
+ tmp.push_back(aRow);
+
+ // Varbinary (VARCHAR); see comment above about BINARY
+ aRow[1] = new ORowSetValueDecorator(OUString("CHARACTER VARYING"));
+ aRow[2] = new ORowSetValueDecorator(DataType::VARBINARY);
+ aRow[3] = new ORowSetValueDecorator(sal_Int16(32765)); // Prevision = max length
+ aRow[6] = new ORowSetValueDecorator(OUString("length")); // Create Params
+ aRow[9] = new ORowSetValueDecorator(
+ sal_Int16(ColumnSearch::NONE)); // Searchable
+
+ // Clob (SQL_BLOB)
+ aRow[1] = new ORowSetValueDecorator(OUString("BLOB SUB_TYPE TEXT")); // BLOB, with subtype 1
+ aRow[2] = new ORowSetValueDecorator(DataType::CLOB);
+ aRow[3] = new ORowSetValueDecorator(sal_Int32(2147483647)); // Precision = max length
+ aRow[6] = new ORowSetValueDecorator(); // Create Params
+ aRow[9] = new ORowSetValueDecorator(
+ sal_Int16(ColumnSearch::FULL)); // Searchable
+ aRow[12] = new ORowSetValueDecorator(ORowSetValue(false)); // Autoincrement
+ aRow[14] = ODatabaseMetaDataResultSet::get0Value(); // Minimum scale
+ aRow[15] = ODatabaseMetaDataResultSet::get0Value(); // Max scale
+ tmp.push_back(aRow);
+
+ // Longvarbinary (SQL_BLOB)
+ // Distinguished from simple blob with a user-defined subtype.
+ aRow[1] = new ORowSetValueDecorator(OUString("BLOB SUB_TYPE " + OUString::number(static_cast<short>(BlobSubtype::Image))) ); // BLOB, with subtype 0
+ aRow[2] = new ORowSetValueDecorator(DataType::LONGVARBINARY);
+ tmp.push_back(aRow);
+
+ // Integer Types common
+ {
+ aRow[6] = new ORowSetValueDecorator(); // Create Params
+ aRow[9] = new ORowSetValueDecorator(
+ sal_Int16(ColumnSearch::FULL)); // Searchable
+ aRow[12] = new ORowSetValueDecorator(ORowSetValue(true)); // Autoincrement
+ aRow[14] = ODatabaseMetaDataResultSet::get0Value(); // Minimum scale
+ aRow[15] = ODatabaseMetaDataResultSet::get0Value(); // Max scale
+ }
+ // Smallint (SQL_SHORT)
+ aRow[1] = new ORowSetValueDecorator(OUString("SMALLINT"));
+ aRow[2] = new ORowSetValueDecorator(DataType::SMALLINT);
+ aRow[3] = new ORowSetValueDecorator(sal_Int16(5)); // Prevision
+ tmp.push_back(aRow);
+ // Integer (SQL_LONG)
+ aRow[1] = new ORowSetValueDecorator(OUString("INTEGER"));
+ aRow[2] = new ORowSetValueDecorator(DataType::INTEGER);
+ aRow[3] = new ORowSetValueDecorator(sal_Int16(10)); // Precision
+ tmp.push_back(aRow);
+ // Bigint (SQL_INT64)
+ aRow[1] = new ORowSetValueDecorator(OUString("BIGINT"));
+ aRow[2] = new ORowSetValueDecorator(DataType::BIGINT);
+ aRow[3] = new ORowSetValueDecorator(sal_Int16(20)); // Precision
+ tmp.push_back(aRow);
+
+ // Decimal Types common
+ {
+ aRow[9] = new ORowSetValueDecorator(
+ sal_Int16(ColumnSearch::FULL)); // Searchable
+ aRow[12] = new ORowSetValueDecorator(ORowSetValue(true)); // Autoincrement
+ }
+
+ aRow[6] = new ORowSetValueDecorator(OUString("PRECISION,SCALE")); // Create params
+ // Numeric
+ aRow[1] = new ORowSetValueDecorator(OUString("NUMERIC"));
+ aRow[2] = new ORowSetValueDecorator(DataType::NUMERIC);
+ aRow[3] = new ORowSetValueDecorator(sal_Int16(18)); // Precision
+ aRow[14] = new ORowSetValueDecorator(sal_Int16(0)); // Minimum scale
+ aRow[15] = new ORowSetValueDecorator(sal_Int16(18)); // Max scale
+ tmp.push_back(aRow);
+ // Decimal
+ aRow[1] = new ORowSetValueDecorator(OUString("DECIMAL"));
+ aRow[2] = new ORowSetValueDecorator(DataType::DECIMAL);
+ aRow[3] = new ORowSetValueDecorator(sal_Int16(18)); // Precision
+ aRow[14] = new ORowSetValueDecorator(sal_Int16(0)); // Minimum scale
+ aRow[15] = new ORowSetValueDecorator(sal_Int16(18)); // Max scale
+ tmp.push_back(aRow);
+
+ aRow[6] = new ORowSetValueDecorator(); // Create Params
+ // Float (SQL_FLOAT)
+ aRow[1] = new ORowSetValueDecorator(OUString("FLOAT"));
+ aRow[2] = new ORowSetValueDecorator(DataType::FLOAT);
+ aRow[3] = new ORowSetValueDecorator(sal_Int16(7)); // Precision
+ aRow[14] = new ORowSetValueDecorator(sal_Int16(1)); // Minimum scale
+ aRow[15] = new ORowSetValueDecorator(sal_Int16(7)); // Max scale
+ tmp.push_back(aRow);
+ // Double (SQL_DOUBLE)
+ aRow[1] = new ORowSetValueDecorator(OUString("DOUBLE PRECISION"));
+ aRow[2] = new ORowSetValueDecorator(DataType::DOUBLE);
+ aRow[3] = new ORowSetValueDecorator(sal_Int16(15)); // Precision
+ aRow[14] = new ORowSetValueDecorator(sal_Int16(1)); // Minimum scale
+ aRow[15] = new ORowSetValueDecorator(sal_Int16(15)); // Max scale
+ tmp.push_back(aRow);
+
+ // TODO: no idea whether D_FLOAT corresponds to an sql type
+
+ // SQL_TIMESTAMP
+ aRow[1] = new ORowSetValueDecorator(OUString("TIMESTAMP"));
+ aRow[2] = new ORowSetValueDecorator(DataType::TIMESTAMP);
+ aRow[3] = new ORowSetValueDecorator(sal_Int32(8)); // Prevision = max length
+ aRow[6] = new ORowSetValueDecorator(); // Create Params
+ aRow[9] = new ORowSetValueDecorator(
+ sal_Int16(ColumnSearch::FULL)); // Searchable
+ aRow[12] = new ORowSetValueDecorator(ORowSetValue(false)); // Autoincrement
+ aRow[14] = ODatabaseMetaDataResultSet::get0Value(); // Minimum scale
+ aRow[15] = ODatabaseMetaDataResultSet::get0Value(); // Max scale
+ tmp.push_back(aRow);
+
+ // SQL_TYPE_TIME
+ aRow[1] = new ORowSetValueDecorator(OUString("TIME"));
+ aRow[2] = new ORowSetValueDecorator(DataType::TIME);
+ aRow[3] = new ORowSetValueDecorator(sal_Int32(8)); // Prevision = max length
+ aRow[6] = new ORowSetValueDecorator(); // Create Params
+ aRow[9] = new ORowSetValueDecorator(
+ sal_Int16(ColumnSearch::FULL)); // Searchable
+ aRow[12] = new ORowSetValueDecorator(ORowSetValue(false)); // Autoincrement
+ aRow[14] = ODatabaseMetaDataResultSet::get0Value(); // Minimum scale
+ aRow[15] = ODatabaseMetaDataResultSet::get0Value(); // Max scale
+ tmp.push_back(aRow);
+
+ // SQL_TYPE_DATE
+ aRow[1] = new ORowSetValueDecorator(OUString("DATE"));
+ aRow[2] = new ORowSetValueDecorator(DataType::DATE);
+ aRow[3] = new ORowSetValueDecorator(sal_Int32(8)); // Prevision = max length
+ aRow[6] = new ORowSetValueDecorator(); // Create Params
+ aRow[9] = new ORowSetValueDecorator(
+ sal_Int16(ColumnSearch::FULL)); // Searchable
+ aRow[12] = new ORowSetValueDecorator(ORowSetValue(false)); // Autoincrement
+ aRow[14] = ODatabaseMetaDataResultSet::get0Value(); // Minimum scale
+ aRow[15] = ODatabaseMetaDataResultSet::get0Value(); // Max scale
+ tmp.push_back(aRow);
+
+ // SQL_BLOB
+ aRow[1] = new ORowSetValueDecorator(OUString("BLOB SUB_TYPE BINARY"));
+ aRow[2] = new ORowSetValueDecorator(DataType::BLOB);
+ aRow[3] = new ORowSetValueDecorator(sal_Int32(0)); // Prevision = max length
+ aRow[6] = new ORowSetValueDecorator(); // Create Params
+ aRow[9] = new ORowSetValueDecorator(
+ sal_Int16(ColumnSearch::NONE)); // Searchable
+ aRow[12] = new ORowSetValueDecorator(ORowSetValue(false)); // Autoincrement
+ aRow[14] = ODatabaseMetaDataResultSet::get0Value(); // Minimum scale
+ aRow[15] = ODatabaseMetaDataResultSet::get0Value(); // Max scale
+ tmp.push_back(aRow);
+
+ // SQL_BOOLEAN
+ aRow[1] = new ORowSetValueDecorator(OUString("BOOLEAN"));
+ aRow[2] = new ORowSetValueDecorator(DataType::BOOLEAN);
+ aRow[3] = new ORowSetValueDecorator(sal_Int32(1)); // Prevision = max length
+ aRow[6] = new ORowSetValueDecorator(); // Create Params
+ aRow[9] = new ORowSetValueDecorator(
+ sal_Int16(ColumnSearch::BASIC)); // Searchable
+ aRow[12] = new ORowSetValueDecorator(ORowSetValue(false)); // Autoincrement
+ aRow[14] = ODatabaseMetaDataResultSet::get0Value(); // Minimum scale
+ aRow[15] = ODatabaseMetaDataResultSet::get0Value(); // Max scale
+ tmp.push_back(aRow);
+ return tmp;
+ }();
+ // [-loplugin:redundantfcast] false positive:
+ pResultSet->setRows(ODatabaseMetaDataResultSet::ORows(aResults));
+ return pResultSet;
+}
+
+uno::Reference< XResultSet > SAL_CALL ODatabaseMetaData::getColumnPrivileges(
+ const Any& /*aCatalog*/,
+ const OUString& /*sSchema*/,
+ const OUString& sTable,
+ const OUString& sColumnNamePattern)
+{
+ SAL_INFO("connectivity.firebird", "getColumnPrivileges() with "
+ "Table: " << sTable
+ << " & ColumnNamePattern: " << sColumnNamePattern);
+
+ rtl::Reference<ODatabaseMetaDataResultSet> pResultSet = new
+ ODatabaseMetaDataResultSet(ODatabaseMetaDataResultSet::eColumnPrivileges);
+ uno::Reference< XStatement > statement = m_pConnection->createStatement();
+
+ static const char wld[] = "%";
+ OUStringBuffer queryBuf(
+ "SELECT "
+ "priv.RDB$RELATION_NAME, " // 1 Table name
+ "priv.RDB$GRANTOR," // 2
+ "priv.RDB$USER, " // 3 Grantee
+ "priv.RDB$PRIVILEGE, " // 4
+ "priv.RDB$GRANT_OPTION, " // 5 is Grantable
+ "priv.RDB$FIELD_NAME " // 6 Column name
+ "FROM RDB$USER_PRIVILEGES priv ");
+
+ {
+ OUString sAppend = "WHERE priv.RDB$RELATION_NAME = '%' ";
+ queryBuf.append(sAppend.replaceAll("%", sTable));
+ }
+ if (!sColumnNamePattern.isEmpty())
+ {
+ OUString sAppend;
+ if (sColumnNamePattern.match(wld))
+ sAppend = "AND priv.RDB$FIELD_NAME LIKE '%' ";
+ else
+ sAppend = "AND priv.RDB$FIELD_NAME = '%' ";
+
+ queryBuf.append(sAppend.replaceAll(wld, sColumnNamePattern));
+ }
+
+ queryBuf.append(" ORDER BY priv.RDB$FIELD, "
+ "priv.RDB$PRIVILEGE");
+
+ OUString query = queryBuf.makeStringAndClear();
+
+ uno::Reference< XResultSet > rs = statement->executeQuery(query);
+ uno::Reference< XRow > xRow( rs, UNO_QUERY_THROW );
+ ODatabaseMetaDataResultSet::ORows aResults;
+
+ ODatabaseMetaDataResultSet::ORow aCurrentRow(9);
+ aCurrentRow[0] = new ORowSetValueDecorator(); // Unused
+ aCurrentRow[1] = new ORowSetValueDecorator(); // 1. TABLE_CAT Unsupported
+ aCurrentRow[2] = new ORowSetValueDecorator(); // 1. TABLE_SCHEM Unsupported
+
+ while( rs->next() )
+ {
+ // 3. TABLE_NAME
+ aCurrentRow[3] = new ORowSetValueDecorator(sanitizeIdentifier(xRow->getString(1)));
+ // 4. COLUMN_NAME
+ aCurrentRow[4] = new ORowSetValueDecorator(sanitizeIdentifier(xRow->getString(6)));
+ aCurrentRow[5] = new ORowSetValueDecorator(sanitizeIdentifier(xRow->getString(2))); // 5. GRANTOR
+ aCurrentRow[6] = new ORowSetValueDecorator(sanitizeIdentifier(xRow->getString(3))); // 6. GRANTEE
+ aCurrentRow[7] = new ORowSetValueDecorator(xRow->getString(4)); // 7. Privilege
+ aCurrentRow[8] = new ORowSetValueDecorator( ( xRow->getShort(5) == 1 ) ?
+ OUString("YES") : OUString("NO")); // 8. Grantable
+
+ aResults.push_back(aCurrentRow);
+ }
+
+ pResultSet->setRows( std::move(aResults) );
+
+ return pResultSet;
+}
+
+uno::Reference< XResultSet > SAL_CALL ODatabaseMetaData::getColumns(
+ const Any& /*catalog*/,
+ const OUString& /*schemaPattern*/,
+ const OUString& tableNamePattern,
+ const OUString& columnNamePattern)
+{
+ SAL_INFO("connectivity.firebird", "getColumns() with "
+ "TableNamePattern: " << tableNamePattern <<
+ " & ColumnNamePattern: " << columnNamePattern);
+
+ OUStringBuffer queryBuf("SELECT "
+ "relfields.RDB$RELATION_NAME, " // 1
+ "relfields.RDB$FIELD_NAME, " // 2
+ "relfields.RDB$DESCRIPTION," // 3
+ "relfields.RDB$DEFAULT_VALUE, " // 4
+ "relfields.RDB$FIELD_POSITION, "// 5
+ "fields.RDB$FIELD_TYPE, " // 6
+ "fields.RDB$FIELD_SUB_TYPE, " // 7
+ "fields.RDB$FIELD_LENGTH, " // 8
+ "fields.RDB$FIELD_PRECISION, " // 9
+ "fields.RDB$FIELD_SCALE, " // 10
+ // Specifically use relfields null flag -- the one in fields is used
+ // for domains, whether a specific field is nullable is set in relfields,
+ // this is also the one we manually fiddle when changing NULL/NOT NULL
+ // (see Table.cxx)
+ "relfields.RDB$NULL_FLAG, " // 11
+ "fields.RDB$CHARACTER_LENGTH, " // 12
+ "charset.RDB$CHARACTER_SET_NAME " // 13
+ "FROM RDB$RELATION_FIELDS relfields "
+ "JOIN RDB$FIELDS fields "
+ "on (fields.RDB$FIELD_NAME = relfields.RDB$FIELD_SOURCE) "
+ "LEFT JOIN RDB$CHARACTER_SETS charset "
+ "on (fields.RDB$CHARACTER_SET_ID = charset.RDB$CHARACTER_SET_ID) "
+ "WHERE (1 = 1) ");
+
+ if (!tableNamePattern.isEmpty())
+ {
+ OUString sAppend;
+ if (tableNamePattern.match("%"))
+ sAppend = "AND relfields.RDB$RELATION_NAME LIKE '%' ";
+ else
+ sAppend = "AND relfields.RDB$RELATION_NAME = '%' ";
+
+ queryBuf.append(sAppend.replaceAll("%", tableNamePattern));
+ }
+
+ if (!columnNamePattern.isEmpty())
+ {
+ OUString sAppend;
+ if (columnNamePattern.match("%"))
+ sAppend = "AND relfields.RDB$FIELD_NAME LIKE '%' ";
+ else
+ sAppend = "AND relfields.RDB$FIELD_NAME = '%' ";
+
+ queryBuf.append(sAppend.replaceAll("%", columnNamePattern));
+ }
+
+ OUString query = queryBuf.makeStringAndClear();
+
+ uno::Reference< XStatement > statement = m_pConnection->createStatement();
+ uno::Reference< XResultSet > rs = statement->executeQuery(query);
+ uno::Reference< XRow > xRow( rs, UNO_QUERY_THROW );
+
+ ODatabaseMetaDataResultSet::ORows aResults;
+ ODatabaseMetaDataResultSet::ORow aCurrentRow(19);
+
+ aCurrentRow[0] = new ORowSetValueDecorator(); // Unused -- numbering starts from 0
+ aCurrentRow[1] = new ORowSetValueDecorator(); // Catalog - can be null
+ aCurrentRow[2] = new ORowSetValueDecorator(); // Schema - can be null
+ aCurrentRow[8] = new ORowSetValueDecorator(); // Unused
+ aCurrentRow[10] = new ORowSetValueDecorator(sal_Int32(10)); // Radix: fixed in FB
+ aCurrentRow[14] = new ORowSetValueDecorator(); // Unused
+ aCurrentRow[15] = new ORowSetValueDecorator(); // Unused
+
+ while( rs->next() )
+ {
+ // 3. TABLE_NAME
+ aCurrentRow[3] = new ORowSetValueDecorator(sanitizeIdentifier(xRow->getString(1)));
+ // 4. Column Name
+ aCurrentRow[4] = new ORowSetValueDecorator(sanitizeIdentifier(xRow->getString(2)));
+ // 5. Datatype
+ short aType = getFBTypeFromBlrType(xRow->getShort(6));
+ short aScale = xRow->getShort(10);
+ OUString sCharsetName = xRow->getString(13);
+ // result field may be filled with spaces
+ sCharsetName = sCharsetName.trim();
+ ColumnTypeInfo aInfo(aType, xRow->getShort(7), aScale,
+ sCharsetName);
+
+ aCurrentRow[5] = new ORowSetValueDecorator(aInfo.getSdbcType());
+ // 6. Typename (SQL_*)
+ aCurrentRow[6] = new ORowSetValueDecorator(aInfo.getColumnTypeName());
+
+ // 7. Column Sizes
+ {
+ sal_Int32 aColumnSize = 0;
+ switch (aType)
+ {
+ case SQL_TEXT:
+ case SQL_VARYING:
+ aColumnSize = xRow->getShort(12);
+ break;
+ case SQL_SHORT:
+ case SQL_LONG:
+ case SQL_FLOAT:
+ case SQL_DOUBLE:
+ case SQL_D_FLOAT:
+ case SQL_INT64:
+ case SQL_QUAD:
+ aColumnSize = xRow->getShort(9);
+ break;
+ case SQL_TIMESTAMP:
+ case SQL_BLOB:
+ case SQL_ARRAY:
+ case SQL_TYPE_TIME:
+ case SQL_TYPE_DATE:
+ case SQL_NULL:
+ // TODO: implement.
+ break;
+ }
+ aCurrentRow[7] = new ORowSetValueDecorator(aColumnSize);
+ }
+
+ // 9. Decimal digits (scale)
+ // fb stores a negative number
+ aCurrentRow[9] = new ORowSetValueDecorator( static_cast<sal_Int16>(-aScale) );
+
+ // 11. Nullable
+ if (xRow->getShort(11))
+ {
+ aCurrentRow[11] = new ORowSetValueDecorator(ColumnValue::NO_NULLS);
+ }
+ else
+ {
+ aCurrentRow[11] = new ORowSetValueDecorator(ColumnValue::NULLABLE);
+ }
+ // 12. Comments -- may be omitted
+ {
+ OUString aDescription;
+ uno::Reference< XBlob > xBlob = xRow->getBlob(3);
+ if (xBlob.is())
+ {
+ const sal_Int64 aBlobLength = xBlob->length();
+ if (aBlobLength > SAL_MAX_INT32)
+ {
+ SAL_WARN("connectivity.firebird", "getBytes can't return " << aBlobLength << " bytes but only max " << SAL_MAX_INT32);
+ aDescription = OUString(reinterpret_cast<char*>(xBlob->getBytes(1, SAL_MAX_INT32).getArray()),
+ SAL_MAX_INT32,
+ RTL_TEXTENCODING_UTF8);
+ }
+ else
+ {
+ aDescription = OUString(reinterpret_cast<char*>(xBlob->getBytes(1, static_cast<sal_Int32>(aBlobLength)).getArray()),
+ aBlobLength,
+ RTL_TEXTENCODING_UTF8);
+ }
+ }
+ aCurrentRow[12] = new ORowSetValueDecorator(aDescription);
+ }
+ // 13. Default -- may be omitted.
+ {
+ uno::Reference< XBlob > xDefaultValueBlob = xRow->getBlob(4);
+ if (xDefaultValueBlob.is())
+ {
+ // TODO: Implement
+ }
+ aCurrentRow[13] = new ORowSetValueDecorator();
+ }
+
+ // 16. Bytes in Column for char
+ if (aType == SQL_TEXT)
+ {
+ aCurrentRow[16] = new ORowSetValueDecorator(xRow->getShort(8));
+ }
+ else if (aType == SQL_VARYING)
+ {
+ aCurrentRow[16] = new ORowSetValueDecorator(sal_Int32(32767));
+ }
+ else
+ {
+ aCurrentRow[16] = new ORowSetValueDecorator(sal_Int32(0));
+ }
+ // 17. Index of column
+ {
+ short nColumnNumber = xRow->getShort(5);
+ // Firebird stores column numbers beginning with 0 internally
+ // SDBC expects column numbering to begin with 1.
+ aCurrentRow[17] = new ORowSetValueDecorator(sal_Int32(nColumnNumber + 1));
+ }
+ // 18. Is nullable
+ if (xRow->getShort(9))
+ {
+ aCurrentRow[18] = new ORowSetValueDecorator(OUString("NO"));
+ }
+ else
+ {
+ aCurrentRow[18] = new ORowSetValueDecorator(OUString("YES"));
+ }
+
+ aResults.push_back(aCurrentRow);
+ }
+ rtl::Reference<ODatabaseMetaDataResultSet> pResultSet = new
+ ODatabaseMetaDataResultSet(ODatabaseMetaDataResultSet::eColumns);
+ pResultSet->setRows( std::move(aResults) );
+
+ return pResultSet;
+}
+
+uno::Reference< XResultSet > SAL_CALL ODatabaseMetaData::getTables(
+ const Any& /*catalog*/,
+ const OUString& /*schemaPattern*/,
+ const OUString& tableNamePattern,
+ const Sequence< OUString >& types)
+{
+ SAL_INFO("connectivity.firebird", "getTables() with "
+ "TableNamePattern: " << tableNamePattern);
+
+ rtl::Reference<ODatabaseMetaDataResultSet> pResultSet = new
+ ODatabaseMetaDataResultSet(ODatabaseMetaDataResultSet::eTables);
+ uno::Reference< XStatement > statement = m_pConnection->createStatement();
+
+ static const char wld[] = "%";
+ OUStringBuffer queryBuf(
+ "SELECT "
+ "RDB$RELATION_NAME, "
+ "RDB$SYSTEM_FLAG, "
+ "RDB$RELATION_TYPE, "
+ "RDB$DESCRIPTION, "
+ "RDB$VIEW_BLR "
+ "FROM RDB$RELATIONS "
+ "WHERE ");
+
+ // TODO: GLOBAL TEMPORARY, LOCAL TEMPORARY, ALIAS, SYNONYM
+ if (!types.hasElements() || (types.getLength() == 1 && types[0].match(wld)))
+ {
+ // from Firebird: src/jrd/constants.h
+ // rel_persistent = 0, rel_view = 1, rel_external = 2
+ // All table types? I.e. includes system tables.
+ queryBuf.append("(RDB$RELATION_TYPE = 0 OR RDB$RELATION_TYPE = 1 OR RDB$RELATION_TYPE = 2) ");
+ }
+ else
+ {
+ queryBuf.append("( (0 = 1) ");
+ for (OUString const & t : types)
+ {
+ if (t == "SYSTEM TABLE")
+ queryBuf.append("OR (RDB$SYSTEM_FLAG = 1 AND RDB$VIEW_BLR IS NULL) ");
+ else if (t == "TABLE")
+ queryBuf.append("OR (RDB$SYSTEM_FLAG IS NULL OR RDB$SYSTEM_FLAG = 0 AND RDB$VIEW_BLR IS NULL) ");
+ else if (t == "VIEW")
+ queryBuf.append("OR (RDB$SYSTEM_FLAG IS NULL OR RDB$SYSTEM_FLAG = 0 AND RDB$VIEW_BLR IS NOT NULL) ");
+ else
+ throw SQLException(); // TODO: implement other types, see above.
+ }
+ queryBuf.append(") ");
+ }
+
+ if (!tableNamePattern.isEmpty())
+ {
+ OUString sAppend;
+ if (tableNamePattern.match(wld))
+ sAppend = "AND RDB$RELATION_NAME LIKE '%' ";
+ else
+ sAppend = "AND RDB$RELATION_NAME = '%' ";
+
+ queryBuf.append(sAppend.replaceAll(wld, tableNamePattern));
+ }
+
+ queryBuf.append(" ORDER BY RDB$RELATION_TYPE, RDB$RELATION_NAME");
+
+ OUString query = queryBuf.makeStringAndClear();
+
+ uno::Reference< XResultSet > rs = statement->executeQuery(query);
+ uno::Reference< XRow > xRow( rs, UNO_QUERY_THROW );
+ ODatabaseMetaDataResultSet::ORows aResults;
+
+ ODatabaseMetaDataResultSet::ORow aCurrentRow(6);
+ aCurrentRow[0] = new ORowSetValueDecorator(); // 0. Unused
+ aCurrentRow[1] = new ORowSetValueDecorator(); // 1. Table_Cat Unsupported
+ aCurrentRow[2] = new ORowSetValueDecorator(); // 2. Table_Schem Unsupported
+
+ while( rs->next() )
+ {
+ // 3. TABLE_NAME
+ aCurrentRow[3] = new ORowSetValueDecorator(sanitizeIdentifier(xRow->getString(1)));
+ // 4. TABLE_TYPE
+ {
+ // TODO: check this as the docs are a bit unclear.
+ sal_Int16 nSystemFlag = xRow->getShort(2);
+ sal_Int16 nTableType = xRow->getShort(3);
+ xRow->getBlob(5); // We have to retrieve a column to verify it is null.
+ bool aIsView = !xRow->wasNull();
+ OUString sTableType;
+
+ if (nSystemFlag == 1)
+ {
+ sTableType = "SYSTEM TABLE";
+ }
+ else if (aIsView)
+ {
+ sTableType = "VIEW";
+ }
+ else
+ {
+ // see above about src/jrd/constants.h
+ if (nTableType == 0 || nTableType == 2)
+ sTableType = "TABLE";
+ }
+
+ aCurrentRow[4] = new ORowSetValueDecorator(sTableType);
+ }
+ // 5. REMARKS
+ {
+ uno::Reference< XClob > xClob = xRow->getClob(4);
+ if (xClob.is())
+ {
+ aCurrentRow[5] = new ORowSetValueDecorator(xClob->getSubString(1, xClob->length()));
+ }
+ }
+
+ aResults.push_back(aCurrentRow);
+ }
+
+ pResultSet->setRows( std::move(aResults) );
+
+ return pResultSet;
+}
+
+uno::Reference< XResultSet > SAL_CALL ODatabaseMetaData::getProcedureColumns(
+ const Any&, const OUString&,
+ const OUString&, const OUString& )
+{
+ SAL_WARN("connectivity.firebird", "Not yet implemented");
+ OSL_FAIL("Not implemented yet!");
+ // TODO implement
+ return new ODatabaseMetaDataResultSet(ODatabaseMetaDataResultSet::eProcedureColumns);
+}
+
+uno::Reference< XResultSet > SAL_CALL ODatabaseMetaData::getProcedures(
+ const Any&, const OUString&,
+ const OUString& )
+{
+ SAL_WARN("connectivity.firebird", "Not yet implemented");
+ OSL_FAIL("Not implemented yet!");
+ // TODO implement
+ return new ODatabaseMetaDataResultSet(ODatabaseMetaDataResultSet::eProcedures);
+}
+
+uno::Reference< XResultSet > SAL_CALL ODatabaseMetaData::getVersionColumns(
+ const Any&, const OUString&, const OUString& )
+{
+ SAL_WARN("connectivity.firebird", "Not yet implemented");
+ OSL_FAIL("Not implemented yet!");
+ // TODO implement
+ return new ODatabaseMetaDataResultSet(ODatabaseMetaDataResultSet::eVersionColumns);
+}
+
+uno::Reference< XResultSet > SAL_CALL ODatabaseMetaData::getExportedKeys(
+ const Any&, const OUString&, const OUString& table )
+{
+ return ODatabaseMetaData::lcl_getKeys(false, table);
+}
+
+uno::Reference< XResultSet > SAL_CALL ODatabaseMetaData::getImportedKeys(
+ const Any&, const OUString&, const OUString& table )
+{
+ return ODatabaseMetaData::lcl_getKeys(true, table);
+}
+
+uno::Reference< XResultSet > ODatabaseMetaData::lcl_getKeys(const bool bIsImport, std::u16string_view table )
+{
+ rtl::Reference<ODatabaseMetaDataResultSet> pResultSet = new
+ ODatabaseMetaDataResultSet(bIsImport?ODatabaseMetaDataResultSet::eImportedKeys:ODatabaseMetaDataResultSet::eExportedKeys);
+
+ uno::Reference< XStatement > statement = m_pConnection->createStatement();
+
+ OUString sSQL = "SELECT "
+ "RDB$REF_CONSTRAINTS.RDB$UPDATE_RULE, " // 1 update rule
+ "RDB$REF_CONSTRAINTS.RDB$DELETE_RULE, " // 2 delete rule
+ "RDB$REF_CONSTRAINTS.RDB$CONST_NAME_UQ, " // 3 primary or unique key name
+ "RDB$REF_CONSTRAINTS.RDB$CONSTRAINT_NAME, " // 4 foreign key name
+ "PRIM.RDB$DEFERRABLE, " // 5 deferrability
+ "PRIM.RDB$INITIALLY_DEFERRED, " // 6 deferrability
+ "PRIM.RDB$RELATION_NAME, " // 7 PK table name
+ "PRIMARY_INDEX.RDB$FIELD_NAME, " // 8 PK column name
+ "PRIMARY_INDEX.RDB$FIELD_POSITION, " // 9 PK sequence number
+ "FOREI.RDB$RELATION_NAME, " // 10 FK table name
+ "FOREIGN_INDEX.RDB$FIELD_NAME " // 11 FK column name
+ "FROM RDB$REF_CONSTRAINTS "
+ "INNER JOIN RDB$RELATION_CONSTRAINTS AS PRIM "
+ "ON RDB$REF_CONSTRAINTS.RDB$CONST_NAME_UQ = PRIM.RDB$CONSTRAINT_NAME "
+ "INNER JOIN RDB$RELATION_CONSTRAINTS AS FOREI "
+ "ON RDB$REF_CONSTRAINTS.RDB$CONSTRAINT_NAME = FOREI.RDB$CONSTRAINT_NAME "
+ "INNER JOIN RDB$INDEX_SEGMENTS AS PRIMARY_INDEX "
+ "ON PRIM.RDB$INDEX_NAME = PRIMARY_INDEX.RDB$INDEX_NAME "
+ "INNER JOIN RDB$INDEX_SEGMENTS AS FOREIGN_INDEX "
+ "ON FOREI.RDB$INDEX_NAME = FOREIGN_INDEX.RDB$INDEX_NAME "
+ "WHERE FOREI.RDB$CONSTRAINT_TYPE = 'FOREIGN KEY' ";
+ if (bIsImport)
+ sSQL += OUString::Concat("AND FOREI.RDB$RELATION_NAME = '")+ table +"'";
+ else
+ sSQL += OUString::Concat("AND PRIM.RDB$RELATION_NAME = '")+ table +"'";
+
+ uno::Reference< XResultSet > rs = statement->executeQuery(sSQL);
+ uno::Reference< XRow > xRow( rs, UNO_QUERY_THROW );
+
+ ODatabaseMetaDataResultSet::ORows aResults;
+ ODatabaseMetaDataResultSet::ORow aCurrentRow(15);
+
+ // TODO is it necessary to initialize these?
+ aCurrentRow[0] = new ORowSetValueDecorator(); // Unused
+ aCurrentRow[1] = new ORowSetValueDecorator(); // PKTABLE_CAT unsupported
+ aCurrentRow[2] = new ORowSetValueDecorator(); // PKTABLE_SCHEM unsupported
+ aCurrentRow[5] = new ORowSetValueDecorator(); // FKTABLE_CAT unsupported
+ aCurrentRow[6] = new ORowSetValueDecorator(); // FKTABLE_SCHEM unsupported
+
+ std::map< OUString,sal_Int32> aRuleMap;
+ aRuleMap[ OUString("CASCADE")] = KeyRule::CASCADE;
+ aRuleMap[ OUString("RESTRICT")] = KeyRule::RESTRICT;
+ aRuleMap[ OUString("SET NULL")] = KeyRule::SET_NULL;
+ aRuleMap[ OUString("SET DEFAULT")] = KeyRule::SET_DEFAULT;
+ aRuleMap[ OUString("NO ACTION")] = KeyRule::NO_ACTION;
+
+ while(rs->next())
+ {
+ aCurrentRow[3] = new ORowSetValueDecorator(sanitizeIdentifier(xRow->getString(7))); // PK table
+ aCurrentRow[4] = new ORowSetValueDecorator(sanitizeIdentifier(xRow->getString(8))); // PK column
+ aCurrentRow[7] = new ORowSetValueDecorator(sanitizeIdentifier(xRow->getString(10))); // FK table
+ aCurrentRow[8] = new ORowSetValueDecorator(sanitizeIdentifier(xRow->getString(11))); // FK column
+
+ aCurrentRow[9] = new ORowSetValueDecorator(xRow->getShort(9)); // PK sequence number
+ aCurrentRow[10] = new ORowSetValueDecorator(aRuleMap[sanitizeIdentifier(xRow->getString(1))]); // update role
+ aCurrentRow[11] = new ORowSetValueDecorator(aRuleMap[sanitizeIdentifier(xRow->getString(2))]); // delete role
+
+ aCurrentRow[12] = new ORowSetValueDecorator(sanitizeIdentifier(xRow->getString(4))); // FK name
+ aCurrentRow[13] = new ORowSetValueDecorator(sanitizeIdentifier(xRow->getString(3))); // PK name
+
+ aCurrentRow[14] = new ORowSetValueDecorator(Deferrability::NONE); // deferrability
+
+ // deferrability is currently not supported, but may be supported in the future.
+ /*
+ aCurrentRow[14] = (xRow->getString(5) == "NO" ?
+ new ORowSetValueDecorator(Deferrability::NONE)
+ : (xRow->getString(6) == "NO" ?
+ new ORowSetValueDecorator(Deferrability::INITIALLY_IMMEDIATE)
+ : new ORowSetValueDecorator(Deferrability::INITIALLY_DEFERRED));
+ */
+
+ aResults.push_back(aCurrentRow);
+ }
+
+ pResultSet->setRows( std::move(aResults) );
+ return pResultSet;
+}
+
+uno::Reference< XResultSet > SAL_CALL ODatabaseMetaData::getPrimaryKeys(
+ const Any& /*aCatalog*/,
+ const OUString& /*sSchema*/,
+ const OUString& sTable)
+{
+ SAL_INFO("connectivity.firebird", "getPrimaryKeys() with "
+ "Table: " << sTable);
+
+ OUString sAppend = "WHERE constr.RDB$RELATION_NAME = '%' ";
+ OUString sQuery = "SELECT "
+ "constr.RDB$RELATION_NAME, " // 1. Table Name
+ "inds.RDB$FIELD_NAME, " // 2. Column Name
+ "inds.RDB$FIELD_POSITION, " // 3. Sequence Number
+ "constr.RDB$CONSTRAINT_NAME " // 4 Constraint name
+ "FROM RDB$RELATION_CONSTRAINTS constr "
+ "JOIN RDB$INDEX_SEGMENTS inds "
+ "on (constr.RDB$INDEX_NAME = inds.RDB$INDEX_NAME) " +
+ sAppend.replaceAll("%", sTable) +
+ "AND constr.RDB$CONSTRAINT_TYPE = 'PRIMARY KEY' "
+ "ORDER BY inds.RDB$FIELD_NAME";
+
+ uno::Reference< XStatement > xStatement = m_pConnection->createStatement();
+ uno::Reference< XResultSet > xRs = xStatement->executeQuery(sQuery);
+ uno::Reference< XRow > xRow( xRs, UNO_QUERY_THROW );
+
+ ODatabaseMetaDataResultSet::ORows aResults;
+ ODatabaseMetaDataResultSet::ORow aCurrentRow(7);
+
+ aCurrentRow[0] = new ORowSetValueDecorator(); // Unused -- numbering starts from 0
+ aCurrentRow[1] = new ORowSetValueDecorator(); // Catalog - can be null
+ aCurrentRow[2] = new ORowSetValueDecorator(); // Schema - can be null
+
+ while(xRs->next())
+ {
+ // 3. Table Name
+ if (xRs->getRow() == 1) // Table name doesn't change, so only retrieve once
+ {
+ aCurrentRow[3] = new ORowSetValueDecorator(sanitizeIdentifier(xRow->getString(1)));
+ }
+ // 4. Column Name
+ aCurrentRow[4] = new ORowSetValueDecorator(sanitizeIdentifier(xRow->getString(2)));
+ // 5. KEY_SEQ (which key in the sequence)
+ aCurrentRow[5] = new ORowSetValueDecorator(xRow->getShort(3));
+ // 6. Primary Key Name
+ aCurrentRow[6] = new ORowSetValueDecorator(sanitizeIdentifier(xRow->getString(4)));
+
+ aResults.push_back(aCurrentRow);
+ }
+ rtl::Reference<ODatabaseMetaDataResultSet> pResultSet = new
+ ODatabaseMetaDataResultSet(ODatabaseMetaDataResultSet::ePrimaryKeys);
+ pResultSet->setRows( std::move(aResults) );
+
+ return pResultSet;
+}
+
+uno::Reference< XResultSet > SAL_CALL ODatabaseMetaData::getIndexInfo(
+ const Any& /*aCatalog*/,
+ const OUString& /*sSchema*/,
+ const OUString& sTable,
+ sal_Bool bIsUnique,
+ sal_Bool) // TODO: what is bIsApproximate?
+
+{
+ // Apparently this method can also return a "tableIndexStatistic"
+ // However this is only mentioned in XDatabaseMetaData.idl (whose comments
+ // are duplicated in the postgresql driver), and is otherwise undocumented.
+ SAL_INFO("connectivity.firebird", "getPrimaryKeys() with "
+ "Table: " << sTable);
+
+ OUStringBuffer aQueryBuf("SELECT "
+ "indices.RDB$RELATION_NAME, " // 1. Table Name
+ "index_segments.RDB$FIELD_NAME, " // 2. Column Name
+ "index_segments.RDB$FIELD_POSITION, " // 3. Sequence Number
+ "indices.RDB$INDEX_NAME, " // 4. Index name
+ "indices.RDB$UNIQUE_FLAG, " // 5. Unique Flag
+ "indices.RDB$INDEX_TYPE " // 6. Index Type
+ "FROM RDB$INDICES indices "
+ "JOIN RDB$INDEX_SEGMENTS index_segments "
+ "on (indices.RDB$INDEX_NAME = index_segments.RDB$INDEX_NAME) "
+ "WHERE indices.RDB$RELATION_NAME = '" + sTable + "' "
+ "AND (indices.RDB$SYSTEM_FLAG = 0) ");
+ // Not sure whether we should exclude system indices, but otoh. we never
+ // actually deal with system tables (system indices only apply to system
+ // tables) within the GUI.
+
+ // Only filter if true (according to the docs), i.e.:
+ // If false we return all indices, if true we return only unique indices
+ if (bIsUnique)
+ aQueryBuf.append("AND (indices.RDB$UNIQUE_FLAG = 1) ");
+
+ OUString sQuery = aQueryBuf.makeStringAndClear();
+
+ uno::Reference< XStatement > xStatement = m_pConnection->createStatement();
+ uno::Reference< XResultSet > xRs = xStatement->executeQuery(sQuery);
+ uno::Reference< XRow > xRow( xRs, UNO_QUERY_THROW );
+
+ ODatabaseMetaDataResultSet::ORows aResults;
+ ODatabaseMetaDataResultSet::ORow aCurrentRow(14);
+
+ aCurrentRow[0] = new ORowSetValueDecorator(); // Unused -- numbering starts from 0
+ aCurrentRow[1] = new ORowSetValueDecorator(); // Catalog - can be null
+ aCurrentRow[2] = new ORowSetValueDecorator(); // Schema - can be null
+ aCurrentRow[5] = new ORowSetValueDecorator(); // Index Catalog -- can be null
+ // Wikipedia indicates:
+ // 'Firebird makes all indices of the database behave like well-tuned "clustered indexes" used by other architectures.'
+ // but it's not "CLUSTERED", neither "STATISTIC" nor "HASHED" (the other specific types from offapi/com/sun/star/sdbc/IndexType.idl)
+ // According to https://www.ibphoenix.com/resources/documents/design/doc_18,
+ // it seems another type => OTHER
+ aCurrentRow[7] = new ORowSetValueDecorator(IndexType::OTHER); // 7. INDEX TYPE
+ aCurrentRow[13] = new ORowSetValueDecorator(); // Filter Condition -- can be null
+
+ while(xRs->next())
+ {
+ // 3. Table Name
+ if (xRs->getRow() == 1) // Table name doesn't change, so only retrieve once
+ {
+ aCurrentRow[3] = new ORowSetValueDecorator(sanitizeIdentifier(xRow->getString(1)));
+ }
+
+ // 4. NON_UNIQUE -- i.e. specifically negate here.
+ aCurrentRow[4] = new ORowSetValueDecorator(ORowSetValue(xRow->getShort(5) == 0));
+ // 6. INDEX NAME
+ aCurrentRow[6] = new ORowSetValueDecorator(sanitizeIdentifier(xRow->getString(4)));
+
+ // 8. ORDINAL POSITION
+ aCurrentRow[8] = new ORowSetValueDecorator(xRow->getShort(3));
+ // 9. COLUMN NAME
+ aCurrentRow[9] = new ORowSetValueDecorator(sanitizeIdentifier(xRow->getString(2)));
+ // 10. ASC(ending)/DESC(ending)
+ if (xRow->getShort(6) == 1)
+ aCurrentRow[10] = new ORowSetValueDecorator(OUString("D"));
+ else
+ aCurrentRow[10] = new ORowSetValueDecorator(OUString("A"));
+ // TODO: double check this^^^, doesn't seem to be officially documented anywhere.
+ // 11. CARDINALITY
+ aCurrentRow[11] = new ORowSetValueDecorator(sal_Int32(0)); // TODO: determine how to do this
+ // 12. PAGES
+ aCurrentRow[12] = new ORowSetValueDecorator(sal_Int32(0)); // TODO: determine how to do this
+
+ aResults.push_back(aCurrentRow);
+ }
+ rtl::Reference<ODatabaseMetaDataResultSet> pResultSet = new
+ ODatabaseMetaDataResultSet(ODatabaseMetaDataResultSet::eIndexInfo);
+ pResultSet->setRows( std::move(aResults) );
+
+ return pResultSet;
+}
+
+uno::Reference< XResultSet > SAL_CALL ODatabaseMetaData::getBestRowIdentifier(
+ const Any&, const OUString&, const OUString&, sal_Int32,
+ sal_Bool )
+{
+ OSL_FAIL("Not implemented yet!");
+ // TODO implement
+ return new ODatabaseMetaDataResultSet(ODatabaseMetaDataResultSet::eBestRowIdentifier);
+}
+
+uno::Reference< XResultSet > SAL_CALL ODatabaseMetaData::getTablePrivileges(
+ const Any& /*aCatalog*/,
+ const OUString& /*sSchemaPattern*/,
+ const OUString& sTableNamePattern)
+{
+ SAL_INFO("connectivity.firebird", "getTablePrivileges() with "
+ "TableNamePattern: " << sTableNamePattern);
+
+ rtl::Reference<ODatabaseMetaDataResultSet> pResultSet = new
+ ODatabaseMetaDataResultSet(ODatabaseMetaDataResultSet::eTablePrivileges);
+ uno::Reference< XStatement > statement = m_pConnection->createStatement();
+
+ // TODO: column specific privileges are included, we may need
+ // to have WHERE RDB$FIELD_NAME = NULL or similar.
+ static const char wld[] = "%";
+ OUStringBuffer queryBuf(
+ "SELECT "
+ "priv.RDB$RELATION_NAME, " // 1
+ "priv.RDB$GRANTOR," // 2
+ "priv.RDB$USER, " // 3 Grantee
+ "priv.RDB$PRIVILEGE, " // 4
+ "priv.RDB$GRANT_OPTION " // 5 is Grantable
+ "FROM RDB$USER_PRIVILEGES priv ");
+
+ if (!sTableNamePattern.isEmpty())
+ {
+ OUString sAppend;
+ if (sTableNamePattern.match(wld))
+ sAppend = "WHERE priv.RDB$RELATION_NAME LIKE '%' ";
+ else
+ sAppend = "WHERE priv.RDB$RELATION_NAME = '%' ";
+
+ queryBuf.append(sAppend.replaceAll(wld, sTableNamePattern));
+ }
+ queryBuf.append(" ORDER BY priv.RDB$RELATION_TYPE, "
+ "priv.RDB$RELATION_NAME, "
+ "priv.RDB$PRIVILEGE");
+
+ OUString query = queryBuf.makeStringAndClear();
+
+ uno::Reference< XResultSet > rs = statement->executeQuery(query);
+ uno::Reference< XRow > xRow( rs, UNO_QUERY_THROW );
+ ODatabaseMetaDataResultSet::ORows aResults;
+
+ ODatabaseMetaDataResultSet::ORow aRow(8);
+ aRow[0] = new ORowSetValueDecorator(); // Unused
+ aRow[1] = new ORowSetValueDecorator(); // TABLE_CAT unsupported
+ aRow[2] = new ORowSetValueDecorator(); // TABLE_SCHEM unsupported.
+
+ while( rs->next() )
+ {
+ // 3. TABLE_NAME
+ aRow[3] = new ORowSetValueDecorator(sanitizeIdentifier(xRow->getString(1)));
+ aRow[4] = new ORowSetValueDecorator(sanitizeIdentifier(xRow->getString(2))); // 4. GRANTOR
+ aRow[5] = new ORowSetValueDecorator(sanitizeIdentifier(xRow->getString(3))); // 5. GRANTEE
+ aRow[6] = new ORowSetValueDecorator(xRow->getString(4)); // 6. Privilege
+ aRow[7] = new ORowSetValueDecorator(ORowSetValue(bool(xRow->getBoolean(5)))); // 7. Is Grantable
+
+ aResults.push_back(aRow);
+ }
+
+ pResultSet->setRows( std::move(aResults) );
+
+ return pResultSet;
+}
+
+uno::Reference< XResultSet > SAL_CALL ODatabaseMetaData::getCrossReference(
+ const Any&, const OUString&,
+ const OUString&, const Any&,
+ const OUString&, const OUString& )
+{
+ OSL_FAIL("Not implemented yet!");
+ // TODO implement
+ return new ODatabaseMetaDataResultSet(ODatabaseMetaDataResultSet::eCrossReference);
+}
+
+uno::Reference< XResultSet > SAL_CALL ODatabaseMetaData::getUDTs( const Any&, const OUString&, const OUString&, const Sequence< sal_Int32 >& )
+{
+ OSL_FAIL("Not implemented yet!");
+ // TODO implement
+ return new ODatabaseMetaDataResultSet(ODatabaseMetaDataResultSet::eUDTs);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/connectivity/source/drivers/firebird/DatabaseMetaData.hxx b/connectivity/source/drivers/firebird/DatabaseMetaData.hxx
new file mode 100644
index 0000000000..c577f594d2
--- /dev/null
+++ b/connectivity/source/drivers/firebird/DatabaseMetaData.hxx
@@ -0,0 +1,205 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <string_view>
+
+#include "Connection.hxx"
+
+#include <com/sun/star/sdbc/XDatabaseMetaData.hpp>
+#include <cppuhelper/implbase.hxx>
+#include <rtl/ref.hxx>
+
+namespace connectivity::firebird
+ {
+
+ //************ Class: ODatabaseMetaData
+
+
+ typedef ::cppu::WeakImplHelper< css::sdbc::XDatabaseMetaData> ODatabaseMetaData_BASE;
+
+ class ODatabaseMetaData : public ODatabaseMetaData_BASE
+ {
+ ::rtl::Reference<Connection> m_pConnection;
+ private:
+ css::uno::Reference< css::sdbc::XResultSet > lcl_getKeys( bool bIsImport, std::u16string_view table );
+ public:
+
+ explicit ODatabaseMetaData(Connection* _pCon);
+ virtual ~ODatabaseMetaData() override;
+
+ // as I mentioned before this interface is really BIG
+ // XDatabaseMetaData
+ virtual sal_Bool SAL_CALL allProceduresAreCallable( ) override;
+ virtual sal_Bool SAL_CALL allTablesAreSelectable( ) override;
+ virtual OUString SAL_CALL getURL( ) override;
+ virtual OUString SAL_CALL getUserName( ) override;
+ virtual sal_Bool SAL_CALL isReadOnly( ) override;
+ virtual sal_Bool SAL_CALL nullsAreSortedHigh( ) override;
+ virtual sal_Bool SAL_CALL nullsAreSortedLow( ) override;
+ virtual sal_Bool SAL_CALL nullsAreSortedAtStart( ) override;
+ virtual sal_Bool SAL_CALL nullsAreSortedAtEnd( ) override;
+ virtual OUString SAL_CALL getDatabaseProductName( ) override;
+ virtual OUString SAL_CALL getDatabaseProductVersion( ) override;
+ virtual OUString SAL_CALL getDriverName( ) override;
+ virtual OUString SAL_CALL getDriverVersion( ) override;
+ virtual sal_Int32 SAL_CALL getDriverMajorVersion( ) override;
+ virtual sal_Int32 SAL_CALL getDriverMinorVersion( ) override;
+ virtual sal_Bool SAL_CALL usesLocalFiles( ) override;
+ virtual sal_Bool SAL_CALL usesLocalFilePerTable( ) override;
+ virtual sal_Bool SAL_CALL supportsMixedCaseIdentifiers( ) override;
+ virtual sal_Bool SAL_CALL storesUpperCaseIdentifiers( ) override;
+ virtual sal_Bool SAL_CALL storesLowerCaseIdentifiers( ) override;
+ virtual sal_Bool SAL_CALL storesMixedCaseIdentifiers( ) override;
+ virtual sal_Bool SAL_CALL supportsMixedCaseQuotedIdentifiers( ) override;
+ virtual sal_Bool SAL_CALL storesUpperCaseQuotedIdentifiers( ) override;
+ virtual sal_Bool SAL_CALL storesLowerCaseQuotedIdentifiers( ) override;
+ virtual sal_Bool SAL_CALL storesMixedCaseQuotedIdentifiers( ) override;
+ virtual OUString SAL_CALL getIdentifierQuoteString( ) override;
+ virtual OUString SAL_CALL getSQLKeywords( ) override;
+ virtual OUString SAL_CALL getNumericFunctions( ) override;
+ virtual OUString SAL_CALL getStringFunctions( ) override;
+ virtual OUString SAL_CALL getSystemFunctions( ) override;
+ virtual OUString SAL_CALL getTimeDateFunctions( ) override;
+ virtual OUString SAL_CALL getSearchStringEscape( ) override;
+ virtual OUString SAL_CALL getExtraNameCharacters( ) override;
+ virtual sal_Bool SAL_CALL supportsAlterTableWithAddColumn( ) override;
+ virtual sal_Bool SAL_CALL supportsAlterTableWithDropColumn( ) override;
+ virtual sal_Bool SAL_CALL supportsColumnAliasing( ) override;
+ virtual sal_Bool SAL_CALL nullPlusNonNullIsNull( ) override;
+ virtual sal_Bool SAL_CALL supportsTypeConversion( ) override;
+ virtual sal_Bool SAL_CALL supportsConvert( sal_Int32 fromType, sal_Int32 toType ) override;
+ virtual sal_Bool SAL_CALL supportsTableCorrelationNames( ) override;
+ virtual sal_Bool SAL_CALL supportsDifferentTableCorrelationNames( ) override;
+ virtual sal_Bool SAL_CALL supportsExpressionsInOrderBy( ) override;
+ virtual sal_Bool SAL_CALL supportsOrderByUnrelated( ) override;
+ virtual sal_Bool SAL_CALL supportsGroupBy( ) override;
+ virtual sal_Bool SAL_CALL supportsGroupByUnrelated( ) override;
+ virtual sal_Bool SAL_CALL supportsGroupByBeyondSelect( ) override;
+ virtual sal_Bool SAL_CALL supportsLikeEscapeClause( ) override;
+ virtual sal_Bool SAL_CALL supportsMultipleResultSets( ) override;
+ virtual sal_Bool SAL_CALL supportsMultipleTransactions( ) override;
+ virtual sal_Bool SAL_CALL supportsNonNullableColumns( ) override;
+ virtual sal_Bool SAL_CALL supportsMinimumSQLGrammar( ) override;
+ virtual sal_Bool SAL_CALL supportsCoreSQLGrammar( ) override;
+ virtual sal_Bool SAL_CALL supportsExtendedSQLGrammar( ) override;
+ virtual sal_Bool SAL_CALL supportsANSI92EntryLevelSQL( ) override;
+ virtual sal_Bool SAL_CALL supportsANSI92IntermediateSQL( ) override;
+ virtual sal_Bool SAL_CALL supportsANSI92FullSQL( ) override;
+ virtual sal_Bool SAL_CALL supportsIntegrityEnhancementFacility( ) override;
+ virtual sal_Bool SAL_CALL supportsOuterJoins( ) override;
+ virtual sal_Bool SAL_CALL supportsFullOuterJoins( ) override;
+ virtual sal_Bool SAL_CALL supportsLimitedOuterJoins( ) override;
+ virtual OUString SAL_CALL getSchemaTerm( ) override;
+ virtual OUString SAL_CALL getProcedureTerm( ) override;
+ virtual OUString SAL_CALL getCatalogTerm( ) override;
+ virtual sal_Bool SAL_CALL isCatalogAtStart( ) override;
+ virtual OUString SAL_CALL getCatalogSeparator( ) override;
+ virtual sal_Bool SAL_CALL supportsSchemasInDataManipulation( ) override;
+ virtual sal_Bool SAL_CALL supportsSchemasInProcedureCalls( ) override;
+ virtual sal_Bool SAL_CALL supportsSchemasInTableDefinitions( ) override;
+ virtual sal_Bool SAL_CALL supportsSchemasInIndexDefinitions( ) override;
+ virtual sal_Bool SAL_CALL supportsSchemasInPrivilegeDefinitions( ) override;
+ virtual sal_Bool SAL_CALL supportsCatalogsInDataManipulation( ) override;
+ virtual sal_Bool SAL_CALL supportsCatalogsInProcedureCalls( ) override;
+ virtual sal_Bool SAL_CALL supportsCatalogsInTableDefinitions( ) override;
+ virtual sal_Bool SAL_CALL supportsCatalogsInIndexDefinitions( ) override;
+ virtual sal_Bool SAL_CALL supportsCatalogsInPrivilegeDefinitions( ) override;
+ virtual sal_Bool SAL_CALL supportsPositionedDelete( ) override;
+ virtual sal_Bool SAL_CALL supportsPositionedUpdate( ) override;
+ virtual sal_Bool SAL_CALL supportsSelectForUpdate( ) override;
+ virtual sal_Bool SAL_CALL supportsStoredProcedures( ) override;
+ virtual sal_Bool SAL_CALL supportsSubqueriesInComparisons( ) override;
+ virtual sal_Bool SAL_CALL supportsSubqueriesInExists( ) override;
+ virtual sal_Bool SAL_CALL supportsSubqueriesInIns( ) override;
+ virtual sal_Bool SAL_CALL supportsSubqueriesInQuantifieds( ) override;
+ virtual sal_Bool SAL_CALL supportsCorrelatedSubqueries( ) override;
+ virtual sal_Bool SAL_CALL supportsUnion( ) override;
+ virtual sal_Bool SAL_CALL supportsUnionAll( ) override;
+ virtual sal_Bool SAL_CALL supportsOpenCursorsAcrossCommit( ) override;
+ virtual sal_Bool SAL_CALL supportsOpenCursorsAcrossRollback( ) override;
+ virtual sal_Bool SAL_CALL supportsOpenStatementsAcrossCommit( ) override;
+ virtual sal_Bool SAL_CALL supportsOpenStatementsAcrossRollback( ) override;
+ virtual sal_Int32 SAL_CALL getMaxBinaryLiteralLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxCharLiteralLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxColumnNameLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxColumnsInGroupBy( ) override;
+ virtual sal_Int32 SAL_CALL getMaxColumnsInIndex( ) override;
+ virtual sal_Int32 SAL_CALL getMaxColumnsInOrderBy( ) override;
+ virtual sal_Int32 SAL_CALL getMaxColumnsInSelect( ) override;
+ virtual sal_Int32 SAL_CALL getMaxColumnsInTable( ) override;
+ virtual sal_Int32 SAL_CALL getMaxConnections( ) override;
+ virtual sal_Int32 SAL_CALL getMaxCursorNameLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxIndexLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxSchemaNameLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxProcedureNameLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxCatalogNameLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxRowSize( ) override;
+ virtual sal_Bool SAL_CALL doesMaxRowSizeIncludeBlobs( ) override;
+ virtual sal_Int32 SAL_CALL getMaxStatementLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxStatements( ) override;
+ virtual sal_Int32 SAL_CALL getMaxTableNameLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxTablesInSelect( ) override;
+ virtual sal_Int32 SAL_CALL getMaxUserNameLength( ) override;
+ virtual sal_Int32 SAL_CALL getDefaultTransactionIsolation( ) override;
+ virtual sal_Bool SAL_CALL supportsTransactions( ) override;
+ virtual sal_Bool SAL_CALL supportsTransactionIsolationLevel( sal_Int32 level ) override;
+ virtual sal_Bool SAL_CALL supportsDataDefinitionAndDataManipulationTransactions( ) override;
+ virtual sal_Bool SAL_CALL supportsDataManipulationTransactionsOnly( ) override;
+ virtual sal_Bool SAL_CALL dataDefinitionCausesTransactionCommit( ) override;
+ virtual sal_Bool SAL_CALL dataDefinitionIgnoredInTransactions( ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getProcedures( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& procedureNamePattern ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getProcedureColumns( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& procedureNamePattern, const OUString& columnNamePattern ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getTables( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& tableNamePattern, const css::uno::Sequence< OUString >& types ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getSchemas( ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getCatalogs( ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getTableTypes( ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getColumns( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& tableNamePattern, const OUString& columnNamePattern ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getColumnPrivileges( const css::uno::Any& catalog, const OUString& schema, const OUString& table, const OUString& columnNamePattern ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getTablePrivileges( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& tableNamePattern ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getBestRowIdentifier( const css::uno::Any& catalog, const OUString& schema, const OUString& table, sal_Int32 scope, sal_Bool nullable ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getVersionColumns( const css::uno::Any& catalog, const OUString& schema, const OUString& table ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getPrimaryKeys( const css::uno::Any& catalog, const OUString& schema, const OUString& table ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getImportedKeys( const css::uno::Any& catalog, const OUString& schema, const OUString& table ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getExportedKeys( const css::uno::Any& catalog, const OUString& schema, const OUString& table ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getCrossReference( const css::uno::Any& primaryCatalog, const OUString& primarySchema, const OUString& primaryTable, const css::uno::Any& foreignCatalog, const OUString& foreignSchema, const OUString& foreignTable ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getTypeInfo( ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getIndexInfo( const css::uno::Any& catalog, const OUString& schema, const OUString& table, sal_Bool unique, sal_Bool approximate ) override;
+ virtual sal_Bool SAL_CALL supportsResultSetType( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL supportsResultSetConcurrency( sal_Int32 setType, sal_Int32 concurrency ) override;
+ virtual sal_Bool SAL_CALL ownUpdatesAreVisible( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL ownDeletesAreVisible( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL ownInsertsAreVisible( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL othersUpdatesAreVisible( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL othersDeletesAreVisible( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL othersInsertsAreVisible( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL updatesAreDetected( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL deletesAreDetected( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL insertsAreDetected( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL supportsBatchUpdates( ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getUDTs( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& typeNamePattern, const css::uno::Sequence< sal_Int32 >& types ) override;
+ virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL getConnection( ) override;
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/connectivity/source/drivers/firebird/Driver.cxx b/connectivity/source/drivers/firebird/Driver.cxx
new file mode 100644
index 0000000000..b674d56c22
--- /dev/null
+++ b/connectivity/source/drivers/firebird/Driver.cxx
@@ -0,0 +1,228 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "Connection.hxx"
+#include "Driver.hxx"
+#include "SubComponent.hxx"
+
+#include <connectivity/dbexception.hxx>
+#include <strings.hrc>
+#include <resource/sharedresources.hxx>
+
+#include <comphelper/servicehelper.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <osl/file.hxx>
+#include <osl/process.h>
+#include <rtl/bootstrap.hxx>
+#include <sal/log.hxx>
+
+using namespace com::sun::star;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::sdbc;
+using namespace com::sun::star::sdbcx;
+
+using namespace ::osl;
+
+using namespace connectivity::firebird;
+
+// Static const variables
+namespace {
+constexpr OUString our_sFirebirdTmpVar = u"FIREBIRD_TMP"_ustr;
+constexpr OUString our_sFirebirdLockVar = u"FIREBIRD_LOCK"_ustr;
+constexpr OUString our_sFirebirdMsgVar = u"FIREBIRD_MSG"_ustr;
+#ifdef MACOSX
+constexpr OUString our_sFirebirdLibVar = u"LIBREOFFICE_FIREBIRD_LIB"_ustr;
+#endif
+};
+
+FirebirdDriver::FirebirdDriver(const css::uno::Reference< css::uno::XComponentContext >& _rxContext)
+ : ODriver_BASE(m_aMutex)
+ , m_aContext(_rxContext)
+ , m_firebirdTMPDirectory(nullptr, true)
+ , m_firebirdLockDirectory(nullptr, true)
+{
+ // ::utl::TempFile uses a unique temporary directory (subdirectory of
+ // /tmp or other user specific tmp directory) per instance in which
+ // we can create directories for firebird at will.
+ m_firebirdTMPDirectory.EnableKillingFile(true);
+ m_firebirdLockDirectory.EnableKillingFile(true);
+
+ // Overrides firebird's default of /tmp or c:\temp
+ osl_setEnvironment(our_sFirebirdTmpVar.pData, m_firebirdTMPDirectory.GetFileName().pData);
+
+ // Overrides firebird's default of /tmp/firebird or c:\temp\firebird
+ osl_setEnvironment(our_sFirebirdLockVar.pData, m_firebirdLockDirectory.GetFileName().pData);
+
+#ifndef SYSTEM_FIREBIRD
+ // Overrides firebird's hardcoded default of /usr/local/firebird on *nix,
+ // however on Windows it seems to use the current directory as a default.
+ OUString sMsgURL("$BRAND_BASE_DIR/$BRAND_SHARE_SUBDIR/firebird");
+ ::rtl::Bootstrap::expandMacros(sMsgURL);
+ OUString sMsgPath;
+ ::osl::FileBase::getSystemPathFromFileURL(sMsgURL, sMsgPath);
+ osl_setEnvironment(our_sFirebirdMsgVar.pData, sMsgPath.pData);
+#ifdef MACOSX
+ // Set an env. variable to specify library location
+ // for dlopen used in fbclient.
+ OUString sLibURL("$LO_LIB_DIR");
+ ::rtl::Bootstrap::expandMacros(sLibURL);
+ OUString sLibPath;
+ ::osl::FileBase::getSystemPathFromFileURL(sLibURL, sLibPath);
+ osl_setEnvironment(our_sFirebirdLibVar.pData, sLibPath.pData);
+#endif /*MACOSX*/
+#endif /*!SYSTEM_FIREBIRD*/
+}
+
+FirebirdDriver::~FirebirdDriver() = default;
+
+void FirebirdDriver::disposing()
+{
+ MutexGuard aGuard(m_aMutex);
+
+ for (auto const& elem : m_xConnections)
+ {
+ Reference< XComponent > xComp(elem.get(), UNO_QUERY);
+ if (xComp.is())
+ xComp->dispose();
+ }
+ m_xConnections.clear();
+
+ osl_clearEnvironment(our_sFirebirdTmpVar.pData);
+ osl_clearEnvironment(our_sFirebirdLockVar.pData);
+
+#ifndef SYSTEM_FIREBIRD
+ osl_clearEnvironment(our_sFirebirdMsgVar.pData);
+#ifdef MACOSX
+ osl_clearEnvironment(our_sFirebirdLibVar.pData);
+#endif /*MACOSX*/
+#endif /*!SYSTEM_FIREBIRD*/
+
+ OSL_VERIFY(fb_shutdown(0, 1));
+
+ ODriver_BASE::disposing();
+}
+
+OUString SAL_CALL FirebirdDriver::getImplementationName()
+{
+ return "com.sun.star.comp.sdbc.firebird.Driver";
+}
+
+sal_Bool SAL_CALL FirebirdDriver::supportsService(const OUString& _rServiceName)
+{
+ return cppu::supportsService(this, _rServiceName);
+}
+
+Sequence< OUString > SAL_CALL FirebirdDriver::getSupportedServiceNames()
+{
+ return { "com.sun.star.sdbc.Driver", "com.sun.star.sdbcx.Driver" };
+}
+
+// ---- XDriver -------------------------------------------------------------
+Reference< XConnection > SAL_CALL FirebirdDriver::connect(
+ const OUString& url, const Sequence< PropertyValue >& info )
+{
+ SAL_INFO("connectivity.firebird", "connect(), URL: " << url );
+
+ MutexGuard aGuard( m_aMutex );
+ if (ODriver_BASE::rBHelper.bDisposed)
+ throw DisposedException();
+
+ if ( ! acceptsURL(url) )
+ return nullptr;
+
+ rtl::Reference<Connection> pCon = new Connection();
+ pCon->construct(url, info);
+
+ m_xConnections.push_back(WeakReferenceHelper(*pCon));
+
+ return pCon;
+}
+
+sal_Bool SAL_CALL FirebirdDriver::acceptsURL( const OUString& url )
+{
+ return (url == "sdbc:embedded:firebird" || url.startsWith("sdbc:firebird:"));
+}
+
+Sequence< DriverPropertyInfo > SAL_CALL FirebirdDriver::getPropertyInfo(
+ const OUString& url, const Sequence< PropertyValue >& )
+{
+ if ( ! acceptsURL(url) )
+ {
+ ::connectivity::SharedResources aResources;
+ const OUString sMessage = aResources.getResourceString(STR_URI_SYNTAX_ERROR);
+ ::dbtools::throwGenericSQLException(sMessage ,*this);
+ }
+
+ return Sequence< DriverPropertyInfo >();
+}
+
+sal_Int32 SAL_CALL FirebirdDriver::getMajorVersion( )
+{
+ // The major and minor version are sdbc driver specific. Must begin with 1.0
+ // as per https://api.libreoffice.org/docs/common/ref/com/sun/star/sdbc/XDriver.html
+ return 1;
+}
+
+sal_Int32 SAL_CALL FirebirdDriver::getMinorVersion( )
+{
+ return 0;
+}
+
+//----- XDataDefinitionSupplier
+uno::Reference< XTablesSupplier > SAL_CALL FirebirdDriver::getDataDefinitionByConnection(
+ const uno::Reference< XConnection >& rConnection)
+{
+ if (Connection* pConnection = comphelper::getFromUnoTunnel<Connection>(rConnection))
+ return pConnection->createCatalog();
+ return {};
+}
+
+uno::Reference< XTablesSupplier > SAL_CALL FirebirdDriver::getDataDefinitionByURL(
+ const OUString& rURL,
+ const uno::Sequence< PropertyValue >& rInfo)
+{
+ uno::Reference< XConnection > xConnection = connect(rURL, rInfo);
+ return getDataDefinitionByConnection(xConnection);
+}
+
+namespace connectivity::firebird
+{
+ void checkDisposed(bool _bThrow)
+ {
+ if (_bThrow)
+ throw DisposedException();
+
+ }
+
+} // namespace
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+connectivity_FirebirdDriver_get_implementation(
+ css::uno::XComponentContext* context , css::uno::Sequence<css::uno::Any> const&)
+{
+ try {
+ return cppu::acquire(new FirebirdDriver(context));
+ } catch (...) {
+ return nullptr;
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/connectivity/source/drivers/firebird/Driver.hxx b/connectivity/source/drivers/firebird/Driver.hxx
new file mode 100644
index 0000000000..d884b5008d
--- /dev/null
+++ b/connectivity/source/drivers/firebird/Driver.hxx
@@ -0,0 +1,90 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "Connection.hxx"
+
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/sdbc/XDriver.hpp>
+#include <com/sun/star/sdbcx/XDataDefinitionSupplier.hpp>
+#include <cppuhelper/compbase.hxx>
+#include <unotools/tempfile.hxx>
+
+namespace connectivity::firebird
+ {
+ // The SQL dialect in use
+ // Has to be used in various isc_* calls.
+ // 3: Is IB6 -- minimum required for delimited identifiers.
+ // SQL_DIALECT_V6 = 3, it's the last current version
+ // SQL_DIALECT_CURRENT is an alias for SQL_DIALECT_V6
+ // See src/dsql/sqlda_pub.h for full details
+
+ typedef ::cppu::WeakComponentImplHelper< css::sdbc::XDriver,
+ css::sdbcx::XDataDefinitionSupplier,
+ css::lang::XServiceInfo > ODriver_BASE;
+
+ class FirebirdDriver : public ODriver_BASE
+ {
+ private:
+ css::uno::Reference<css::uno::XComponentContext> m_aContext;
+ ::utl::TempFileNamed m_firebirdTMPDirectory;
+ ::utl::TempFileNamed m_firebirdLockDirectory;
+
+ protected:
+ ::osl::Mutex m_aMutex; // mutex is need to control member access
+ OWeakRefArray m_xConnections; // vector containing a list
+ // of all the Connection objects
+ // for this Driver
+
+ public:
+
+ explicit FirebirdDriver(const css::uno::Reference< css::uno::XComponentContext >& _rxContext);
+ virtual ~FirebirdDriver() override;
+ const css::uno::Reference<css::uno::XComponentContext>& getContext() const { return m_aContext; }
+
+ // OComponentHelper
+ virtual void SAL_CALL disposing() override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+ // XDriver
+ virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL connect( const OUString& url, const css::uno::Sequence< css::beans::PropertyValue >& info ) override;
+ virtual sal_Bool SAL_CALL acceptsURL( const OUString& url ) override;
+ virtual css::uno::Sequence< css::sdbc::DriverPropertyInfo > SAL_CALL getPropertyInfo( const OUString& url, const css::uno::Sequence< css::beans::PropertyValue >& info ) override;
+ virtual sal_Int32 SAL_CALL getMajorVersion( ) override;
+ virtual sal_Int32 SAL_CALL getMinorVersion( ) override;
+
+ // XDataDefinitionSupplier
+ virtual css::uno::Reference< css::sdbcx::XTablesSupplier >
+ SAL_CALL getDataDefinitionByConnection(
+ const css::uno::Reference< css::sdbc::XConnection >& rxConnection) override;
+ virtual css::uno::Reference< css::sdbcx::XTablesSupplier >
+ SAL_CALL getDataDefinitionByURL(
+ const OUString& rsURL,
+ const css::uno::Sequence< css::beans::PropertyValue >& rInfo) override;
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/connectivity/source/drivers/firebird/Indexes.cxx b/connectivity/source/drivers/firebird/Indexes.cxx
new file mode 100644
index 0000000000..7bf783c79c
--- /dev/null
+++ b/connectivity/source/drivers/firebird/Indexes.cxx
@@ -0,0 +1,33 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "Indexes.hxx"
+
+using namespace ::connectivity;
+using namespace ::connectivity::firebird;
+
+using namespace ::osl;
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::sdbc;
+
+Indexes::Indexes(Table* pTable, Mutex& rMutex, const std::vector<OUString>& rVector)
+ : OIndexesHelper(pTable, rMutex, rVector)
+ , m_pTable(pTable)
+{
+}
+
+// XDrop
+void Indexes::dropObject(sal_Int32 /*nPosition*/, const OUString& sIndexName)
+{
+ OUString sSql("DROP INDEX \"" + sIndexName + "\"");
+ m_pTable->getConnection()->createStatement()->execute(sSql);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/connectivity/source/drivers/firebird/Indexes.hxx b/connectivity/source/drivers/firebird/Indexes.hxx
new file mode 100644
index 0000000000..12d7dd1980
--- /dev/null
+++ b/connectivity/source/drivers/firebird/Indexes.hxx
@@ -0,0 +1,39 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include "Table.hxx"
+
+#include <connectivity/TIndexes.hxx>
+
+namespace connectivity::firebird
+ {
+
+ /**
+ * Firebird has a non-standard DROP INDEX statement, hence we need
+ * to override OIndexesHelper::dropObject
+ */
+ class Indexes: public ::connectivity::OIndexesHelper
+ {
+ private:
+ Table* m_pTable;
+ protected:
+ // XDrop
+ virtual void dropObject(sal_Int32 nPosition,
+ const OUString& sIndexName) override;
+ public:
+ Indexes(Table* pTable,
+ ::osl::Mutex& rMutex,
+ const std::vector< OUString>& rVector);
+ };
+
+} // namespace connectivity::firebird
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/connectivity/source/drivers/firebird/Keys.cxx b/connectivity/source/drivers/firebird/Keys.cxx
new file mode 100644
index 0000000000..8de112ec6f
--- /dev/null
+++ b/connectivity/source/drivers/firebird/Keys.cxx
@@ -0,0 +1,54 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "Keys.hxx"
+#include "Table.hxx"
+
+#include <connectivity/dbtools.hxx>
+
+using namespace ::connectivity;
+using namespace ::connectivity::firebird;
+
+using namespace ::dbtools;
+using namespace ::osl;
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::uno;
+
+Keys::Keys(Table* pTable, Mutex& rMutex, const ::std::vector< OUString>& rNames):
+ OKeysHelper(pTable,
+ rMutex,
+ rNames),
+ m_pTable(pTable)
+{
+}
+
+//----- XDrop ----------------------------------------------------------------
+void Keys::dropObject(sal_Int32 nPosition, const OUString& sName)
+{
+ if (m_pTable->isNew())
+ return;
+
+ uno::Reference<XPropertySet> xKey(getObject(nPosition), UNO_QUERY);
+
+ if (xKey.is())
+ {
+ const OUString sQuote = m_pTable->getConnection()->getMetaData()
+ ->getIdentifierQuoteString();
+
+ OUString sSql("ALTER TABLE " + quoteName(sQuote, m_pTable->getName())
+ + " DROP CONSTRAINT " + quoteName(sQuote, sName));
+
+ m_pTable->getConnection()->createStatement()->execute(sSql);
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/connectivity/source/drivers/firebird/Keys.hxx b/connectivity/source/drivers/firebird/Keys.hxx
new file mode 100644
index 0000000000..4e9ba5a7ee
--- /dev/null
+++ b/connectivity/source/drivers/firebird/Keys.hxx
@@ -0,0 +1,36 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include <connectivity/TKeys.hxx>
+
+namespace connectivity::firebird
+ {
+
+ class Table;
+
+ class Keys: public ::connectivity::OKeysHelper
+ {
+ private:
+ Table* m_pTable;
+
+ public:
+ Keys(Table* pTable,
+ ::osl::Mutex& rMutex,
+ const ::std::vector< OUString>& rNames);
+
+ // OKeysHelper / XDrop
+ void dropObject(sal_Int32 nPosition, const OUString& sName) override;
+
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/connectivity/source/drivers/firebird/PreparedStatement.cxx b/connectivity/source/drivers/firebird/PreparedStatement.cxx
new file mode 100644
index 0000000000..608d05c274
--- /dev/null
+++ b/connectivity/source/drivers/firebird/PreparedStatement.cxx
@@ -0,0 +1,1058 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+#include <cmath>
+
+#include "Connection.hxx"
+#include "PreparedStatement.hxx"
+#include "ResultSet.hxx"
+#include "ResultSetMetaData.hxx"
+#include "Util.hxx"
+
+#include <comphelper/sequence.hxx>
+#include <connectivity/dbexception.hxx>
+#include <propertyids.hxx>
+#include <connectivity/dbtools.hxx>
+#include <sal/log.hxx>
+
+#include <com/sun/star/sdbc/DataType.hpp>
+
+using namespace connectivity::firebird;
+
+using namespace ::comphelper;
+using namespace ::osl;
+
+using namespace com::sun::star;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::sdbc;
+using namespace com::sun::star::container;
+using namespace com::sun::star::io;
+using namespace com::sun::star::util;
+
+IMPLEMENT_SERVICE_INFO(OPreparedStatement,"com.sun.star.sdbcx.firebird.PreparedStatement","com.sun.star.sdbc.PreparedStatement");
+
+constexpr size_t MAX_SIZE_SEGMENT = 65535; // max value of a segment of CLOB, if we want more than 65535 bytes, we need more segments
+
+
+OPreparedStatement::OPreparedStatement( Connection* _pConnection,
+ const OUString& sql)
+ :OStatementCommonBase(_pConnection)
+ ,m_sSqlStatement(sql)
+ ,m_pOutSqlda(nullptr)
+ ,m_pInSqlda(nullptr)
+{
+ SAL_INFO("connectivity.firebird", "OPreparedStatement(). "
+ "sql: " << sql);
+}
+
+void OPreparedStatement::ensurePrepared()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OStatementCommonBase_Base::rBHelper.bDisposed);
+
+ if (m_aStatementHandle)
+ return;
+
+ ISC_STATUS aErr = 0;
+
+ if (!m_pInSqlda)
+ {
+ m_pInSqlda = static_cast<XSQLDA*>(calloc(1, XSQLDA_LENGTH(10)));
+ m_pInSqlda->version = SQLDA_VERSION1;
+ m_pInSqlda->sqln = 10;
+ }
+
+ prepareAndDescribeStatement(m_sSqlStatement, m_pOutSqlda);
+
+ aErr = isc_dsql_describe_bind(m_statusVector,
+ &m_aStatementHandle,
+ 1,
+ m_pInSqlda);
+
+ if (aErr)
+ {
+ SAL_WARN("connectivity.firebird", "isc_dsql_describe_bind failed");
+ }
+ else if (m_pInSqlda->sqld > m_pInSqlda->sqln) // Not large enough
+ {
+ short nItems = m_pInSqlda->sqld;
+ free(m_pInSqlda);
+ m_pInSqlda = static_cast<XSQLDA*>(calloc(1, XSQLDA_LENGTH(nItems)));
+ m_pInSqlda->version = SQLDA_VERSION1;
+ m_pInSqlda->sqln = nItems;
+ aErr = isc_dsql_describe_bind(m_statusVector,
+ &m_aStatementHandle,
+ 1,
+ m_pInSqlda);
+ SAL_WARN_IF(aErr, "connectivity.firebird", "isc_dsql_describe_bind failed");
+ }
+
+ if (!aErr)
+ mallocSQLVAR(m_pInSqlda);
+ else
+ evaluateStatusVector(m_statusVector, m_sSqlStatement, *this);
+}
+
+OPreparedStatement::~OPreparedStatement()
+{
+}
+
+void SAL_CALL OPreparedStatement::acquire() noexcept
+{
+ OStatementCommonBase::acquire();
+}
+
+void SAL_CALL OPreparedStatement::release() noexcept
+{
+ OStatementCommonBase::release();
+}
+
+Any SAL_CALL OPreparedStatement::queryInterface(const Type& rType)
+{
+ Any aRet = OStatementCommonBase::queryInterface(rType);
+ if(!aRet.hasValue())
+ aRet = OPreparedStatement_Base::queryInterface(rType);
+ return aRet;
+}
+
+uno::Sequence< Type > SAL_CALL OPreparedStatement::getTypes()
+{
+ return concatSequences(OPreparedStatement_Base::getTypes(),
+ OStatementCommonBase::getTypes());
+}
+
+Reference< XResultSetMetaData > SAL_CALL OPreparedStatement::getMetaData()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OStatementCommonBase_Base::rBHelper.bDisposed);
+ ensurePrepared();
+
+ if(!m_xMetaData.is())
+ m_xMetaData = new OResultSetMetaData(m_pConnection.get()
+ , m_pOutSqlda);
+
+ return m_xMetaData;
+}
+
+void SAL_CALL OPreparedStatement::close()
+{
+ MutexGuard aGuard( m_aMutex );
+ checkDisposed(OStatementCommonBase_Base::rBHelper.bDisposed);
+
+ OStatementCommonBase::close();
+ if (m_pInSqlda)
+ {
+ freeSQLVAR(m_pInSqlda);
+ free(m_pInSqlda);
+ m_pInSqlda = nullptr;
+ }
+ if (m_pOutSqlda)
+ {
+ freeSQLVAR(m_pOutSqlda);
+ free(m_pOutSqlda);
+ m_pOutSqlda = nullptr;
+ }
+}
+
+void SAL_CALL OPreparedStatement::disposing()
+{
+ close();
+}
+
+void SAL_CALL OPreparedStatement::setString(sal_Int32 nParameterIndex,
+ const OUString& sInput)
+{
+ SAL_INFO("connectivity.firebird",
+ "setString(" << nParameterIndex << " , " << sInput << ")");
+
+ MutexGuard aGuard( m_aMutex );
+ checkDisposed(OStatementCommonBase_Base::rBHelper.bDisposed);
+ ensurePrepared();
+
+ checkParameterIndex(nParameterIndex);
+ setParameterNull(nParameterIndex, false);
+
+ OString str = OUStringToOString(sInput , RTL_TEXTENCODING_UTF8 );
+
+ XSQLVAR* pVar = m_pInSqlda->sqlvar + (nParameterIndex - 1);
+
+ int dtype = (pVar->sqltype & ~1); // drop flag bit for now
+
+ if (str.getLength() > pVar->sqllen)
+ str = str.copy(0, pVar->sqllen);
+
+ switch (dtype) {
+ case SQL_VARYING:
+ {
+ const sal_Int32 max_varchar_len = 0xFFFF;
+ // First 2 bytes indicate string size
+ if (str.getLength() > max_varchar_len)
+ {
+ str = str.copy(0, max_varchar_len);
+ }
+ const sal_uInt16 nLength = str.getLength();
+ static_assert(sizeof(nLength) == 2, "must match dest memcpy len");
+ memcpy(pVar->sqldata, &nLength, 2);
+ // Actual data
+ memcpy(pVar->sqldata + 2, str.getStr(), str.getLength());
+ break;
+ }
+ case SQL_TEXT:
+ memcpy(pVar->sqldata, str.getStr(), str.getLength());
+ // Fill remainder with spaces
+ memset(pVar->sqldata + str.getLength(), ' ', pVar->sqllen - str.getLength());
+ break;
+ case SQL_BLOB: // Clob
+ assert( pVar->sqlsubtype == static_cast<short>(BlobSubtype::Clob) );
+ setClob(nParameterIndex, sInput );
+ break;
+ case SQL_SHORT:
+ {
+ sal_Int32 int32Value = sInput.toInt32();
+ if ( (int32Value < std::numeric_limits<sal_Int16>::min()) ||
+ (int32Value > std::numeric_limits<sal_Int16>::max()) )
+ {
+ ::dbtools::throwSQLException(
+ "Value out of range for SQL_SHORT type",
+ ::dbtools::StandardSQLState::INVALID_SQL_DATA_TYPE,
+ *this);
+ }
+ setShort(nParameterIndex, int32Value);
+ break;
+ }
+ case SQL_LONG:
+ {
+ sal_Int32 int32Value = sInput.toInt32();
+ setInt(nParameterIndex, int32Value);
+ break;
+ }
+ case SQL_INT64:
+ {
+ sal_Int64 int64Value = sInput.toInt64();
+ setLong(nParameterIndex, int64Value);
+ break;
+ }
+ case SQL_FLOAT:
+ {
+ float floatValue = sInput.toFloat();
+ setFloat(nParameterIndex, floatValue);
+ break;
+ }
+ case SQL_BOOLEAN:
+ {
+ bool boolValue = sInput.toBoolean();
+ setBoolean(nParameterIndex, boolValue);
+ break;
+ }
+ case SQL_NULL:
+ {
+ // See https://www.firebirdsql.org/file/documentation/html/en/refdocs/fblangref25/firebird-25-language-reference.html#fblangref25-datatypes-special-sqlnull
+ pVar->sqldata = nullptr;
+ break;
+ }
+ default:
+ ::dbtools::throwSQLException(
+ "Incorrect type for setString",
+ ::dbtools::StandardSQLState::INVALID_SQL_DATA_TYPE,
+ *this);
+ }
+}
+
+Reference< XConnection > SAL_CALL OPreparedStatement::getConnection()
+{
+ MutexGuard aGuard( m_aMutex );
+ checkDisposed(OStatementCommonBase_Base::rBHelper.bDisposed);
+
+ return m_pConnection;
+}
+
+sal_Bool SAL_CALL OPreparedStatement::execute()
+{
+ SAL_INFO("connectivity.firebird", "executeQuery(). "
+ "Got called with sql: " << m_sSqlStatement);
+
+ MutexGuard aGuard( m_aMutex );
+ checkDisposed(OStatementCommonBase_Base::rBHelper.bDisposed);
+
+ ensurePrepared();
+
+ ISC_STATUS aErr;
+
+ if (m_xResultSet.is()) // Checks whether we have already run the statement.
+ {
+ disposeResultSet();
+ // Closes the cursor from the last run.
+ // This doesn't actually free the statement -- using DSQL_close closes
+ // the cursor and keeps the statement, using DSQL_drop frees the statement
+ // (and associated cursors).
+ aErr = isc_dsql_free_statement(m_statusVector,
+ &m_aStatementHandle,
+ DSQL_close);
+ if (aErr)
+ {
+ // Do not throw error. Trying to close a closed cursor is not a
+ // critical mistake.
+ OUString sErrMsg = StatusVectorToString(m_statusVector,
+ u"isc_dsql_free_statement: close cursor");
+ SAL_WARN("connectivity.firebird", sErrMsg);
+ }
+ }
+
+ aErr = isc_dsql_execute(m_statusVector,
+ &m_pConnection->getTransaction(),
+ &m_aStatementHandle,
+ 1,
+ m_pInSqlda);
+ if (aErr)
+ {
+ SAL_WARN("connectivity.firebird", "isc_dsql_execute failed" );
+ evaluateStatusVector(m_statusVector, u"isc_dsql_execute", *this);
+ }
+
+ m_xResultSet = new OResultSet(m_pConnection.get(),
+ m_aMutex,
+ uno::Reference< XInterface >(*this),
+ m_aStatementHandle,
+ m_pOutSqlda);
+
+ if (getStatementChangeCount() > 0)
+ m_pConnection->notifyDatabaseModified();
+
+ return m_xResultSet.is();
+ // TODO: implement handling of multiple ResultSets.
+}
+
+sal_Int32 SAL_CALL OPreparedStatement::executeUpdate()
+{
+ execute();
+ return getStatementChangeCount();
+}
+
+Reference< XResultSet > SAL_CALL OPreparedStatement::executeQuery()
+{
+ execute();
+ return m_xResultSet;
+}
+
+namespace {
+
+/**
+ * Take out the number part of a fix point decimal without
+ * the information of where is the fractional part from a
+ * string representation of a number. (e.g. 54.654 -> 54654)
+ */
+sal_Int64 toNumericWithoutDecimalPlace(const OUString& sSource)
+{
+ OUString sNumber(sSource);
+
+ // cut off leading 0 eventually ( eg. 0.567 -> .567)
+ (void)sSource.startsWith("0", &sNumber);
+
+ sal_Int32 nDotIndex = sNumber.indexOf('.');
+
+ if( nDotIndex < 0)
+ {
+ return sNumber.toInt64(); // no dot -> it's an integer
+ }
+ else
+ {
+ // remove dot
+ OUStringBuffer sBuffer(15);
+ if(nDotIndex > 0)
+ {
+ sBuffer.append(sNumber.subView(0, nDotIndex));
+ }
+ sBuffer.append(sNumber.subView(nDotIndex + 1));
+ return o3tl::toInt64(sBuffer);
+ }
+}
+
+}
+
+//----- XParameters -----------------------------------------------------------
+void SAL_CALL OPreparedStatement::setNull(sal_Int32 nIndex, sal_Int32 /*nSqlType*/)
+{
+ MutexGuard aGuard( m_aMutex );
+ checkDisposed(OStatementCommonBase_Base::rBHelper.bDisposed);
+ ensurePrepared();
+
+ checkParameterIndex(nIndex);
+ setParameterNull(nIndex);
+}
+
+void SAL_CALL OPreparedStatement::setBoolean(sal_Int32 nIndex, sal_Bool bValue)
+{
+ setValue< sal_Bool >(nIndex, bValue, SQL_BOOLEAN);
+}
+
+template <typename T>
+void OPreparedStatement::setValue(sal_Int32 nIndex, const T& nValue, ISC_SHORT nType)
+{
+ MutexGuard aGuard( m_aMutex );
+ checkDisposed(OStatementCommonBase_Base::rBHelper.bDisposed);
+ ensurePrepared();
+
+ checkParameterIndex(nIndex);
+ setParameterNull(nIndex, false);
+
+ XSQLVAR* pVar = m_pInSqlda->sqlvar + (nIndex - 1);
+
+ if ((pVar->sqltype & ~1) != nType)
+ {
+ ::dbtools::throwSQLException(
+ "Incorrect type for setValue",
+ ::dbtools::StandardSQLState::INVALID_SQL_DATA_TYPE,
+ *this);
+ }
+
+ memcpy(pVar->sqldata, &nValue, sizeof(nValue));
+}
+
+void SAL_CALL OPreparedStatement::setByte(sal_Int32 nIndex, sal_Int8 nValue)
+{
+ // there's no TINYINT or equivalent on Firebird,
+ // so do the same as setShort
+ setValue< sal_Int16 >(nIndex, nValue, SQL_SHORT);
+}
+
+void SAL_CALL OPreparedStatement::setShort(sal_Int32 nIndex, sal_Int16 nValue)
+{
+ setValue< sal_Int16 >(nIndex, nValue, SQL_SHORT);
+}
+
+void SAL_CALL OPreparedStatement::setInt(sal_Int32 nIndex, sal_Int32 nValue)
+{
+ setValue< sal_Int32 >(nIndex, nValue, SQL_LONG);
+}
+
+void SAL_CALL OPreparedStatement::setLong(sal_Int32 nIndex, sal_Int64 nValue)
+{
+ setValue< sal_Int64 >(nIndex, nValue, SQL_INT64);
+}
+
+void SAL_CALL OPreparedStatement::setFloat(sal_Int32 nIndex, float nValue)
+{
+ setValue< float >(nIndex, nValue, SQL_FLOAT);
+}
+
+void SAL_CALL OPreparedStatement::setDouble(sal_Int32 nIndex, double nValue)
+{
+ MutexGuard aGuard( m_aMutex );
+ checkDisposed(OStatementCommonBase_Base::rBHelper.bDisposed);
+ ensurePrepared();
+
+ XSQLVAR* pVar = m_pInSqlda->sqlvar + (nIndex - 1);
+ short dType = (pVar->sqltype & ~1); // drop flag bit for now
+ short dSubType = pVar->sqlsubtype;
+ // Assume it is a sub type of a number.
+ if(dSubType < 0 || dSubType > 2)
+ {
+ ::dbtools::throwSQLException(
+ "Incorrect number sub type",
+ ::dbtools::StandardSQLState::INVALID_SQL_DATA_TYPE,
+ *this);
+ }
+ // firebird stores scale as a negative number
+ ColumnTypeInfo columnType{ dType, dSubType,
+ static_cast<short>(-pVar->sqlscale) };
+
+ // Caller might try to set an integer type here. It makes sense to convert
+ // it instead of throwing an error.
+ switch(columnType.getSdbcType())
+ {
+ case DataType::SMALLINT:
+ setValue< sal_Int16 >(nIndex,
+ static_cast<sal_Int16>(nValue),
+ dType);
+ break;
+ case DataType::INTEGER:
+ setValue< sal_Int32 >(nIndex,
+ static_cast<sal_Int32>(nValue),
+ dType);
+ break;
+ case DataType::BIGINT:
+ setValue< sal_Int64 >(nIndex,
+ static_cast<sal_Int64>(nValue),
+ dType);
+ break;
+ case DataType::NUMERIC:
+ case DataType::DECIMAL:
+ // take decimal places into account, later on they are removed in makeNumericString
+ setObjectWithInfo(nIndex,Any{nValue}, columnType.getSdbcType(), columnType.getScale());
+ break;
+ default:
+ setValue< double >(nIndex, nValue, SQL_DOUBLE); // TODO: SQL_D_FLOAT?
+ }
+}
+
+void SAL_CALL OPreparedStatement::setDate(sal_Int32 nIndex, const Date& rDate)
+{
+ struct tm aCTime;
+ aCTime.tm_mday = rDate.Day;
+ aCTime.tm_mon = rDate.Month -1;
+ aCTime.tm_year = rDate.Year -1900;
+
+ ISC_DATE aISCDate;
+ isc_encode_sql_date(&aCTime, &aISCDate);
+
+ setValue< ISC_DATE >(nIndex, aISCDate, SQL_TYPE_DATE);
+}
+
+void SAL_CALL OPreparedStatement::setTime( sal_Int32 nIndex, const css::util::Time& rTime)
+{
+ struct tm aCTime;
+ aCTime.tm_sec = rTime.Seconds;
+ aCTime.tm_min = rTime.Minutes;
+ aCTime.tm_hour = rTime.Hours;
+
+ ISC_TIME aISCTime;
+ isc_encode_sql_time(&aCTime, &aISCTime);
+
+ // Here we "know" that ISC_TIME is simply in units of seconds/ISC_TIME_SECONDS_PRECISION with no
+ // other funkiness, so we can simply add the fraction of a second.
+ aISCTime += rTime.NanoSeconds / (1000000000 / ISC_TIME_SECONDS_PRECISION);
+
+ setValue< ISC_TIME >(nIndex, aISCTime, SQL_TYPE_TIME);
+}
+
+void SAL_CALL OPreparedStatement::setTimestamp(sal_Int32 nIndex, const DateTime& rTimestamp)
+{
+ struct tm aCTime;
+ aCTime.tm_sec = rTimestamp.Seconds;
+ aCTime.tm_min = rTimestamp.Minutes;
+ aCTime.tm_hour = rTimestamp.Hours;
+ aCTime.tm_mday = rTimestamp.Day;
+ aCTime.tm_mon = rTimestamp.Month - 1;
+ aCTime.tm_year = rTimestamp.Year - 1900;
+
+ ISC_TIMESTAMP aISCTimestamp;
+ isc_encode_timestamp(&aCTime, &aISCTimestamp);
+
+ // As in previous function
+ aISCTimestamp.timestamp_time += rTimestamp.NanoSeconds / (1000000000 / ISC_TIME_SECONDS_PRECISION);
+
+ setValue< ISC_TIMESTAMP >(nIndex, aISCTimestamp, SQL_TIMESTAMP);
+}
+
+
+// void OPreparedStatement::set
+void OPreparedStatement::openBlobForWriting(isc_blob_handle& rBlobHandle, ISC_QUAD& rBlobId)
+{
+ ISC_STATUS aErr;
+
+ aErr = isc_create_blob2(m_statusVector,
+ &m_pConnection->getDBHandle(),
+ &m_pConnection->getTransaction(),
+ &rBlobHandle,
+ &rBlobId,
+ 0, // Blob parameter buffer length
+ nullptr); // Blob parameter buffer handle
+
+ if (aErr)
+ {
+ evaluateStatusVector(m_statusVector,
+ Concat2View("setBlob failed on " + m_sSqlStatement),
+ *this);
+ assert(false);
+ }
+}
+
+void OPreparedStatement::closeBlobAfterWriting(isc_blob_handle& rBlobHandle)
+{
+ ISC_STATUS aErr;
+
+ aErr = isc_close_blob(m_statusVector,
+ &rBlobHandle);
+ if (aErr)
+ {
+ evaluateStatusVector(m_statusVector,
+ u"isc_close_blob failed",
+ *this);
+ assert(false);
+ }
+}
+
+void SAL_CALL OPreparedStatement::setClob(sal_Int32 nParameterIndex, const Reference< XClob >& xClob )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OStatementCommonBase_Base::rBHelper.bDisposed);
+
+#if SAL_TYPES_SIZEOFPOINTER == 8
+ isc_blob_handle aBlobHandle = 0;
+#else
+ isc_blob_handle aBlobHandle = nullptr;
+#endif
+ ISC_QUAD aBlobId;
+
+ openBlobForWriting(aBlobHandle, aBlobId);
+
+
+ // Max segment size is 2^16 == SAL_MAX_UINT16
+ // SAL_MAX_UINT16 / 4 is surely enough for UTF-8
+ // TODO apply max segment size to character encoding
+ sal_Int64 nCharWritten = 1; // XClob is indexed from 1
+ ISC_STATUS aErr = 0;
+ sal_Int64 nLen = xClob->length();
+ while ( nLen >= nCharWritten )
+ {
+ sal_Int64 nCharRemain = nLen - nCharWritten + 1;
+ constexpr sal_uInt16 MAX_SIZE = SAL_MAX_UINT16 / 4;
+ sal_uInt16 nWriteSize = std::min<sal_Int64>(nCharRemain, MAX_SIZE);
+ OString sData = OUStringToOString(
+ xClob->getSubString(nCharWritten, nWriteSize),
+ RTL_TEXTENCODING_UTF8);
+ aErr = isc_put_segment( m_statusVector,
+ &aBlobHandle,
+ sData.getLength(),
+ sData.getStr() );
+ nCharWritten += nWriteSize;
+
+ if (aErr)
+ break;
+ }
+
+ // We need to make sure we close the Blob even if there are errors, hence evaluate
+ // errors after closing.
+ closeBlobAfterWriting(aBlobHandle);
+
+ if (aErr)
+ {
+ evaluateStatusVector(m_statusVector,
+ u"isc_put_segment failed",
+ *this);
+ assert(false);
+ }
+
+ setValue< ISC_QUAD >(nParameterIndex, aBlobId, SQL_BLOB);
+}
+
+void OPreparedStatement::setClob( sal_Int32 nParameterIndex, const OUString& rStr )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OStatementCommonBase_Base::rBHelper.bDisposed);
+ checkParameterIndex(nParameterIndex);
+
+#if SAL_TYPES_SIZEOFPOINTER == 8
+ isc_blob_handle aBlobHandle = 0;
+#else
+ isc_blob_handle aBlobHandle = nullptr;
+#endif
+ ISC_QUAD aBlobId;
+
+ openBlobForWriting(aBlobHandle, aBlobId);
+
+ OString sData = OUStringToOString(
+ rStr,
+ RTL_TEXTENCODING_UTF8);
+ size_t nDataSize = sData.getLength();
+ ISC_STATUS aErr = 0;
+ // we can't store more than MAX_SIZE_SEGMENT in a segment
+ if (nDataSize <= MAX_SIZE_SEGMENT)
+ {
+ aErr = isc_put_segment( m_statusVector,
+ &aBlobHandle,
+ sData.getLength(),
+ sData.getStr() );
+ }
+ else
+ {
+ // if we need more, let's split the input and first let's calculate the nb of entire chunks needed
+ size_t nNbEntireChunks = nDataSize / MAX_SIZE_SEGMENT;
+ for (size_t i = 0; i < nNbEntireChunks; ++i)
+ {
+ OString strCurrentChunk = sData.copy(i * MAX_SIZE_SEGMENT, MAX_SIZE_SEGMENT);
+ aErr = isc_put_segment( m_statusVector,
+ &aBlobHandle,
+ strCurrentChunk.getLength(),
+ strCurrentChunk.getStr() );
+ if (aErr)
+ break;
+ }
+ size_t nRemainingBytes = nDataSize - (nNbEntireChunks * MAX_SIZE_SEGMENT);
+ if (nRemainingBytes && !aErr)
+ {
+ // then copy the remaining
+ OString strCurrentChunk = sData.copy(nNbEntireChunks * MAX_SIZE_SEGMENT, nRemainingBytes);
+ aErr = isc_put_segment( m_statusVector,
+ &aBlobHandle,
+ strCurrentChunk.getLength(),
+ strCurrentChunk.getStr() );
+ }
+ }
+
+ // We need to make sure we close the Blob even if there are errors, hence evaluate
+ // errors after closing.
+ closeBlobAfterWriting(aBlobHandle);
+
+ if (aErr)
+ {
+ evaluateStatusVector(m_statusVector,
+ u"isc_put_segment failed",
+ *this);
+ assert(false);
+ }
+
+ setValue< ISC_QUAD >(nParameterIndex, aBlobId, SQL_BLOB);
+}
+
+void SAL_CALL OPreparedStatement::setBlob(sal_Int32 nParameterIndex,
+ const Reference< XBlob >& xBlob)
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(OStatementCommonBase_Base::rBHelper.bDisposed);
+ checkParameterIndex(nParameterIndex);
+
+#if SAL_TYPES_SIZEOFPOINTER == 8
+ isc_blob_handle aBlobHandle = 0;
+#else
+ isc_blob_handle aBlobHandle = nullptr;
+#endif
+ ISC_QUAD aBlobId;
+
+ openBlobForWriting(aBlobHandle, aBlobId);
+
+ ISC_STATUS aErr = 0;
+ const sal_Int64 nBlobLen = xBlob->length();
+ if (nBlobLen > 0)
+ {
+ // Max write size is 0xFFFF == SAL_MAX_UINT16
+ sal_uInt64 nDataWritten = 0;
+ while (sal::static_int_cast<sal_uInt64>(nBlobLen) > nDataWritten)
+ {
+ sal_uInt64 nDataRemaining = nBlobLen - nDataWritten;
+ sal_uInt16 nWriteSize = std::min(nDataRemaining, sal_uInt64(SAL_MAX_UINT16));
+ aErr = isc_put_segment(m_statusVector,
+ &aBlobHandle,
+ nWriteSize,
+ reinterpret_cast<const char*>(xBlob->getBytes(nDataWritten, nWriteSize).getConstArray()));
+ nDataWritten += nWriteSize;
+
+ if (aErr)
+ break;
+ }
+ }
+
+ // We need to make sure we close the Blob even if there are errors, hence evaluate
+ // errors after closing.
+ closeBlobAfterWriting(aBlobHandle);
+
+ if (aErr)
+ {
+ evaluateStatusVector(m_statusVector,
+ u"isc_put_segment failed",
+ *this);
+ assert(false);
+ }
+
+ setValue< ISC_QUAD >(nParameterIndex, aBlobId, SQL_BLOB);
+}
+
+
+void SAL_CALL OPreparedStatement::setArray( sal_Int32 nIndex, const Reference< XArray >& )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OStatementCommonBase_Base::rBHelper.bDisposed);
+ checkParameterIndex(nIndex);
+}
+
+
+void SAL_CALL OPreparedStatement::setRef( sal_Int32 nIndex, const Reference< XRef >& )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OStatementCommonBase_Base::rBHelper.bDisposed);
+ checkParameterIndex(nIndex);
+}
+
+
+void SAL_CALL OPreparedStatement::setObjectWithInfo( sal_Int32 parameterIndex, const Any& x, sal_Int32 sqlType, sal_Int32 scale )
+{
+ checkDisposed(OStatementCommonBase_Base::rBHelper.bDisposed);
+ ::osl::MutexGuard aGuard( m_aMutex );
+ ensurePrepared();
+
+ checkParameterIndex(parameterIndex);
+ setParameterNull(parameterIndex, false);
+
+ XSQLVAR* pVar = m_pInSqlda->sqlvar + (parameterIndex - 1);
+ int dType = (pVar->sqltype & ~1); // drop null flag
+
+ if(sqlType == DataType::DECIMAL || sqlType == DataType::NUMERIC)
+ {
+ double dbValue =0.0;
+ OUString sValue;
+ if( x >>= dbValue )
+ {
+ // truncate and round to 'scale' number of decimal places
+ sValue = OUString::number( std::floor((dbValue * pow10Integer(scale)) + .5) / pow10Integer(scale) );
+ }
+ else
+ {
+ x >>= sValue;
+ }
+
+ // fill in the number with nulls in fractional part.
+ // We need this because e.g. 0.450 != 0.045 despite
+ // their scale is equal
+ OUStringBuffer sBuffer(15);
+ sBuffer.append(sValue);
+ if(sValue.indexOf('.') != -1) // there is a dot
+ {
+ for(sal_Int32 i=sValue.subView(sValue.indexOf('.')+1).size(); i<scale;i++)
+ {
+ sBuffer.append('0');
+ }
+ }
+ else
+ {
+ for (sal_Int32 i=0; i<scale; i++)
+ {
+ sBuffer.append('0');
+ }
+ }
+
+ sValue = sBuffer.makeStringAndClear();
+ switch(dType)
+ {
+ case SQL_SHORT:
+ setValue< sal_Int16 >(parameterIndex,
+ static_cast<sal_Int16>( toNumericWithoutDecimalPlace(sValue) ),
+ dType);
+ break;
+ case SQL_LONG:
+ case SQL_DOUBLE:
+ setValue< sal_Int32 >(parameterIndex,
+ static_cast<sal_Int32>( toNumericWithoutDecimalPlace(sValue) ),
+ dType);
+ break;
+ case SQL_INT64:
+ setValue< sal_Int64 >(parameterIndex,
+ toNumericWithoutDecimalPlace(sValue),
+ dType);
+ break;
+ default:
+ SAL_WARN("connectivity.firebird",
+ "No Firebird sql type found for numeric or decimal types");
+ ::dbtools::setObjectWithInfo(this,parameterIndex,x,sqlType,scale);
+ }
+ }
+ else
+ {
+ ::dbtools::setObjectWithInfo(this,parameterIndex,x,sqlType,scale);
+ }
+
+}
+
+
+void SAL_CALL OPreparedStatement::setObjectNull( sal_Int32 nIndex, sal_Int32, const OUString& )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OStatementCommonBase_Base::rBHelper.bDisposed);
+ checkParameterIndex(nIndex);
+}
+
+
+void SAL_CALL OPreparedStatement::setObject( sal_Int32 nIndex, const Any& )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OStatementCommonBase_Base::rBHelper.bDisposed);
+ checkParameterIndex(nIndex);
+}
+
+void SAL_CALL OPreparedStatement::setBytes(sal_Int32 nParameterIndex,
+ const Sequence< sal_Int8 >& xBytes)
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(OStatementCommonBase_Base::rBHelper.bDisposed);
+ checkParameterIndex(nParameterIndex);
+
+ XSQLVAR* pVar = m_pInSqlda->sqlvar + (nParameterIndex - 1);
+ int dType = (pVar->sqltype & ~1); // drop flag bit for now
+
+ if( dType == SQL_BLOB )
+ {
+#if SAL_TYPES_SIZEOFPOINTER == 8
+ isc_blob_handle aBlobHandle = 0;
+#else
+ isc_blob_handle aBlobHandle = nullptr;
+#endif
+ ISC_QUAD aBlobId;
+
+ openBlobForWriting(aBlobHandle, aBlobId);
+
+ ISC_STATUS aErr = 0;
+ const sal_Int32 nBytesLen = xBytes.getLength();
+ if (nBytesLen > 0)
+ {
+ // Max write size is 0xFFFF == SAL_MAX_UINT16
+ sal_uInt32 nDataWritten = 0;
+ while (sal::static_int_cast<sal_uInt32>(nBytesLen) > nDataWritten)
+ {
+ sal_uInt32 nDataRemaining = nBytesLen - nDataWritten;
+ sal_uInt16 nWriteSize = std::min(nDataRemaining, sal_uInt32(SAL_MAX_UINT16));
+ aErr = isc_put_segment(m_statusVector,
+ &aBlobHandle,
+ nWriteSize,
+ reinterpret_cast<const char*>(xBytes.getConstArray()) + nDataWritten);
+ nDataWritten += nWriteSize;
+
+ if (aErr)
+ break;
+ }
+ }
+
+ // We need to make sure we close the Blob even if there are errors, hence evaluate
+ // errors after closing.
+ closeBlobAfterWriting(aBlobHandle);
+
+ if (aErr)
+ {
+ evaluateStatusVector(m_statusVector,
+ u"isc_put_segment failed",
+ *this);
+ assert(false);
+ }
+
+ setValue< ISC_QUAD >(nParameterIndex, aBlobId, SQL_BLOB);
+ }
+ else if( dType == SQL_VARYING )
+ {
+ setParameterNull(nParameterIndex, false);
+ const sal_Int32 nMaxSize = 0xFFFF;
+ Sequence<sal_Int8> xBytesCopy(xBytes);
+ if (xBytesCopy.getLength() > nMaxSize)
+ {
+ xBytesCopy.realloc( nMaxSize );
+ }
+ const sal_uInt16 nSize = xBytesCopy.getLength();
+ // 8000 corresponds to value from lcl_addDefaultParameters
+ // in dbaccess/source/filter/hsqldb/createparser.cxx
+ if (nSize > 8000)
+ {
+ free(pVar->sqldata);
+ pVar->sqldata = static_cast<char *>(malloc(sizeof(char) * nSize + 2));
+ }
+ static_assert(sizeof(nSize) == 2, "must match dest memcpy len");
+ // First 2 bytes indicate string size
+ memcpy(pVar->sqldata, &nSize, 2);
+ // Actual data
+ memcpy(pVar->sqldata + 2, xBytesCopy.getConstArray(), nSize);
+ }
+ else if( dType == SQL_TEXT )
+ {
+ if (pVar->sqllen < xBytes.getLength())
+ dbtools::throwSQLException("Data too big for this field",
+ dbtools::StandardSQLState::INVALID_SQL_DATA_TYPE, *this);
+ setParameterNull(nParameterIndex, false);
+ memcpy(pVar->sqldata, xBytes.getConstArray(), xBytes.getLength() );
+ // Fill remainder with zeroes
+ memset(pVar->sqldata + xBytes.getLength(), 0, pVar->sqllen - xBytes.getLength());
+ }
+ else
+ {
+ ::dbtools::throwSQLException(
+ "Incorrect type for setBytes",
+ ::dbtools::StandardSQLState::INVALID_SQL_DATA_TYPE,
+ *this);
+ }
+}
+
+
+void SAL_CALL OPreparedStatement::setCharacterStream( sal_Int32 nIndex, const Reference< css::io::XInputStream >&, sal_Int32 )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OStatementCommonBase_Base::rBHelper.bDisposed);
+ checkParameterIndex(nIndex);
+}
+
+
+void SAL_CALL OPreparedStatement::setBinaryStream( sal_Int32 nIndex, const Reference< css::io::XInputStream >&, sal_Int32 )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OStatementCommonBase_Base::rBHelper.bDisposed);
+ checkParameterIndex(nIndex);
+}
+
+
+void SAL_CALL OPreparedStatement::clearParameters( )
+{
+}
+
+// ---- Batch methods -- unsupported -----------------------------------------
+void SAL_CALL OPreparedStatement::clearBatch()
+{
+ // Unsupported
+}
+
+void SAL_CALL OPreparedStatement::addBatch()
+{
+ // Unsupported by firebird
+}
+
+Sequence< sal_Int32 > SAL_CALL OPreparedStatement::executeBatch()
+{
+ // Unsupported by firebird
+ return Sequence< sal_Int32 >();
+}
+
+void OPreparedStatement::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,const Any& rValue)
+{
+ switch(nHandle)
+ {
+ case PROPERTY_ID_RESULTSETCONCURRENCY:
+ break;
+ case PROPERTY_ID_RESULTSETTYPE:
+ break;
+ case PROPERTY_ID_FETCHDIRECTION:
+ break;
+ case PROPERTY_ID_USEBOOKMARKS:
+ break;
+ default:
+ OStatementCommonBase::setFastPropertyValue_NoBroadcast(nHandle,rValue);
+ }
+}
+
+void OPreparedStatement::checkParameterIndex(sal_Int32 nParameterIndex)
+{
+ ensurePrepared();
+ if ((nParameterIndex == 0) || (nParameterIndex > m_pInSqlda->sqld))
+ {
+ ::dbtools::throwSQLException(
+ "No column " + OUString::number(nParameterIndex),
+ ::dbtools::StandardSQLState::COLUMN_NOT_FOUND,
+ *this);
+ }
+}
+
+void OPreparedStatement::setParameterNull(sal_Int32 nParameterIndex,
+ bool bSetNull)
+{
+ XSQLVAR* pVar = m_pInSqlda->sqlvar + (nParameterIndex - 1);
+ if (bSetNull)
+ {
+ pVar->sqltype |= 1;
+ *pVar->sqlind = -1;
+ }
+ else
+ *pVar->sqlind = 0;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/connectivity/source/drivers/firebird/PreparedStatement.hxx b/connectivity/source/drivers/firebird/PreparedStatement.hxx
new file mode 100644
index 0000000000..3e61436b58
--- /dev/null
+++ b/connectivity/source/drivers/firebird/PreparedStatement.hxx
@@ -0,0 +1,152 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "StatementCommonBase.hxx"
+
+#include <cppuhelper/implbase5.hxx>
+
+#include <com/sun/star/sdbc/XPreparedStatement.hpp>
+#include <com/sun/star/sdbc/XParameters.hpp>
+#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
+#include <com/sun/star/sdbc/XPreparedBatchExecution.hpp>
+#include <com/sun/star/io/XInputStream.hpp>
+
+#include <ibase.h>
+
+namespace connectivity::firebird
+ {
+
+ class OBoundParam;
+ typedef ::cppu::ImplHelper5< css::sdbc::XPreparedStatement,
+ css::sdbc::XParameters,
+ css::sdbc::XPreparedBatchExecution,
+ css::sdbc::XResultSetMetaDataSupplier,
+ css::lang::XServiceInfo> OPreparedStatement_Base;
+
+ class OPreparedStatement : public OStatementCommonBase,
+ public OPreparedStatement_Base
+ {
+ protected:
+ OUString m_sSqlStatement;
+ css::uno::Reference< css::sdbc::XResultSetMetaData > m_xMetaData;
+
+ XSQLDA* m_pOutSqlda;
+ XSQLDA* m_pInSqlda;
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void checkParameterIndex(sal_Int32 nParameterIndex);
+
+ /**
+ * Set a numeric value in the input SQLDA. If the destination
+ * parameter is not of nType then an Exception will be thrown.
+ *
+ * @throws css::sdbc::SQLException
+ * @throws css::uno::RuntimeException
+ */
+ template <typename T> void setValue(sal_Int32 nIndex, const T& nValue, ISC_SHORT nType);
+ void setParameterNull(sal_Int32 nParameterIndex, bool bSetNull = true);
+
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void ensurePrepared();
+ /**
+ * Assumes that all necessary mutexes have been taken.
+ */
+ void openBlobForWriting(isc_blob_handle& rBlobHandle, ISC_QUAD& rBlobId);
+ /**
+ * Assumes that all necessary mutexes have been taken.
+ */
+ void closeBlobAfterWriting(isc_blob_handle& rBlobHandle);
+ void setClob(sal_Int32 nParamIndex, const OUString& rStr);
+
+ protected:
+ virtual void SAL_CALL setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,
+ const css::uno::Any& rValue) override;
+ virtual ~OPreparedStatement() override;
+ public:
+ DECLARE_SERVICE_INFO();
+ // a constructor, which is required for returning objects:
+ OPreparedStatement( Connection* _pConnection,
+ const OUString& sql);
+
+ //XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+ //XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override;
+
+ // XPreparedStatement
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL
+ executeQuery() override;
+ virtual sal_Int32 SAL_CALL
+ executeUpdate() override;
+ virtual sal_Bool SAL_CALL
+ execute() override;
+ virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL
+ getConnection() override;
+
+ // XParameters
+ virtual void SAL_CALL setNull(sal_Int32 nIndex, sal_Int32 nValue) override;
+ virtual void SAL_CALL setObjectNull(sal_Int32 parameterIndex, sal_Int32 sqlType, const OUString& typeName ) override;
+ virtual void SAL_CALL setBoolean( sal_Int32 nIndex, sal_Bool nValue) override;
+ virtual void SAL_CALL setByte(sal_Int32 nIndex, sal_Int8 nValue) override;
+ virtual void SAL_CALL setShort(sal_Int32 nIndex, sal_Int16 nValue) override;
+ virtual void SAL_CALL setInt(sal_Int32 nIndex, sal_Int32 nValue) override;
+ virtual void SAL_CALL setLong(sal_Int32 nIndex, sal_Int64 nValue) override;
+ virtual void SAL_CALL setFloat( sal_Int32 parameterIndex, float x ) override;
+ virtual void SAL_CALL setDouble( sal_Int32 parameterIndex, double x ) override;
+ virtual void SAL_CALL setString( sal_Int32 parameterIndex, const OUString& x ) override;
+ virtual void SAL_CALL setBytes( sal_Int32 parameterIndex, const css::uno::Sequence< sal_Int8 >& x ) override;
+ virtual void SAL_CALL setDate( sal_Int32 parameterIndex, const css::util::Date& x ) override;
+ virtual void SAL_CALL setTime( sal_Int32 parameterIndex, const css::util::Time& x ) override;
+ virtual void SAL_CALL setTimestamp( sal_Int32 parameterIndex, const css::util::DateTime& x ) override;
+ virtual void SAL_CALL setBinaryStream( sal_Int32 parameterIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override;
+ virtual void SAL_CALL setCharacterStream( sal_Int32 parameterIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override;
+ virtual void SAL_CALL setObject( sal_Int32 parameterIndex, const css::uno::Any& x ) override;
+ virtual void SAL_CALL setObjectWithInfo( sal_Int32 parameterIndex, const css::uno::Any& x, sal_Int32 targetSqlType, sal_Int32 scale ) override;
+ virtual void SAL_CALL setRef( sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XRef >& x ) override;
+ virtual void SAL_CALL setBlob( sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XBlob >& x ) override;
+ virtual void SAL_CALL setClob( sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XClob >& x ) override;
+ virtual void SAL_CALL setArray( sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XArray >& x ) override;
+ virtual void SAL_CALL clearParameters( ) override;
+
+ // XPreparedBatchExecution -- UNSUPPORTED by firebird
+ virtual void SAL_CALL
+ addBatch() override;
+ virtual void SAL_CALL
+ clearBatch() override;
+ virtual css::uno::Sequence< sal_Int32 > SAL_CALL
+ executeBatch() override;
+
+ // XCloseable
+ virtual void SAL_CALL close() override;
+ // OComponentHelper
+ virtual void SAL_CALL disposing() override;
+
+ // XResultSetMetaDataSupplier
+ virtual css::uno::Reference< css::sdbc::XResultSetMetaData > SAL_CALL getMetaData( ) override;
+
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/connectivity/source/drivers/firebird/ResultSet.cxx b/connectivity/source/drivers/firebird/ResultSet.cxx
new file mode 100644
index 0000000000..ea3ac86ae7
--- /dev/null
+++ b/connectivity/source/drivers/firebird/ResultSet.cxx
@@ -0,0 +1,926 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "ResultSet.hxx"
+#include "ResultSetMetaData.hxx"
+#include "Util.hxx"
+
+#include <comphelper/sequence.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <connectivity/dbexception.hxx>
+#include <propertyids.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <sal/log.hxx>
+#include <TConnection.hxx>
+
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <com/sun/star/sdbc/FetchDirection.hpp>
+#include <com/sun/star/sdbc/ResultSetConcurrency.hpp>
+#include <com/sun/star/sdbc/ResultSetType.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
+
+using namespace ::comphelper;
+using namespace ::connectivity;
+using namespace ::connectivity::firebird;
+using namespace ::cppu;
+using namespace ::dbtools;
+using namespace ::osl;
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::io;
+using namespace ::com::sun::star::util;
+
+OResultSet::OResultSet(Connection* pConnection,
+ ::osl::Mutex& rMutex,
+ const uno::Reference< XInterface >& xStatement,
+ isc_stmt_handle aStatementHandle,
+ XSQLDA* pSqlda )
+ : OResultSet_BASE(rMutex)
+ , OPropertyContainer(OResultSet_BASE::rBHelper)
+ , m_bIsBookmarkable(false)
+ , m_nFetchSize(1)
+ , m_nResultSetType(css::sdbc::ResultSetType::FORWARD_ONLY)
+ , m_nFetchDirection(css::sdbc::FetchDirection::FORWARD)
+ , m_nResultSetConcurrency(css::sdbc::ResultSetConcurrency::READ_ONLY)
+ , m_pConnection(pConnection)
+ , m_rMutex(rMutex)
+ , m_xStatement(xStatement)
+ , m_pSqlda(pSqlda)
+ , m_statementHandle(aStatementHandle)
+ , m_bWasNull(false)
+ , m_currentRow(0)
+ , m_bIsAfterLastRow(false)
+ , m_fieldCount(pSqlda? pSqlda->sqld : 0)
+{
+ SAL_INFO("connectivity.firebird", "OResultSet().");
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISBOOKMARKABLE),
+ PROPERTY_ID_ISBOOKMARKABLE,
+ PropertyAttribute::READONLY,
+ &m_bIsBookmarkable,
+ cppu::UnoType<decltype(m_bIsBookmarkable)>::get());
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHSIZE),
+ PROPERTY_ID_FETCHSIZE,
+ PropertyAttribute::READONLY,
+ &m_nFetchSize,
+ cppu::UnoType<decltype(m_nFetchSize)>::get());
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETTYPE),
+ PROPERTY_ID_RESULTSETTYPE,
+ PropertyAttribute::READONLY,
+ &m_nResultSetType,
+ cppu::UnoType<decltype(m_nResultSetType)>::get());
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHDIRECTION),
+ PROPERTY_ID_FETCHDIRECTION,
+ PropertyAttribute::READONLY,
+ &m_nFetchDirection,
+ cppu::UnoType<decltype(m_nFetchDirection)>::get());
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETCONCURRENCY),
+ PROPERTY_ID_RESULTSETCONCURRENCY,
+ PropertyAttribute::READONLY,
+ &m_nResultSetConcurrency,
+ cppu::UnoType<decltype(m_nResultSetConcurrency)>::get());
+
+ if (!pSqlda)
+ return; // TODO: what?
+
+}
+
+OResultSet::~OResultSet()
+{
+}
+
+// ---- XResultSet -- Row retrieval methods ------------------------------------
+sal_Int32 SAL_CALL OResultSet::getRow()
+{
+ MutexGuard aGuard(m_rMutex);
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ return m_currentRow;
+}
+
+sal_Bool SAL_CALL OResultSet::next()
+{
+ MutexGuard aGuard(m_rMutex);
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ m_currentRow++;
+
+ ISC_STATUS fetchStat = isc_dsql_fetch(m_statusVector,
+ &m_statementHandle,
+ 1,
+ m_pSqlda);
+ if (fetchStat == 0) // SUCCESSFUL
+ {
+ return true;
+ }
+ else if (fetchStat == 100) // END OF DATASET
+ {
+ m_bIsAfterLastRow = true;
+ return false;
+ }
+ else
+ {
+ SAL_WARN("connectivity.firebird", "Error when fetching data");
+ // Throws sql exception as appropriate
+ evaluateStatusVector(m_statusVector, u"isc_dsql_fetch", *this);
+ return false;
+ }
+}
+
+sal_Bool SAL_CALL OResultSet::previous()
+{
+ ::dbtools::throwFunctionNotSupportedSQLException("previous not supported in firebird",
+ *this);
+ return false;
+}
+
+sal_Bool SAL_CALL OResultSet::isLast()
+{
+ ::dbtools::throwFunctionNotSupportedSQLException("isLast not supported in firebird",
+ *this);
+ return false;
+}
+
+sal_Bool SAL_CALL OResultSet::isBeforeFirst()
+{
+ MutexGuard aGuard(m_rMutex);
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ return m_currentRow == 0;
+}
+
+sal_Bool SAL_CALL OResultSet::isAfterLast()
+{
+ MutexGuard aGuard(m_rMutex);
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ return m_bIsAfterLastRow;
+}
+
+sal_Bool SAL_CALL OResultSet::isFirst()
+{
+ MutexGuard aGuard(m_rMutex);
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ return m_currentRow == 1 && !m_bIsAfterLastRow;
+}
+
+void SAL_CALL OResultSet::beforeFirst()
+{
+ MutexGuard aGuard(m_rMutex);
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ if (m_currentRow != 0)
+ ::dbtools::throwFunctionNotSupportedSQLException("beforeFirst not supported in firebird",
+ *this);
+}
+
+void SAL_CALL OResultSet::afterLast()
+{
+ MutexGuard aGuard(m_rMutex);
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ if (!m_bIsAfterLastRow)
+ ::dbtools::throwFunctionNotSupportedSQLException("afterLast not supported in firebird",
+ *this);
+}
+
+sal_Bool SAL_CALL OResultSet::first()
+{
+ MutexGuard aGuard(m_rMutex);
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ if (m_currentRow == 0)
+ {
+ return next();
+ }
+ else if (m_currentRow == 1 && !m_bIsAfterLastRow)
+ {
+ return true;
+ }
+ else
+ {
+ ::dbtools::throwFunctionNotSupportedSQLException("first not supported in firebird",
+ *this);
+ return false;
+ }
+}
+
+sal_Bool SAL_CALL OResultSet::last()
+{
+ // We need to iterate past the last row to know when we've passed the last
+ // row, hence we can't actually move to last.
+ ::dbtools::throwFunctionNotSupportedSQLException("last not supported in firebird",
+ *this);
+ return false;
+}
+
+sal_Bool SAL_CALL OResultSet::absolute(sal_Int32 aRow)
+{
+ MutexGuard aGuard(m_rMutex);
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ if (aRow > m_currentRow)
+ {
+ sal_Int32 aIterations = aRow - m_currentRow;
+ return relative(aIterations);
+ }
+ else
+ {
+ ::dbtools::throwFunctionNotSupportedSQLException("absolute not supported in firebird",
+ *this);
+ return false;
+ }
+}
+
+sal_Bool SAL_CALL OResultSet::relative(sal_Int32 row)
+{
+ MutexGuard aGuard(m_rMutex);
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ if (row > 0)
+ {
+ while (row--)
+ {
+ if (!next())
+ return false;
+ }
+ return true;
+ }
+ else
+ {
+ ::dbtools::throwFunctionNotSupportedSQLException("relative not supported in firebird",
+ *this);
+ return false;
+ }
+}
+
+void OResultSet::checkColumnIndex(sal_Int32 nIndex)
+{
+ MutexGuard aGuard(m_rMutex);
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ if( nIndex < 1 || nIndex > m_fieldCount )
+ {
+ ::dbtools::throwSQLException(
+ "No column " + OUString::number(nIndex),
+ ::dbtools::StandardSQLState::COLUMN_NOT_FOUND,
+ *this);
+ }
+}
+
+void OResultSet::checkRowIndex()
+{
+ MutexGuard aGuard(m_rMutex);
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ if((m_currentRow < 1) || m_bIsAfterLastRow)
+ {
+ ::dbtools::throwSQLException(
+ "Invalid Row",
+ ::dbtools::StandardSQLState::INVALID_CURSOR_POSITION,
+ *this);
+ }
+}
+
+Any SAL_CALL OResultSet::queryInterface( const Type & rType )
+{
+ Any aRet = OPropertySetHelper::queryInterface(rType);
+ return aRet.hasValue() ? aRet : OResultSet_BASE::queryInterface(rType);
+}
+
+ Sequence< Type > SAL_CALL OResultSet::getTypes()
+{
+ return concatSequences(OPropertySetHelper::getTypes(), OResultSet_BASE::getTypes());
+}
+// ---- XColumnLocate ---------------------------------------------------------
+sal_Int32 SAL_CALL OResultSet::findColumn(const OUString& rColumnName)
+{
+ MutexGuard aGuard(m_rMutex);
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ uno::Reference< XResultSetMetaData > xMeta = getMetaData();
+ sal_Int32 nLen = xMeta->getColumnCount();
+ sal_Int32 i;
+
+ for(i = 1; i<=nLen; ++i)
+ {
+ // We assume case sensitive, otherwise you'd have to test
+ // xMeta->isCaseSensitive and use qualsIgnoreAsciiCase as needed.
+ if (rColumnName == xMeta->getColumnName(i))
+ return i;
+ }
+
+ ::dbtools::throwInvalidColumnException(rColumnName, *this);
+ assert(false);
+ return 0; // Never reached
+}
+
+uno::Reference< XInputStream > SAL_CALL OResultSet::getBinaryStream( sal_Int32 )
+{
+ MutexGuard aGuard(m_rMutex);
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ return nullptr;
+}
+
+uno::Reference< XInputStream > SAL_CALL OResultSet::getCharacterStream( sal_Int32 )
+{
+ MutexGuard aGuard(m_rMutex);
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ return nullptr;
+}
+
+// ---- Internal Utilities ---------------------------------------------------
+bool OResultSet::isNull(const sal_Int32 nColumnIndex)
+{
+ assert(nColumnIndex <= m_fieldCount);
+ XSQLVAR* pVar = m_pSqlda->sqlvar;
+
+ if (pVar[nColumnIndex-1].sqltype & 1) // Indicates column may contain null
+ {
+ if (*pVar[nColumnIndex-1].sqlind == -1)
+ return true;
+ }
+ return false;
+}
+
+template <typename T>
+OUString OResultSet::makeNumericString(const sal_Int32 nColumnIndex)
+{
+ // minus because firebird stores scale as a negative number
+ int nDecimalCount = -(m_pSqlda->sqlvar[nColumnIndex-1].sqlscale);
+ if(nDecimalCount < 0)
+ {
+ // scale should be always positive
+ assert(false);
+ return OUString();
+ }
+
+ OUStringBuffer sRetBuffer;
+ T nAllDigits = *reinterpret_cast<T*>(m_pSqlda->sqlvar[nColumnIndex-1].sqldata);
+ sal_Int64 nDecimalCountExp = pow10Integer(nDecimalCount);
+
+ if(nAllDigits < 0)
+ {
+ sRetBuffer.append('-');
+ nAllDigits = -nAllDigits; // abs
+ }
+
+ sRetBuffer.append(static_cast<sal_Int64>(nAllDigits / nDecimalCountExp) );
+ if( nDecimalCount > 0)
+ {
+ sRetBuffer.append('.');
+
+ sal_Int64 nFractionalPart = nAllDigits % nDecimalCountExp;
+
+ int iCount = 0; // digit count
+ sal_Int64 nFracTemp = nFractionalPart;
+ while(nFracTemp>0)
+ {
+ nFracTemp /= 10;
+ iCount++;
+ }
+
+ int nMissingNulls = nDecimalCount - iCount;
+
+ // append nulls after dot and before nFractionalPart
+ for(int i=0; i<nMissingNulls; i++)
+ {
+ sRetBuffer.append('0');
+ }
+
+ // the rest
+ sRetBuffer.append(nFractionalPart);
+ }
+
+ return sRetBuffer.makeStringAndClear();
+}
+
+template <typename T>
+T OResultSet::retrieveValue(const sal_Int32 nColumnIndex, const ISC_SHORT nType)
+{
+ m_bWasNull = isNull(nColumnIndex);
+ if (m_bWasNull)
+ return T();
+
+ if ((m_pSqlda->sqlvar[nColumnIndex-1].sqltype & ~1) == nType)
+ return *reinterpret_cast<T*>(m_pSqlda->sqlvar[nColumnIndex-1].sqldata);
+ else
+ {
+ ORowSetValue row = retrieveValue< ORowSetValue >(nColumnIndex, 0);
+ if constexpr ( std::is_same_v<sal_Int64, T> )
+ return row.getLong();
+ else if constexpr ( std::is_same_v<sal_Int32, T> )
+ return row.getInt32();
+ else if constexpr ( std::is_same_v<sal_Int16, T> )
+ return row.getInt16();
+ else if constexpr ( std::is_same_v<float, T> )
+ return row.getFloat();
+ else if constexpr ( std::is_same_v<double, T> )
+ return row.getDouble();
+ else if constexpr ( std::is_same_v<bool, T> )
+ return row.getBool();
+ else
+ return row;
+ }
+}
+
+template <>
+ORowSetValue OResultSet::retrieveValue(const sal_Int32 nColumnIndex, const ISC_SHORT /*nType*/)
+{
+ // See https://wiki.documentfoundation.org/Documentation/DevGuide/Database_Access#Using_the_getXXX_Methods
+ // (bottom of page) for a chart of possible conversions, we should allow all
+ // of these -- Blob/Clob will probably need some specialist handling especially
+ // w.r.t. to generating Strings for them.
+ //
+ // Basically we just have to map to the correct direct request and
+ // ORowSetValue does the rest for us here.
+ int nSqlSubType = m_pSqlda->sqlvar[nColumnIndex-1].sqlsubtype;
+
+ // TODO Firebird 3.0 does not set subtype (i.e. set to 0) for computed numeric/decimal value.
+ // It may change in the future.
+ // Imply numeric data type when subtype is 0 and scale is negative
+ if( nSqlSubType == 0 && m_pSqlda->sqlvar[nColumnIndex-1].sqlscale < 0 )
+ nSqlSubType = 1;
+
+ switch (m_pSqlda->sqlvar[nColumnIndex-1].sqltype & ~1)
+ {
+ case SQL_TEXT:
+ case SQL_VARYING:
+ return getString(nColumnIndex);
+ case SQL_SHORT:
+ if(nSqlSubType == 1 || nSqlSubType == 2) //numeric or decimal
+ return getString(nColumnIndex);
+ return getShort(nColumnIndex);
+ case SQL_LONG:
+ if(nSqlSubType == 1 || nSqlSubType == 2) //numeric or decimal
+ return getString(nColumnIndex);
+ return getInt(nColumnIndex);
+ case SQL_FLOAT:
+ return getFloat(nColumnIndex);
+ case SQL_DOUBLE:
+ if(nSqlSubType == 1 || nSqlSubType == 2) //numeric or decimal
+ return getString(nColumnIndex);
+ return getDouble(nColumnIndex);
+ case SQL_D_FLOAT:
+ return getFloat(nColumnIndex);
+ case SQL_TIMESTAMP:
+ return getTimestamp(nColumnIndex);
+ case SQL_TYPE_TIME:
+ return getTime(nColumnIndex);
+ case SQL_TYPE_DATE:
+ return getDate(nColumnIndex);
+ case SQL_INT64:
+ if(nSqlSubType == 1 || nSqlSubType == 2) //numeric or decimal
+ return getString(nColumnIndex);
+ return getLong(nColumnIndex);
+ case SQL_BOOLEAN:
+ return ORowSetValue(bool(getBoolean(nColumnIndex)));
+ case SQL_BLOB:
+ case SQL_NULL:
+ case SQL_QUAD:
+ case SQL_ARRAY:
+ // TODO: these are all invalid conversions, so maybe we should
+ // throw an exception?
+ return ORowSetValue();
+ default:
+ assert(false);
+ return ORowSetValue();
+ }
+}
+
+template <>
+Date OResultSet::retrieveValue(const sal_Int32 nColumnIndex, const ISC_SHORT /*nType*/)
+{
+ if ((m_pSqlda->sqlvar[nColumnIndex-1].sqltype & ~1) == SQL_TYPE_DATE)
+ {
+ ISC_DATE aISCDate = *reinterpret_cast<ISC_DATE*>(m_pSqlda->sqlvar[nColumnIndex-1].sqldata);
+
+ struct tm aCTime;
+ isc_decode_sql_date(&aISCDate, &aCTime);
+
+ return Date(aCTime.tm_mday, aCTime.tm_mon + 1, aCTime.tm_year + 1900);
+ }
+ else
+ {
+ return retrieveValue< ORowSetValue >(nColumnIndex, 0).getDate();
+ }
+}
+
+template <>
+Time OResultSet::retrieveValue(const sal_Int32 nColumnIndex, const ISC_SHORT /*nType*/)
+{
+ if ((m_pSqlda->sqlvar[nColumnIndex-1].sqltype & ~1) == SQL_TYPE_TIME)
+ {
+ ISC_TIME aISCTime = *reinterpret_cast<ISC_TIME*>(m_pSqlda->sqlvar[nColumnIndex-1].sqldata);
+
+ struct tm aCTime;
+ isc_decode_sql_time(&aISCTime, &aCTime);
+
+ // First field is nanoseconds.
+ // last field denotes UTC (true) or unknown (false)
+ // Here we "know" that ISC_TIME is simply in units of seconds/ISC_TIME_SECONDS_PRECISION
+ // with no other funkiness, so we can get the fractional seconds easily.
+ return Time((aISCTime % ISC_TIME_SECONDS_PRECISION) * (1000000000 / ISC_TIME_SECONDS_PRECISION),
+ aCTime.tm_sec, aCTime.tm_min, aCTime.tm_hour, false);
+ }
+ else
+ {
+ return retrieveValue< ORowSetValue >(nColumnIndex, 0).getTime();
+ }
+}
+
+template <>
+DateTime OResultSet::retrieveValue(const sal_Int32 nColumnIndex, const ISC_SHORT /*nType*/)
+{
+ if ((m_pSqlda->sqlvar[nColumnIndex-1].sqltype & ~1) == SQL_TIMESTAMP)
+ {
+ ISC_TIMESTAMP aISCTimestamp = *reinterpret_cast<ISC_TIMESTAMP*>(m_pSqlda->sqlvar[nColumnIndex-1].sqldata);
+
+ struct tm aCTime;
+ isc_decode_timestamp(&aISCTimestamp, &aCTime);
+
+ // Ditto here, see comment in previous function about ISC_TIME and ISC_TIME_SECONDS_PRECISION.
+ return DateTime((aISCTimestamp.timestamp_time % ISC_TIME_SECONDS_PRECISION) * (1000000000 / ISC_TIME_SECONDS_PRECISION), //nanoseconds
+ aCTime.tm_sec,
+ aCTime.tm_min,
+ aCTime.tm_hour,
+ aCTime.tm_mday,
+ aCTime.tm_mon + 1, // tm is from 0 to 11
+ aCTime.tm_year + 1900, //tm_year is the years since 1900
+ false); // denotes UTC (true), or unknown (false)
+ }
+ else
+ {
+ return retrieveValue< ORowSetValue >(nColumnIndex, 0).getDateTime();
+ }
+}
+
+template <>
+OUString OResultSet::retrieveValue(const sal_Int32 nColumnIndex, const ISC_SHORT /*nType*/)
+{
+ // &~1 to remove the "can contain NULL" indicator
+ int aSqlType = m_pSqlda->sqlvar[nColumnIndex-1].sqltype & ~1;
+ int aSqlSubType = m_pSqlda->sqlvar[nColumnIndex-1].sqlsubtype;
+ if (aSqlType == SQL_TEXT )
+ {
+ return OUString(m_pSqlda->sqlvar[nColumnIndex-1].sqldata,
+ m_pSqlda->sqlvar[nColumnIndex-1].sqllen,
+ RTL_TEXTENCODING_UTF8);
+ }
+ else if (aSqlType == SQL_VARYING)
+ {
+ // First 2 bytes are a short containing the length of the string
+ // Under unclear conditions, it may be wrong and greater than sqllen.
+ sal_uInt16 aLength = *reinterpret_cast<sal_uInt16*>(m_pSqlda->sqlvar[nColumnIndex-1].sqldata);
+ // Use greater signed type sal_Int32 to get the minimum of two 16-bit values
+ return OUString(m_pSqlda->sqlvar[nColumnIndex-1].sqldata + 2,
+ std::min<sal_Int32>(aLength, m_pSqlda->sqlvar[nColumnIndex-1].sqllen),
+ RTL_TEXTENCODING_UTF8);
+ }
+ else if ((aSqlType == SQL_SHORT || aSqlType == SQL_LONG ||
+ aSqlType == SQL_DOUBLE || aSqlType == SQL_INT64)
+ && (aSqlSubType == 1 ||
+ aSqlSubType == 2 ||
+ (aSqlSubType == 0 && m_pSqlda->sqlvar[nColumnIndex-1].sqlscale < 0) ) )
+ {
+ // decimal and numeric types
+ switch(aSqlType)
+ {
+ case SQL_SHORT:
+ return makeNumericString<sal_Int16>(nColumnIndex);
+ case SQL_LONG:
+ return makeNumericString<sal_Int32>(nColumnIndex);
+ case SQL_DOUBLE:
+ // TODO FIXME 64 bits?
+ case SQL_INT64:
+ return makeNumericString<sal_Int64>(nColumnIndex);
+ default:
+ assert(false);
+ return OUString(); // never reached
+ }
+ }
+ else if(aSqlType == SQL_BLOB && aSqlSubType == static_cast<short>(BlobSubtype::Clob) )
+ {
+ uno::Reference<XClob> xClob = getClob(nColumnIndex);
+ return xClob->getSubString( 1, xClob->length() );
+ }
+ else
+ {
+ return retrieveValue< ORowSetValue >(nColumnIndex, 0).getString();
+ }
+}
+
+template <>
+ISC_QUAD* OResultSet::retrieveValue(const sal_Int32 nColumnIndex, const ISC_SHORT nType)
+{
+ // TODO: this is probably wrong
+ if ((m_pSqlda->sqlvar[nColumnIndex-1].sqltype & ~1) != nType)
+ throw SQLException(); // TODO: better exception (can't convert Blob)
+
+ return reinterpret_cast<ISC_QUAD*>(m_pSqlda->sqlvar[nColumnIndex-1].sqldata);
+}
+
+template <typename T>
+T OResultSet::safelyRetrieveValue(const sal_Int32 nColumnIndex, const ISC_SHORT nType)
+{
+ MutexGuard aGuard(m_rMutex);
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ checkColumnIndex(nColumnIndex);
+ checkRowIndex();
+
+ m_bWasNull = isNull(nColumnIndex);
+ if (m_bWasNull)
+ return T();
+
+ return retrieveValue< T >(nColumnIndex, nType);
+}
+
+// ---- XRow -----------------------------------------------------------------
+sal_Bool SAL_CALL OResultSet::wasNull()
+{
+ MutexGuard aGuard(m_rMutex);
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ return m_bWasNull;
+}
+
+// ---- XRow: Simple Numerical types ------------------------------------------
+sal_Bool SAL_CALL OResultSet::getBoolean(sal_Int32 nColumnIndex)
+{
+ return safelyRetrieveValue< bool >(nColumnIndex, SQL_BOOLEAN);
+}
+
+sal_Int8 SAL_CALL OResultSet::getByte(sal_Int32 nColumnIndex)
+{
+ // Not a native firebird type hence we always have to convert.
+ return safelyRetrieveValue< ORowSetValue >(nColumnIndex).getInt8();
+}
+
+Sequence< sal_Int8 > SAL_CALL OResultSet::getBytes(sal_Int32 nColumnIndex)
+{
+ // &~1 to remove the "can contain NULL" indicator
+ int aSqlType = m_pSqlda->sqlvar[nColumnIndex-1].sqltype & ~1;
+ if ( aSqlType == SQL_BLOB )
+ {
+ Reference< XBlob> xBlob = getBlob(nColumnIndex);
+ if (xBlob.is())
+ {
+ const sal_Int64 aBlobLength = xBlob->length();
+ if (aBlobLength > SAL_MAX_INT32)
+ {
+ SAL_WARN("connectivity.firebird", "getBytes can't return " << aBlobLength << " bytes but only max " << SAL_MAX_INT32);
+ return xBlob->getBytes(1, SAL_MAX_INT32);
+ }
+ return xBlob->getBytes(1, static_cast<sal_Int32>(aBlobLength));
+ }
+ else
+ return Sequence< sal_Int8 >();
+ }
+ // TODO implement SQL_VARYING and SQL_TEXT
+ // as it's the counterpart as OPreparedStatement::setBytes
+ else
+ {
+ return Sequence< sal_Int8 >(); // TODO: implement
+ }
+}
+
+sal_Int16 SAL_CALL OResultSet::getShort(sal_Int32 columnIndex)
+{
+ return safelyRetrieveValue< sal_Int16 >(columnIndex, SQL_SHORT);
+}
+
+sal_Int32 SAL_CALL OResultSet::getInt(sal_Int32 columnIndex)
+{
+ return safelyRetrieveValue< sal_Int32 >(columnIndex, SQL_LONG);
+}
+
+sal_Int64 SAL_CALL OResultSet::getLong(sal_Int32 columnIndex)
+{
+ return safelyRetrieveValue< sal_Int64 >(columnIndex, SQL_INT64);
+}
+
+float SAL_CALL OResultSet::getFloat(sal_Int32 columnIndex)
+{
+ return safelyRetrieveValue< float >(columnIndex, SQL_FLOAT);
+}
+
+double SAL_CALL OResultSet::getDouble(sal_Int32 columnIndex)
+{
+ return safelyRetrieveValue< double >(columnIndex, SQL_DOUBLE);
+}
+
+// ---- XRow: More complex types ----------------------------------------------
+OUString SAL_CALL OResultSet::getString(sal_Int32 nIndex)
+{
+ return safelyRetrieveValue< OUString >(nIndex);
+}
+
+Date SAL_CALL OResultSet::getDate(sal_Int32 nIndex)
+{
+ return safelyRetrieveValue< Date >(nIndex, SQL_TYPE_DATE);
+}
+
+Time SAL_CALL OResultSet::getTime(sal_Int32 nIndex)
+{
+ return safelyRetrieveValue< css::util::Time >(nIndex, SQL_TYPE_TIME);
+}
+
+DateTime SAL_CALL OResultSet::getTimestamp(sal_Int32 nIndex)
+{
+ return safelyRetrieveValue< DateTime >(nIndex, SQL_TIMESTAMP);
+}
+
+
+uno::Reference< XResultSetMetaData > SAL_CALL OResultSet::getMetaData( )
+{
+ MutexGuard aGuard(m_rMutex);
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ if(!m_xMetaData.is())
+ m_xMetaData = new OResultSetMetaData(m_pConnection
+ , m_pSqlda);
+ return m_xMetaData;
+}
+
+uno::Reference< XArray > SAL_CALL OResultSet::getArray( sal_Int32 )
+{
+ MutexGuard aGuard(m_rMutex);
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ return nullptr;
+}
+
+
+uno::Reference< XClob > SAL_CALL OResultSet::getClob( sal_Int32 columnIndex )
+{
+ MutexGuard aGuard(m_rMutex);
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ int aSqlSubType = m_pSqlda->sqlvar[columnIndex-1].sqlsubtype;
+
+ SAL_WARN_IF(aSqlSubType != 1,
+ "connectivity.firebird", "wrong subtype, not a textual blob");
+
+ ISC_QUAD* pBlobID = safelyRetrieveValue< ISC_QUAD* >(columnIndex, SQL_BLOB);
+ if (!pBlobID)
+ return nullptr;
+ return m_pConnection->createClob(pBlobID);
+}
+
+uno::Reference< XBlob > SAL_CALL OResultSet::getBlob(sal_Int32 columnIndex)
+{
+ MutexGuard aGuard(m_rMutex);
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ // TODO: CLOB etc. should be valid here too, but we probably want some more
+ // cleverness around this.
+ ISC_QUAD* pBlobID = safelyRetrieveValue< ISC_QUAD* >(columnIndex, SQL_BLOB);
+ if (!pBlobID)
+ return nullptr;
+ return m_pConnection->createBlob(pBlobID);
+}
+
+
+uno::Reference< XRef > SAL_CALL OResultSet::getRef( sal_Int32 )
+{
+ MutexGuard aGuard(m_rMutex);
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ return nullptr;
+}
+
+
+Any SAL_CALL OResultSet::getObject( sal_Int32, const uno::Reference< css::container::XNameAccess >& )
+{
+ MutexGuard aGuard(m_rMutex);
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ return Any();
+}
+
+
+void SAL_CALL OResultSet::close()
+{
+ SAL_INFO("connectivity.firebird", "close().");
+
+ {
+ MutexGuard aGuard(m_rMutex);
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+ }
+ dispose();
+}
+
+
+uno::Reference< XInterface > SAL_CALL OResultSet::getStatement()
+{
+ MutexGuard aGuard(m_rMutex);
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ return m_xStatement;
+}
+//----- XResultSet: unsupported change detection methods ---------------------
+sal_Bool SAL_CALL OResultSet::rowDeleted()
+{
+ ::dbtools::throwFunctionNotSupportedSQLException("rowDeleted not supported in firebird",
+ *this);
+ return false;
+}
+sal_Bool SAL_CALL OResultSet::rowInserted()
+{
+ ::dbtools::throwFunctionNotSupportedSQLException("rowInserted not supported in firebird",
+ *this);
+ return false;
+}
+
+sal_Bool SAL_CALL OResultSet::rowUpdated()
+{
+ ::dbtools::throwFunctionNotSupportedSQLException("rowUpdated not supported in firebird",
+ *this);
+ return false;
+}
+
+void SAL_CALL OResultSet::refreshRow()
+{
+ ::dbtools::throwFunctionNotSupportedSQLException("refreshRow not supported in firebird",
+ *this);
+}
+
+
+void SAL_CALL OResultSet::cancel( )
+{
+ MutexGuard aGuard(m_rMutex);
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+}
+
+//----- OIdPropertyArrayUsageHelper ------------------------------------------
+IPropertyArrayHelper* OResultSet::createArrayHelper() const
+{
+ Sequence< Property > aProperties;
+ describeProperties(aProperties);
+ return new ::cppu::OPropertyArrayHelper(aProperties);
+}
+
+IPropertyArrayHelper & OResultSet::getInfoHelper()
+{
+ return *getArrayHelper();
+}
+
+void SAL_CALL OResultSet::acquire() noexcept
+{
+ OResultSet_BASE::acquire();
+}
+
+void SAL_CALL OResultSet::release() noexcept
+{
+ OResultSet_BASE::release();
+}
+
+uno::Reference< css::beans::XPropertySetInfo > SAL_CALL OResultSet::getPropertySetInfo( )
+{
+ return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper());
+}
+
+// ---- XServiceInfo -----------------------------------------------------------
+OUString SAL_CALL OResultSet::getImplementationName()
+{
+ return "com.sun.star.sdbcx.firebird.ResultSet";
+}
+
+Sequence< OUString > SAL_CALL OResultSet::getSupportedServiceNames()
+{
+ return {"com.sun.star.sdbc.ResultSet","com.sun.star.sdbcx.ResultSet"};
+}
+
+sal_Bool SAL_CALL OResultSet::supportsService(const OUString& _rServiceName)
+{
+ return cppu::supportsService(this, _rServiceName);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/connectivity/source/drivers/firebird/ResultSet.hxx b/connectivity/source/drivers/firebird/ResultSet.hxx
new file mode 100644
index 0000000000..fdae21dfba
--- /dev/null
+++ b/connectivity/source/drivers/firebird/ResultSet.hxx
@@ -0,0 +1,216 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "Connection.hxx"
+
+#include <ibase.h>
+
+#include <connectivity/FValue.hxx>
+#include <cppuhelper/compbase.hxx>
+#include <comphelper/proparrhlp.hxx>
+#include <comphelper/propertycontainer.hxx>
+
+#include <com/sun/star/util/XCancellable.hpp>
+#include <com/sun/star/sdbc/XCloseable.hpp>
+#include <com/sun/star/sdbc/XColumnLocate.hpp>
+#include <com/sun/star/sdbc/XResultSet.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
+
+namespace connectivity::firebird
+ {
+ /*
+ ** OResultSet
+ */
+ typedef ::cppu::WeakComponentImplHelper< css::sdbc::XResultSet,
+ css::sdbc::XRow,
+ css::sdbc::XResultSetMetaDataSupplier,
+ css::util::XCancellable,
+ css::sdbc::XCloseable,
+ css::sdbc::XColumnLocate,
+ css::lang::XServiceInfo> OResultSet_BASE;
+
+ /**
+ * This ResultSet does not deal with the management of the SQLDA
+ * it is supplied with. The owner must mange its SQLDA appropriately
+ * and ensure that the ResultSet is destroyed before disposing of the
+ * SQLDA.
+ */
+ class OResultSet: public OResultSet_BASE,
+ public ::comphelper::OPropertyContainer,
+ public ::comphelper::OPropertyArrayUsageHelper<OResultSet>
+ {
+ private:
+ bool m_bIsBookmarkable;
+ sal_Int32 m_nFetchSize;
+ sal_Int32 m_nResultSetType;
+ sal_Int32 m_nFetchDirection;
+ sal_Int32 m_nResultSetConcurrency;
+
+ protected:
+ // Connection kept alive by m_xStatement
+ Connection* m_pConnection;
+ ::osl::Mutex& m_rMutex;
+ const css::uno::Reference< css::uno::XInterface >& m_xStatement;
+
+ css::uno::Reference< css::sdbc::XResultSetMetaData> m_xMetaData;
+
+ XSQLDA* m_pSqlda;
+ isc_stmt_handle m_statementHandle;
+
+ bool m_bWasNull;
+ // Row numbering starts with 0 for "in front of first row"
+ sal_Int32 m_currentRow;
+ bool m_bIsAfterLastRow;
+
+ const sal_Int32 m_fieldCount;
+ ISC_STATUS_ARRAY m_statusVector;
+
+ bool isNull(const sal_Int32 nColumnIndex);
+
+ template <typename T> OUString makeNumericString(
+ const sal_Int32 nColumnIndex);
+
+ template <typename T> T retrieveValue(const sal_Int32 nColumnIndex,
+ const ISC_SHORT nType);
+
+ template <typename T> T safelyRetrieveValue(
+ const sal_Int32 nColumnIndex,
+ const ISC_SHORT nType = 0);
+
+ // OIdPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper() const override;
+ virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override;
+
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void checkColumnIndex( sal_Int32 index );
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void checkRowIndex();
+
+ // you can't delete objects of this type
+ virtual ~OResultSet() override;
+ public:
+ DECLARE_SERVICE_INFO();
+
+ OResultSet(Connection* pConnection,
+ ::osl::Mutex& rMutex,
+ const css::uno::Reference< css::uno::XInterface >& xStatement,
+ isc_stmt_handle aStatementHandle,
+ XSQLDA* aSqlda
+ );
+
+ // XInterface
+ virtual css::uno::Any SAL_CALL queryInterface(
+ const css::uno::Type& rType) override;
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+ //XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override;
+ // XPropertySet
+ virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override;
+ // XResultSet
+ virtual sal_Bool SAL_CALL next( ) override;
+ virtual sal_Bool SAL_CALL isBeforeFirst( ) override;
+ virtual sal_Bool SAL_CALL isAfterLast( ) override;
+ virtual sal_Bool SAL_CALL isFirst( ) override;
+ virtual sal_Bool SAL_CALL isLast( ) override;
+ virtual void SAL_CALL beforeFirst( ) override;
+ virtual void SAL_CALL afterLast( ) override;
+ virtual sal_Bool SAL_CALL first( ) override;
+ virtual sal_Bool SAL_CALL last( ) override;
+ virtual sal_Int32 SAL_CALL getRow( ) override;
+ virtual sal_Bool SAL_CALL absolute( sal_Int32 row ) override;
+ virtual sal_Bool SAL_CALL relative( sal_Int32 rows ) override;
+ virtual sal_Bool SAL_CALL previous( ) override;
+ virtual void SAL_CALL refreshRow( ) override;
+ virtual sal_Bool SAL_CALL rowUpdated( ) override;
+ virtual sal_Bool SAL_CALL rowInserted( ) override;
+ virtual sal_Bool SAL_CALL rowDeleted( ) override;
+ virtual css::uno::Reference< css::uno::XInterface > SAL_CALL getStatement( ) override;
+ // XRow
+ virtual sal_Bool SAL_CALL wasNull( ) override;
+ virtual OUString SAL_CALL getString( sal_Int32 columnIndex ) override;
+ virtual sal_Bool SAL_CALL getBoolean( sal_Int32 columnIndex ) override;
+ virtual sal_Int8 SAL_CALL getByte( sal_Int32 columnIndex ) override;
+ virtual sal_Int16 SAL_CALL getShort( sal_Int32 columnIndex ) override;
+ virtual sal_Int32 SAL_CALL getInt( sal_Int32 columnIndex ) override;
+ virtual sal_Int64 SAL_CALL getLong( sal_Int32 columnIndex ) override;
+ virtual float SAL_CALL getFloat( sal_Int32 columnIndex ) override;
+ virtual double SAL_CALL getDouble( sal_Int32 columnIndex ) override;
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getBytes( sal_Int32 columnIndex ) override;
+ virtual css::util::Date SAL_CALL getDate( sal_Int32 columnIndex ) override;
+ virtual css::util::Time SAL_CALL getTime( sal_Int32 columnIndex ) override;
+ virtual css::util::DateTime SAL_CALL getTimestamp( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getBinaryStream( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getCharacterStream( sal_Int32 columnIndex ) override;
+ virtual css::uno::Any SAL_CALL getObject( sal_Int32 columnIndex, const css::uno::Reference< css::container::XNameAccess >& typeMap ) override;
+ virtual css::uno::Reference< css::sdbc::XRef > SAL_CALL getRef( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XBlob > SAL_CALL getBlob( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XClob > SAL_CALL getClob( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XArray > SAL_CALL getArray( sal_Int32 columnIndex ) override;
+ // XResultSetMetaDataSupplier
+ virtual css::uno::Reference< css::sdbc::XResultSetMetaData > SAL_CALL getMetaData( ) override;
+ // XCancellable
+ virtual void SAL_CALL cancel( ) override;
+ // XCloseable
+ virtual void SAL_CALL close( ) override;
+ // XWarningsSupplier
+
+ // XColumnLocate
+ virtual sal_Int32 SAL_CALL findColumn(const OUString& columnName) override;
+
+ };
+
+ // Specialisations have to be in the namespace and can't be within the class.
+ template <> css::util::Date
+ OResultSet::retrieveValue(
+ const sal_Int32 nColumnIndex,
+ const ISC_SHORT nType);
+ template <> ::connectivity::ORowSetValue
+ OResultSet::retrieveValue(
+ const sal_Int32 nColumnIndex,
+ const ISC_SHORT nType);
+ template <> css::util::Time
+ OResultSet::retrieveValue(
+ const sal_Int32 nColumnIndex,
+ const ISC_SHORT nType);
+ template <> css::util::DateTime
+ OResultSet::retrieveValue(
+ const sal_Int32 nColumnIndex,
+ const ISC_SHORT nType);
+ template <> ISC_QUAD*
+ OResultSet::retrieveValue(
+ const sal_Int32 nColumnIndex,
+ const ISC_SHORT nType);
+ template <> OUString
+ OResultSet::retrieveValue(
+ const sal_Int32 nColumnIndex,
+ const ISC_SHORT nType);
+ template <> ISC_QUAD*
+ OResultSet::retrieveValue(
+ const sal_Int32 nColumnIndex,
+ const ISC_SHORT nType);
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/connectivity/source/drivers/firebird/ResultSetMetaData.cxx b/connectivity/source/drivers/firebird/ResultSetMetaData.cxx
new file mode 100644
index 0000000000..31a6796f53
--- /dev/null
+++ b/connectivity/source/drivers/firebird/ResultSetMetaData.cxx
@@ -0,0 +1,301 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "ResultSetMetaData.hxx"
+#include "Util.hxx"
+
+#include <com/sun/star/sdbc/ColumnValue.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/DataType.hpp>
+
+#include <sal/log.hxx>
+
+using namespace connectivity::firebird;
+
+using namespace com::sun::star::lang;
+using namespace com::sun::star::sdbc;
+using namespace com::sun::star::sdbcx;
+using namespace com::sun::star::uno;
+
+OResultSetMetaData::~OResultSetMetaData()
+{
+}
+
+OUString OResultSetMetaData::getCharacterSet( sal_Int32 nIndex )
+{
+ OUString sTable = getTableName( nIndex );
+ if( !sTable.isEmpty() )
+ {
+ OUString sColumnName = getColumnName( nIndex );
+
+ OUString sSql = "SELECT charset.RDB$CHARACTER_SET_NAME "
+ "FROM RDB$CHARACTER_SETS charset "
+ "JOIN RDB$FIELDS fields "
+ "ON (fields.RDB$CHARACTER_SET_ID = charset.RDB$CHARACTER_SET_ID) "
+ "JOIN RDB$RELATION_FIELDS relfields "
+ "ON (fields.RDB$FIELD_NAME = relfields.RDB$FIELD_SOURCE) "
+ "WHERE relfields.RDB$RELATION_NAME = '"
+ + sTable.replaceAll("'", "''") + "' AND "
+ "relfields.RDB$FIELD_NAME = '"+ sColumnName.replaceAll("'", "''") +"'";
+
+ Reference<XStatement> xStmt= m_pConnection->createStatement();
+
+ Reference<XResultSet> xRes =
+ xStmt->executeQuery(sSql);
+ Reference<XRow> xRow ( xRes, UNO_QUERY);
+ if(xRes->next())
+ {
+ OUString sCharset = xRow->getString(1).trim();
+ return sCharset;
+ }
+ }
+ return OUString();
+
+
+}
+
+void OResultSetMetaData::verifyValidColumn(sal_Int32 column)
+{
+ if (column>getColumnCount() || column < 1)
+ throw SQLException("Invalid column specified", *this, OUString(), 0, Any());
+}
+
+sal_Int32 SAL_CALL OResultSetMetaData::getColumnCount()
+{
+ return m_pSqlda->sqld;
+}
+
+sal_Int32 SAL_CALL OResultSetMetaData::getColumnDisplaySize( sal_Int32 column )
+{
+ verifyValidColumn(column);
+ return 32; // Hard limit for firebird
+}
+
+sal_Int32 SAL_CALL OResultSetMetaData::getColumnType(sal_Int32 column)
+{
+ verifyValidColumn(column);
+
+ short aType = m_pSqlda->sqlvar[column-1].sqltype & ~1;
+ OUString sCharset;
+
+ // do not query the character set unnecessarily
+ if(aType == SQL_TEXT || aType == SQL_VARYING)
+ {
+ sCharset = getCharacterSet(column);
+ }
+
+ ColumnTypeInfo aInfo( m_pSqlda->sqlvar[column-1].sqltype,
+ m_pSqlda->sqlvar[column-1].sqlsubtype,
+ -(m_pSqlda->sqlvar[column-1].sqlscale),
+ sCharset );
+
+ return aInfo.getSdbcType();
+}
+
+sal_Bool SAL_CALL OResultSetMetaData::isCaseSensitive(sal_Int32)
+{
+ // Firebird is generally case sensitive when using quoted identifiers.
+ // IF THIS CHANGES make ResultSet::findColumn to be case-insensitive as needed.
+ // Generally names that are entirely UPPERCASE are case insensitive, however
+ // there remains some ambiguity if there is another mixed-case-named column
+ // of the same name. For safety always assume case insensitive.
+ return true;
+}
+
+OUString SAL_CALL OResultSetMetaData::getSchemaName(sal_Int32)
+{
+ return OUString(); // Schemas supported by firebird
+}
+
+OUString SAL_CALL OResultSetMetaData::getColumnName(sal_Int32 column)
+{
+ verifyValidColumn(column);
+ char* pColumnName = m_pSqlda->sqlvar[column - 1].sqlname;
+ sal_Int32 nColumnNameLength = m_pSqlda->sqlvar[column - 1].sqlname_length;
+ // tdf#132924 - return column alias if specified
+ if (m_pSqlda->sqlvar[column - 1].aliasname_length > 0)
+ {
+ pColumnName = m_pSqlda->sqlvar[column - 1].aliasname;
+ nColumnNameLength = m_pSqlda->sqlvar[column - 1].aliasname_length;
+ }
+ OUString sRet(pColumnName, nColumnNameLength, RTL_TEXTENCODING_UTF8);
+ sanitizeIdentifier(sRet);
+ return sRet;
+}
+
+OUString SAL_CALL OResultSetMetaData::getTableName(sal_Int32 column)
+{
+ verifyValidColumn(column);
+ return OUString(m_pSqlda->sqlvar[column-1].relname,
+ m_pSqlda->sqlvar[column-1].relname_length,
+ RTL_TEXTENCODING_UTF8);
+}
+
+OUString SAL_CALL OResultSetMetaData::getCatalogName(sal_Int32)
+{
+ return OUString(); // Catalogs not supported by firebird
+}
+
+OUString SAL_CALL OResultSetMetaData::getColumnTypeName(sal_Int32 column)
+{
+ verifyValidColumn(column);
+
+ ColumnTypeInfo aInfo( m_pSqlda->sqlvar[column-1].sqltype,
+ m_pSqlda->sqlvar[column-1].sqlsubtype,
+ -(m_pSqlda->sqlvar[column-1].sqlscale) );
+
+ return aInfo.getColumnTypeName();
+}
+
+OUString SAL_CALL OResultSetMetaData::getColumnLabel(sal_Int32 column)
+{
+ // aliasname
+ verifyValidColumn(column);
+ OUString sRet(m_pSqlda->sqlvar[column-1].aliasname,
+ m_pSqlda->sqlvar[column-1].aliasname_length,
+ RTL_TEXTENCODING_UTF8);
+ sanitizeIdentifier(sRet);
+ return sRet;
+}
+
+OUString SAL_CALL OResultSetMetaData::getColumnServiceName(sal_Int32)
+{
+ // TODO: implement
+ return OUString();
+}
+
+sal_Bool SAL_CALL OResultSetMetaData::isCurrency(sal_Int32)
+{
+ return false;
+}
+
+sal_Bool SAL_CALL OResultSetMetaData::isAutoIncrement(sal_Int32 column)
+{
+ OUString sTable = getTableName(column);
+ if( sTable.isEmpty() )
+ return false;
+
+ OUString sColumnName = getColumnName( column );
+
+ OUString sSql = "SELECT RDB$IDENTITY_TYPE FROM RDB$RELATION_FIELDS "
+ "WHERE RDB$RELATION_NAME = '"
+ + sTable.replaceAll("'", "''") + "' AND "
+ "RDB$FIELD_NAME = '"+ sColumnName.replaceAll("'", "''") +"'";
+
+ Reference<XStatement> xStmt =m_pConnection ->createStatement();
+
+ Reference<XResultSet> xRes =
+ xStmt->executeQuery(sSql);
+ Reference<XRow> xRow ( xRes, UNO_QUERY);
+ if(xRes->next())
+ {
+ int iType = xRow->getShort(1);
+ if(iType == 1) // IDENTITY
+ return true;
+ }
+ else
+ {
+ SAL_WARN("connectivity.firebird","Column '"
+ << sColumnName
+ << "' not found in database");
+
+ return false;
+ }
+ return false;
+}
+
+
+sal_Bool SAL_CALL OResultSetMetaData::isSigned(sal_Int32)
+{
+ // Unsigned values aren't supported in firebird.
+ return true;
+}
+
+sal_Int32 SAL_CALL OResultSetMetaData::getPrecision(sal_Int32 column)
+{
+ sal_Int32 nType = getColumnType(column);
+ if( nType != DataType::NUMERIC && nType != DataType::DECIMAL )
+ return 0;
+
+ OUString sColumnName = getColumnName( column );
+
+ // RDB$FIELD_SOURCE is a unique name of column per database
+ OUString sSql = "SELECT RDB$FIELD_PRECISION FROM RDB$FIELDS "
+ " INNER JOIN RDB$RELATION_FIELDS "
+ " ON RDB$RELATION_FIELDS.RDB$FIELD_SOURCE = RDB$FIELDS.RDB$FIELD_NAME "
+ "WHERE RDB$RELATION_FIELDS.RDB$RELATION_NAME = '"
+ + getTableName(column).replaceAll("'", "''") + "' AND "
+ "RDB$RELATION_FIELDS.RDB$FIELD_NAME = '"
+ + sColumnName.replaceAll("'", "''") +"'";
+ Reference<XStatement> xStmt= m_pConnection->createStatement();
+
+ Reference<XResultSet> xRes =
+ xStmt->executeQuery(sSql);
+ Reference<XRow> xRow ( xRes, UNO_QUERY);
+ if(xRes->next())
+ {
+ return static_cast<sal_Int32>(xRow->getShort(1));
+ }
+ else
+ {
+ SAL_WARN("connectivity.firebird","Column '"
+ << sColumnName
+ << "' not found in database");
+ return 0;
+ }
+ return 0;
+}
+
+sal_Int32 SAL_CALL OResultSetMetaData::getScale(sal_Int32 column)
+{
+ return -(m_pSqlda->sqlvar[column-1].sqlscale); // fb stores negative number
+}
+
+sal_Int32 SAL_CALL OResultSetMetaData::isNullable(sal_Int32 column)
+{
+ if (m_pSqlda->sqlvar[column-1].sqltype & 1)
+ return ColumnValue::NULLABLE;
+ else
+ return ColumnValue::NO_NULLS;
+}
+
+sal_Bool SAL_CALL OResultSetMetaData::isSearchable(sal_Int32)
+{
+ // TODO: Can the column be used as part of a where clause? Assume yes
+ return true;
+}
+
+sal_Bool SAL_CALL OResultSetMetaData::isReadOnly(sal_Int32)
+{
+ return m_pConnection->isReadOnly(); // Readonly only available on db level
+}
+
+sal_Bool SAL_CALL OResultSetMetaData::isDefinitelyWritable(sal_Int32)
+{
+ return !m_pConnection->isReadOnly();
+}
+
+sal_Bool SAL_CALL OResultSetMetaData::isWritable( sal_Int32 )
+{
+ return !m_pConnection->isReadOnly();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/connectivity/source/drivers/firebird/ResultSetMetaData.hxx b/connectivity/source/drivers/firebird/ResultSetMetaData.hxx
new file mode 100644
index 0000000000..a32c206213
--- /dev/null
+++ b/connectivity/source/drivers/firebird/ResultSetMetaData.hxx
@@ -0,0 +1,80 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "Connection.hxx"
+
+#include <ibase.h>
+
+#include <cppuhelper/implbase.hxx>
+#include <rtl/ref.hxx>
+
+#include <com/sun/star/sdbc/XResultSetMetaData.hpp>
+
+namespace connectivity::firebird
+ {
+ typedef ::cppu::WeakImplHelper< css::sdbc::XResultSetMetaData>
+ OResultSetMetaData_BASE;
+
+ class OResultSetMetaData : public OResultSetMetaData_BASE
+ {
+ protected:
+ ::rtl::Reference<Connection> m_pConnection;
+ XSQLDA* m_pSqlda;
+
+ virtual ~OResultSetMetaData() override;
+
+ /// @throws css::sdbc::SQLException
+ void verifyValidColumn(sal_Int32 column);
+ OUString getCharacterSet(sal_Int32 nIndex);
+ public:
+ // a constructor, which is required for returning objects:
+ OResultSetMetaData(Connection* pConnection,
+ XSQLDA* pSqlda)
+ : m_pConnection(pConnection)
+ , m_pSqlda(pSqlda)
+ {}
+
+ virtual sal_Int32 SAL_CALL getColumnCount() override;
+ virtual sal_Bool SAL_CALL isAutoIncrement(sal_Int32 column) override;
+ virtual sal_Bool SAL_CALL isCaseSensitive(sal_Int32 column) override;
+ virtual sal_Bool SAL_CALL isSearchable(sal_Int32 column) override;
+ virtual sal_Bool SAL_CALL isCurrency(sal_Int32 column) override;
+ virtual sal_Int32 SAL_CALL isNullable(sal_Int32 column) override;
+ virtual sal_Bool SAL_CALL isSigned(sal_Int32 column) override;
+ virtual sal_Int32 SAL_CALL getColumnDisplaySize(sal_Int32 column) override;
+ virtual OUString SAL_CALL getColumnLabel(sal_Int32 column) override;
+ virtual OUString SAL_CALL getColumnName(sal_Int32 column) override;
+ virtual OUString SAL_CALL getSchemaName(sal_Int32 column) override;
+ virtual sal_Int32 SAL_CALL getPrecision(sal_Int32 column) override;
+ virtual sal_Int32 SAL_CALL getScale(sal_Int32 column) override;
+ virtual OUString SAL_CALL getTableName(sal_Int32 column) override;
+ virtual OUString SAL_CALL getCatalogName(sal_Int32 column) override;
+ virtual sal_Int32 SAL_CALL getColumnType(sal_Int32 column) override;
+ virtual OUString SAL_CALL getColumnTypeName(sal_Int32 column) override;
+ virtual sal_Bool SAL_CALL isReadOnly(sal_Int32 column) override;
+ virtual sal_Bool SAL_CALL isWritable(sal_Int32 column) override;
+ virtual sal_Bool SAL_CALL isDefinitelyWritable(sal_Int32 column) override;
+ virtual OUString SAL_CALL getColumnServiceName(sal_Int32 column) override;
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/connectivity/source/drivers/firebird/Statement.cxx b/connectivity/source/drivers/firebird/Statement.cxx
new file mode 100644
index 0000000000..ed56b594a3
--- /dev/null
+++ b/connectivity/source/drivers/firebird/Statement.cxx
@@ -0,0 +1,176 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "Connection.hxx"
+#include "ResultSet.hxx"
+#include "Statement.hxx"
+#include "Util.hxx"
+
+#include <comphelper/sequence.hxx>
+#include <cppuhelper/queryinterface.hxx>
+#include <sal/log.hxx>
+
+using namespace connectivity::firebird;
+
+using namespace com::sun::star;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::sdbc;
+using namespace com::sun::star::sdbcx;
+using namespace com::sun::star::container;
+using namespace com::sun::star::io;
+using namespace com::sun::star::util;
+
+using namespace ::comphelper;
+using namespace ::osl;
+
+// ---- XBatchExecution - UNSUPPORTED ----------------------------------------
+void SAL_CALL OStatement::addBatch(const OUString&)
+{
+}
+
+void SAL_CALL OStatement::clearBatch()
+{
+}
+
+Sequence< sal_Int32 > SAL_CALL OStatement::executeBatch()
+{
+ return Sequence< sal_Int32 >();
+}
+
+IMPLEMENT_SERVICE_INFO(OStatement,"com.sun.star.sdbcx.OStatement","com.sun.star.sdbc.Statement");
+
+void SAL_CALL OStatement::acquire() noexcept
+{
+ OStatementCommonBase::acquire();
+}
+
+void SAL_CALL OStatement::release() noexcept
+{
+ OStatementCommonBase::release();
+}
+
+void OStatement::disposeResultSet()
+{
+ MutexGuard aGuard(m_aMutex);
+ if (OStatementCommonBase_Base::rBHelper.bDisposed)
+ return;
+
+ OStatementCommonBase::disposeResultSet();
+
+ if (m_pSqlda)
+ {
+ freeSQLVAR(m_pSqlda);
+ free(m_pSqlda);
+ m_pSqlda = nullptr;
+ }
+}
+
+// ---- XStatement -----------------------------------------------------------
+sal_Int32 SAL_CALL OStatement::executeUpdate(const OUString& sql)
+{
+ execute(sql);
+ return getStatementChangeCount();
+}
+
+
+uno::Reference< XResultSet > SAL_CALL OStatement::executeQuery(const OUString& sql)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OStatementCommonBase_Base::rBHelper.bDisposed);
+
+ SAL_INFO("connectivity.firebird", "executeQuery(" << sql << ")");
+
+ ISC_STATUS aErr = 0;
+
+ disposeResultSet();
+
+ prepareAndDescribeStatement(sql,
+ m_pSqlda);
+
+ aErr = isc_dsql_execute(m_statusVector,
+ &m_pConnection->getTransaction(),
+ &m_aStatementHandle,
+ 1,
+ nullptr);
+ if (aErr)
+ SAL_WARN("connectivity.firebird", "isc_dsql_execute failed");
+
+ m_xResultSet = new OResultSet(m_pConnection.get(),
+ m_aMutex,
+ uno::Reference< XInterface >(*this),
+ m_aStatementHandle,
+ m_pSqlda );
+
+ // TODO: deal with cleanup
+
+ evaluateStatusVector(m_statusVector, sql, *this);
+
+ if (isDDLStatement())
+ {
+ m_pConnection->commit();
+ m_pConnection->notifyDatabaseModified();
+ }
+ else if (getStatementChangeCount() > 0)
+ {
+ m_pConnection->notifyDatabaseModified();
+ }
+
+ return m_xResultSet;
+}
+
+sal_Bool SAL_CALL OStatement::execute(const OUString& sql)
+{
+ uno::Reference< XResultSet > xResults = executeQuery(sql);
+ return xResults.is();
+ // TODO: what if we have multiple results?
+}
+
+uno::Reference< XConnection > SAL_CALL OStatement::getConnection()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OStatementCommonBase_Base::rBHelper.bDisposed);
+
+ return m_pConnection;
+}
+
+Any SAL_CALL OStatement::queryInterface( const Type & rType )
+{
+ Any aRet = OStatement_Base::queryInterface(rType);
+ if(!aRet.hasValue())
+ aRet = ::cppu::queryInterface(rType,static_cast< XBatchExecution*> (this));
+ if(!aRet.hasValue())
+ aRet = OStatementCommonBase::queryInterface(rType);
+ return aRet;
+}
+
+uno::Sequence< Type > SAL_CALL OStatement::getTypes()
+{
+ return concatSequences(OStatement_Base::getTypes(),
+ OStatementCommonBase::getTypes());
+}
+
+void SAL_CALL OStatement::disposing()
+{
+ disposeResultSet();
+ close();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/connectivity/source/drivers/firebird/Statement.hxx b/connectivity/source/drivers/firebird/Statement.hxx
new file mode 100644
index 0000000000..d1b967def1
--- /dev/null
+++ b/connectivity/source/drivers/firebird/Statement.hxx
@@ -0,0 +1,84 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "StatementCommonBase.hxx"
+
+#include <cppuhelper/implbase1.hxx>
+#include <com/sun/star/sdbc/XBatchExecution.hpp>
+
+namespace connectivity::firebird
+ {
+
+ typedef ::cppu::ImplHelper1< css::sdbc::XStatement >
+ OStatement_Base;
+
+ class OStatement : public OStatementCommonBase,
+ public OStatement_Base,
+ public css::sdbc::XBatchExecution,
+ public css::lang::XServiceInfo
+ {
+ XSQLDA* m_pSqlda;
+ protected:
+ virtual ~OStatement() override {}
+
+ public:
+ // a constructor, which is required for returning objects:
+ explicit OStatement( Connection* _pConnection)
+ : OStatementCommonBase( _pConnection),
+ m_pSqlda(nullptr)
+ {}
+
+ virtual void disposeResultSet() override;
+
+ DECLARE_SERVICE_INFO();
+
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+
+ // XStatement
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL
+ executeQuery(const OUString& sql) override;
+ virtual sal_Int32 SAL_CALL executeUpdate(const OUString& sqlIn) override;
+ virtual sal_Bool SAL_CALL
+ execute(const OUString& sql) override;
+ virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL
+ getConnection() override;
+
+ // XBatchExecution - UNSUPPORTED
+ virtual void SAL_CALL addBatch( const OUString& sql ) override;
+ virtual void SAL_CALL clearBatch( ) override;
+ virtual css::uno::Sequence< sal_Int32 > SAL_CALL executeBatch( ) override;
+
+ // XInterface
+ virtual css::uno::Any SAL_CALL
+ queryInterface(const css::uno::Type & rType) override;
+
+ //XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL
+ getTypes() override;
+ // OComponentHelper
+ virtual void SAL_CALL disposing() override;
+
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/connectivity/source/drivers/firebird/StatementCommonBase.cxx b/connectivity/source/drivers/firebird/StatementCommonBase.cxx
new file mode 100644
index 0000000000..29ef592565
--- /dev/null
+++ b/connectivity/source/drivers/firebird/StatementCommonBase.cxx
@@ -0,0 +1,486 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "StatementCommonBase.hxx"
+#include "Util.hxx"
+
+#include <sal/log.hxx>
+#include <comphelper/sequence.hxx>
+#include <cppuhelper/typeprovider.hxx>
+#include <propertyids.hxx>
+#include <vcl/svapp.hxx>
+#include <TConnection.hxx>
+
+#include <com/sun/star/sdbc/SQLException.hpp>
+
+using namespace ::connectivity::firebird;
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::io;
+using namespace ::com::sun::star::util;
+
+using namespace ::comphelper;
+using namespace ::osl;
+
+OStatementCommonBase::OStatementCommonBase(Connection* _pConnection)
+ : OStatementCommonBase_Base(m_aMutex),
+ OPropertySetHelper(OStatementCommonBase_Base::rBHelper),
+ m_pConnection(_pConnection),
+#if SAL_TYPES_SIZEOFPOINTER == 8
+ m_aStatementHandle(0)
+#else
+ m_aStatementHandle(nullptr)
+#endif
+{
+}
+
+OStatementCommonBase::~OStatementCommonBase()
+{
+}
+
+void OStatementCommonBase::disposeResultSet()
+{
+ uno::Reference< XComponent > xComp(m_xResultSet, UNO_QUERY);
+ if (xComp.is())
+ xComp->dispose();
+ m_xResultSet.clear();
+}
+
+void OStatementCommonBase::freeStatementHandle()
+{
+ if (m_aStatementHandle)
+ {
+ isc_dsql_free_statement(m_statusVector,
+ &m_aStatementHandle,
+ DSQL_drop);
+ evaluateStatusVector(m_statusVector,
+ u"isc_dsql_free_statement",
+ *this);
+ }
+}
+
+
+Any SAL_CALL OStatementCommonBase::queryInterface( const Type & rType )
+{
+ Any aRet = OStatementCommonBase_Base::queryInterface(rType);
+ if(!aRet.hasValue())
+ aRet = OPropertySetHelper::queryInterface(rType);
+ return aRet;
+}
+
+Sequence< Type > SAL_CALL OStatementCommonBase::getTypes( )
+{
+ ::cppu::OTypeCollection aTypes(
+ ::cppu::UnoType<XMultiPropertySet>::get(),
+ ::cppu::UnoType<XFastPropertySet>::get(),
+ ::cppu::UnoType<XPropertySet>::get());
+
+ return concatSequences(aTypes.getTypes(),OStatementCommonBase_Base::getTypes());
+}
+
+
+void SAL_CALL OStatementCommonBase::cancel( )
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OStatementCommonBase_Base::rBHelper.bDisposed);
+ // cancel the current sql statement
+}
+
+void SAL_CALL OStatementCommonBase::close()
+{
+ SAL_INFO("connectivity.firebird", "close");
+
+ {
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OStatementCommonBase_Base::rBHelper.bDisposed);
+ disposeResultSet();
+ freeStatementHandle();
+ }
+
+ dispose();
+}
+
+void OStatementCommonBase::prepareAndDescribeStatement(std::u16string_view sql, XSQLDA*& pOutSqlda)
+{
+ SolarMutexGuard g; // tdf#122129
+
+ freeStatementHandle();
+
+ if (!pOutSqlda)
+ {
+ pOutSqlda = static_cast<XSQLDA*>(calloc(1, XSQLDA_LENGTH(10)));
+ pOutSqlda->version = SQLDA_VERSION1;
+ pOutSqlda->sqln = 10;
+ }
+
+ ISC_STATUS aErr = isc_dsql_allocate_statement(m_statusVector,
+ &m_pConnection->getDBHandle(),
+ &m_aStatementHandle);
+
+ if (aErr)
+ {
+ evaluateStatusVector(m_statusVector,
+ u"isc_dsql_allocate_statement",
+ *this);
+ }
+ else
+ {
+ aErr = isc_dsql_prepare(m_statusVector,
+ &m_pConnection->getTransaction(),
+ &m_aStatementHandle,
+ 0,
+ OUStringToOString(sql, RTL_TEXTENCODING_UTF8).getStr(),
+ SQL_DIALECT_CURRENT,
+ pOutSqlda);
+
+ if (aErr)
+ {
+ evaluateStatusVector(m_statusVector,
+ u"isc_dsql_prepare",
+ *this);
+ }
+ else
+ {
+ // Ensure we have enough space in pOutSqlda
+ if (pOutSqlda->sqld > pOutSqlda->sqln)
+ {
+ int n = pOutSqlda->sqld;
+ free(pOutSqlda);
+ pOutSqlda = static_cast<XSQLDA*>(calloc(1, XSQLDA_LENGTH(n)));
+ pOutSqlda->version = SQLDA_VERSION1;
+ pOutSqlda->sqln = n;
+ aErr = isc_dsql_describe(m_statusVector,
+ &m_aStatementHandle,
+ 1,
+ pOutSqlda);
+ }
+
+ // Process each XSQLVAR parameter structure in the output XSQLDA
+ if (aErr)
+ {
+ evaluateStatusVector(m_statusVector,
+ u"isc_dsql_describe",
+ *this);
+ }
+ else
+ {
+ mallocSQLVAR(pOutSqlda);
+ }
+ }
+ if(aErr)
+ {
+ freeStatementHandle();
+ }
+ }
+ if(aErr)
+ {
+ free(pOutSqlda);
+ pOutSqlda = nullptr;
+ }
+}
+
+// ---- XMultipleResults - UNSUPPORTED ----------------------------------------
+uno::Reference< XResultSet > SAL_CALL OStatementCommonBase::getResultSet()
+{
+ // TODO: verify we really can't support this
+// return uno::Reference< XResultSet >();
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OStatementCommonBase_Base::rBHelper.bDisposed);
+
+ return m_xResultSet;
+}
+
+sal_Bool SAL_CALL OStatementCommonBase::getMoreResults()
+{
+ // TODO: verify we really can't support this
+ return false;
+// MutexGuard aGuard( m_aMutex );
+// checkDisposed(OStatementCommonBase_Base::rBHelper.bDisposed);
+}
+
+sal_Int32 SAL_CALL OStatementCommonBase::getUpdateCount()
+{
+ // TODO: verify we really can't support this
+ return -1;
+}
+
+
+// ---- XWarningsSupplier - UNSUPPORTED ----------------------------------------
+Any SAL_CALL OStatementCommonBase::getWarnings()
+{
+ return Any();
+}
+
+void SAL_CALL OStatementCommonBase::clearWarnings()
+{
+}
+
+::cppu::IPropertyArrayHelper* OStatementCommonBase::createArrayHelper( ) const
+{
+ // this properties are define by the service statement
+ // they must in alphabetic order
+ return new ::cppu::OPropertyArrayHelper
+ {
+ {
+ {
+ ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_CURSORNAME),
+ PROPERTY_ID_CURSORNAME,
+ cppu::UnoType<OUString>::get(),
+ 0
+ },
+ {
+ ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ESCAPEPROCESSING),
+ PROPERTY_ID_ESCAPEPROCESSING,
+ cppu::UnoType<bool>::get(),
+ 0
+ },
+ {
+ ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHDIRECTION),
+ PROPERTY_ID_FETCHDIRECTION,
+ cppu::UnoType<sal_Int32>::get(),
+ 0
+ },
+ {
+ ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHSIZE),
+ PROPERTY_ID_FETCHSIZE,
+ cppu::UnoType<sal_Int32>::get(),
+ 0
+ },
+ {
+ ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_MAXFIELDSIZE),
+ PROPERTY_ID_MAXFIELDSIZE,
+ cppu::UnoType<sal_Int32>::get(),
+ 0
+ },
+ {
+ ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_MAXROWS),
+ PROPERTY_ID_MAXROWS,
+ cppu::UnoType<sal_Int32>::get(),
+ 0
+ },
+ {
+ ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_QUERYTIMEOUT),
+ PROPERTY_ID_QUERYTIMEOUT,
+ cppu::UnoType<sal_Int32>::get(),
+ 0
+ },
+ {
+ ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETCONCURRENCY),
+ PROPERTY_ID_RESULTSETCONCURRENCY,
+ cppu::UnoType<sal_Int32>::get(),
+ 0
+ },
+ {
+ ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETTYPE),
+ PROPERTY_ID_RESULTSETTYPE,
+ cppu::UnoType<sal_Int32>::get(),
+ 0
+ },
+ {
+ ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_USEBOOKMARKS),
+ PROPERTY_ID_USEBOOKMARKS,
+ cppu::UnoType<bool>::get(),
+ 0
+ }
+ }
+ };
+}
+
+
+::cppu::IPropertyArrayHelper & OStatementCommonBase::getInfoHelper()
+{
+ return *getArrayHelper();
+}
+
+sal_Bool OStatementCommonBase::convertFastPropertyValue(
+ Any &,
+ Any &,
+ sal_Int32,
+ const Any& )
+{
+ // here we have to try to convert
+ return false;
+}
+
+void OStatementCommonBase::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,const Any&)
+{
+ // set the value to whatever is necessary
+ switch(nHandle)
+ {
+ case PROPERTY_ID_QUERYTIMEOUT:
+ case PROPERTY_ID_MAXFIELDSIZE:
+ case PROPERTY_ID_MAXROWS:
+ case PROPERTY_ID_CURSORNAME:
+ case PROPERTY_ID_RESULTSETCONCURRENCY:
+ case PROPERTY_ID_RESULTSETTYPE:
+ case PROPERTY_ID_FETCHDIRECTION:
+ case PROPERTY_ID_FETCHSIZE:
+ case PROPERTY_ID_ESCAPEPROCESSING:
+ case PROPERTY_ID_USEBOOKMARKS:
+ default:
+ ;
+ }
+}
+
+void OStatementCommonBase::getFastPropertyValue(Any&,sal_Int32 nHandle) const
+{
+ switch(nHandle)
+ {
+ case PROPERTY_ID_QUERYTIMEOUT:
+ case PROPERTY_ID_MAXFIELDSIZE:
+ case PROPERTY_ID_MAXROWS:
+ case PROPERTY_ID_CURSORNAME:
+ case PROPERTY_ID_RESULTSETCONCURRENCY:
+ case PROPERTY_ID_RESULTSETTYPE:
+ case PROPERTY_ID_FETCHDIRECTION:
+ case PROPERTY_ID_FETCHSIZE:
+ case PROPERTY_ID_ESCAPEPROCESSING:
+ case PROPERTY_ID_USEBOOKMARKS:
+ default:
+ ;
+ }
+}
+
+void SAL_CALL OStatementCommonBase::acquire() noexcept
+{
+ OStatementCommonBase_Base::acquire();
+}
+
+void SAL_CALL OStatementCommonBase::release() noexcept
+{
+ OStatementCommonBase_Base::release();
+}
+
+uno::Reference< css::beans::XPropertySetInfo > SAL_CALL OStatementCommonBase::getPropertySetInfo( )
+{
+ return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper());
+}
+
+short OStatementCommonBase::getSqlInfoItem(char aInfoItem)
+{
+ ISC_STATUS_ARRAY aStatusVector;
+ ISC_STATUS aErr;
+
+ char aInfoItems[] = {aInfoItem};
+ char aResultsBuffer[8];
+
+ aErr = isc_dsql_sql_info(aStatusVector,
+ &m_aStatementHandle,
+ sizeof(aInfoItems),
+ aInfoItems,
+ sizeof(aResultsBuffer),
+ aResultsBuffer);
+
+ if (!aErr && aResultsBuffer[0] == aInfoItem)
+ {
+ const short aBytes = static_cast<short>(isc_vax_integer(aResultsBuffer+1, 2));
+ return static_cast<short>(isc_vax_integer(aResultsBuffer+3, aBytes));
+ }
+
+ evaluateStatusVector(aStatusVector,
+ u"isc_dsq_sql_info",
+ *this);
+ return 0;
+}
+
+bool OStatementCommonBase::isDDLStatement()
+{
+ return getSqlInfoItem(isc_info_sql_stmt_type) == isc_info_sql_stmt_ddl;
+}
+
+sal_Int32 OStatementCommonBase::getStatementChangeCount()
+{
+ const short aStatementType = getSqlInfoItem(isc_info_sql_stmt_type);
+
+
+ ISC_STATUS_ARRAY aStatusVector;
+ ISC_STATUS aErr;
+
+ // This is somewhat undocumented so I'm just guessing and hoping for the best.
+ char aInfoItems[] = {isc_info_sql_records};
+ char aResultsBuffer[1024];
+
+ aErr = isc_dsql_sql_info(aStatusVector,
+ &m_aStatementHandle,
+ sizeof(aInfoItems),
+ aInfoItems,
+ sizeof(aResultsBuffer),
+ aResultsBuffer);
+
+ if (aErr)
+ {
+ evaluateStatusVector(aStatusVector,
+ u"isc_dsq_sql_info",
+ *this);
+ return 0;
+ }
+
+ short aDesiredInfoType = 0;
+ switch (aStatementType)
+ {
+ case isc_info_sql_stmt_select:
+ aDesiredInfoType = isc_info_req_select_count;
+ break;
+ case isc_info_sql_stmt_insert:
+ aDesiredInfoType = isc_info_req_insert_count;
+ break;
+ case isc_info_sql_stmt_update:
+ aDesiredInfoType = isc_info_req_update_count;
+ break;
+ case isc_info_sql_stmt_delete:
+ aDesiredInfoType = isc_info_req_delete_count;
+ break;
+ case isc_info_sql_stmt_exec_procedure:
+ case isc_info_sql_stmt_ddl:
+ return 0; // cannot determine
+ default:
+ throw SQLException(); // TODO: better error message?
+ }
+
+ char* pResults = aResultsBuffer;
+ if (static_cast<short>(*pResults++) != isc_info_sql_records)
+ return 0;
+
+// const short aTotalLength = (short) isc_vax_integer(pResults, 2);
+ pResults += 2;
+
+ // Seems to be of form TOKEN (1 byte), LENGTH (2 bytes), DATA (LENGTH bytes)
+ while (*pResults != isc_info_rsb_end)
+ {
+ const char aToken = *pResults;
+ const short aLength = static_cast<short>(isc_vax_integer(pResults+1, 2));
+
+ if (aToken == aDesiredInfoType)
+ {
+ return isc_vax_integer(pResults + 3, aLength);
+ }
+
+ pResults += (3 + aLength);
+ }
+
+ return 0;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/connectivity/source/drivers/firebird/StatementCommonBase.hxx b/connectivity/source/drivers/firebird/StatementCommonBase.hxx
new file mode 100644
index 0000000000..fa9cd79027
--- /dev/null
+++ b/connectivity/source/drivers/firebird/StatementCommonBase.hxx
@@ -0,0 +1,134 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <string_view>
+
+#include "Connection.hxx"
+#include "SubComponent.hxx"
+
+#include <ibase.h>
+
+#include <cppuhelper/compbase.hxx>
+#include <rtl/ref.hxx>
+
+#include <com/sun/star/sdbc/XCloseable.hpp>
+#include <com/sun/star/sdbc/XMultipleResults.hpp>
+#include <com/sun/star/sdbc/XWarningsSupplier.hpp>
+#include <com/sun/star/util/XCancellable.hpp>
+
+namespace connectivity::firebird
+ {
+
+ typedef ::cppu::WeakComponentImplHelper< css::sdbc::XWarningsSupplier,
+ css::util::XCancellable,
+ css::sdbc::XCloseable,
+ css::sdbc::XMultipleResults> OStatementCommonBase_Base;
+
+ class OStatementCommonBase : public OStatementCommonBase_Base,
+ public ::cppu::OPropertySetHelper,
+ public OPropertyArrayUsageHelper<OStatementCommonBase>
+
+ {
+ protected:
+ ::osl::Mutex m_aMutex;
+
+ css::uno::Reference< css::sdbc::XResultSet> m_xResultSet; // The last ResultSet created
+ // for this Statement
+
+ ::rtl::Reference<Connection> m_pConnection;
+
+ ISC_STATUS_ARRAY m_statusVector;
+ isc_stmt_handle m_aStatementHandle;
+
+ protected:
+ virtual void disposeResultSet();
+ /// @throws css::sdbc::SQLException
+ void freeStatementHandle();
+
+ // OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override;
+ // OPropertySetHelper
+ using OPropertySetHelper::getFastPropertyValue;
+ virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override;
+ virtual sal_Bool SAL_CALL convertFastPropertyValue(
+ css::uno::Any & rConvertedValue,
+ css::uno::Any & rOldValue,
+ sal_Int32 nHandle,
+ const css::uno::Any& rValue ) override;
+ virtual void SAL_CALL setFastPropertyValue_NoBroadcast(
+ sal_Int32 nHandle,
+ const css::uno::Any& rValue) override;
+ virtual void SAL_CALL getFastPropertyValue(
+ css::uno::Any& rValue,
+ sal_Int32 nHandle) const override;
+ virtual ~OStatementCommonBase() override;
+
+ /// @throws css::sdbc::SQLException
+ void prepareAndDescribeStatement(std::u16string_view sqlIn, XSQLDA*& pOutSqlda);
+
+ /// @throws css::sdbc::SQLException
+ short getSqlInfoItem(char aInfoItem);
+ /// @throws css::sdbc::SQLException
+ bool isDDLStatement();
+ /// @throws css::sdbc::SQLException
+ sal_Int32 getStatementChangeCount();
+
+ public:
+
+ explicit OStatementCommonBase(Connection* _pConnection);
+ using OStatementCommonBase_Base::operator css::uno::Reference< css::uno::XInterface >;
+
+ // OComponentHelper
+ virtual void SAL_CALL disposing() override {
+ disposeResultSet();
+ OStatementCommonBase_Base::disposing();
+ }
+ // XInterface
+ virtual void SAL_CALL release() noexcept override;
+ virtual void SAL_CALL acquire() noexcept override;
+ // XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ //XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override;
+
+ // XPropertySet
+ virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override;
+
+ // XWarningsSupplier - UNSUPPORTED
+ virtual css::uno::Any SAL_CALL getWarnings( ) override;
+ virtual void SAL_CALL clearWarnings( ) override;
+ // XMultipleResults - UNSUPPORTED
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getResultSet( ) override;
+ virtual sal_Int32 SAL_CALL getUpdateCount( ) override;
+ virtual sal_Bool SAL_CALL getMoreResults( ) override;
+
+ // XCancellable
+ virtual void SAL_CALL cancel( ) override;
+ // XCloseable
+ virtual void SAL_CALL close( ) override;
+
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/connectivity/source/drivers/firebird/SubComponent.hxx b/connectivity/source/drivers/firebird/SubComponent.hxx
new file mode 100644
index 0000000000..bea5d76d42
--- /dev/null
+++ b/connectivity/source/drivers/firebird/SubComponent.hxx
@@ -0,0 +1,111 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <cppuhelper/propshlp.hxx>
+#include <osl/diagnose.h>
+#include <osl/mutex.hxx>
+
+namespace cppu { class IPropertyArrayHelper; }
+namespace com::sun::star::lang { class XComponent; }
+
+namespace connectivity::firebird
+ {
+ /// @throws css::lang::DisposedException
+ void checkDisposed(bool _bThrow);
+
+
+ template <class TYPE>
+ class OPropertyArrayUsageHelper
+ {
+ protected:
+ static sal_Int32 s_nRefCount;
+ static ::cppu::IPropertyArrayHelper* s_pProps;
+ static ::osl::Mutex s_aMutex;
+
+ public:
+ OPropertyArrayUsageHelper();
+ virtual ~OPropertyArrayUsageHelper();
+
+ /** call this in the getInfoHelper method of your derived class. The method returns the array helper of the
+ class, which is created if necessary.
+ */
+ ::cppu::IPropertyArrayHelper* getArrayHelper();
+
+ protected:
+ /** used to implement the creation of the array helper which is shared amongst all instances of the class.
+ This method needs to be implemented in derived classes.
+ <BR>
+ The method gets called with s_aMutex acquired.
+ @return a pointer to the newly created array helper. Must not be NULL.
+ */
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const = 0;
+ };
+
+ template<class TYPE>
+ sal_Int32 OPropertyArrayUsageHelper< TYPE >::s_nRefCount = 0;
+
+ template<class TYPE>
+ ::cppu::IPropertyArrayHelper* OPropertyArrayUsageHelper< TYPE >::s_pProps = nullptr;
+
+ template<class TYPE>
+ ::osl::Mutex OPropertyArrayUsageHelper< TYPE >::s_aMutex;
+
+
+ template <class TYPE>
+ OPropertyArrayUsageHelper<TYPE>::OPropertyArrayUsageHelper()
+ {
+ ::osl::MutexGuard aGuard(s_aMutex);
+ ++s_nRefCount;
+ }
+
+
+ template <class TYPE>
+ OPropertyArrayUsageHelper<TYPE>::~OPropertyArrayUsageHelper()
+ {
+ ::osl::MutexGuard aGuard(s_aMutex);
+ OSL_ENSURE(s_nRefCount > 0, "OPropertyArrayUsageHelper::~OPropertyArrayUsageHelper : suspicious call : have a refcount of 0 !");
+ if (!--s_nRefCount)
+ {
+ delete s_pProps;
+ s_pProps = nullptr;
+ }
+ }
+
+
+ template <class TYPE>
+ ::cppu::IPropertyArrayHelper* OPropertyArrayUsageHelper<TYPE>::getArrayHelper()
+ {
+ OSL_ENSURE(s_nRefCount, "OPropertyArrayUsageHelper::getArrayHelper : suspicious call : have a refcount of 0 !");
+ if (!s_pProps)
+ {
+ ::osl::MutexGuard aGuard(s_aMutex);
+ if (!s_pProps)
+ {
+ s_pProps = createArrayHelper();
+ OSL_ENSURE(s_pProps, "OPropertyArrayUsageHelper::getArrayHelper : createArrayHelper returned nonsense !");
+ }
+ }
+ return s_pProps;
+ }
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/connectivity/source/drivers/firebird/Table.cxx b/connectivity/source/drivers/firebird/Table.cxx
new file mode 100644
index 0000000000..871febcf51
--- /dev/null
+++ b/connectivity/source/drivers/firebird/Table.cxx
@@ -0,0 +1,232 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "Columns.hxx"
+#include "Indexes.hxx"
+#include "Keys.hxx"
+#include "Table.hxx"
+
+#include <TConnection.hxx>
+
+#include <sal/log.hxx>
+#include <comphelper/sequence.hxx>
+#include <connectivity/dbtools.hxx>
+
+#include <com/sun/star/sdbc/ColumnValue.hpp>
+#include <com/sun/star/sdbcx/Privilege.hpp>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+
+using namespace ::connectivity;
+using namespace ::connectivity::firebird;
+using namespace ::connectivity::sdbcx;
+
+using namespace ::osl;
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::uno;
+
+Table::Table(Tables* pTables,
+ Mutex& rMutex,
+ const uno::Reference< XConnection >& rConnection):
+ OTableHelper(pTables,
+ rConnection,
+ true),
+ m_rMutex(rMutex),
+ m_nPrivileges(0)
+{
+ construct();
+}
+
+Table::Table(Tables* pTables,
+ Mutex& rMutex,
+ const uno::Reference< XConnection >& rConnection,
+ const OUString& rName,
+ const OUString& rType,
+ const OUString& rDescription):
+ OTableHelper(pTables,
+ rConnection,
+ true,
+ rName,
+ rType,
+ rDescription,
+ "",
+ ""),
+ m_rMutex(rMutex),
+ m_nPrivileges(0)
+{
+ construct();
+}
+
+void Table::construct()
+{
+ OTableHelper::construct();
+ if (isNew())
+ return;
+
+ // TODO: get privileges when in non-embedded mode.
+ m_nPrivileges = Privilege::DROP |
+ Privilege::REFERENCE |
+ Privilege::ALTER |
+ Privilege::CREATE |
+ Privilege::READ |
+ Privilege::DELETE |
+ Privilege::UPDATE |
+ Privilege::INSERT |
+ Privilege::SELECT;
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PRIVILEGES),
+ PROPERTY_ID_PRIVILEGES,
+ PropertyAttribute::READONLY,
+ &m_nPrivileges,
+ cppu::UnoType<decltype(m_nPrivileges)>::get());
+}
+//----- OTableHelper ---------------------------------------------------------
+OCollection* Table::createColumns(const ::std::vector< OUString>& rNames)
+{
+ return new Columns(*this,
+ m_rMutex,
+ rNames);
+}
+
+OCollection* Table::createKeys(const ::std::vector< OUString>& rNames)
+{
+ return new Keys(this,
+ m_rMutex,
+ rNames);
+}
+
+OCollection* Table::createIndexes(const ::std::vector< OUString>& rNames)
+{
+ return new Indexes(this,
+ m_rMutex,
+ rNames);
+}
+
+//----- XAlterTable -----------------------------------------------------------
+void SAL_CALL Table::alterColumnByName(const OUString& rColName,
+ const uno::Reference< XPropertySet >& rDescriptor)
+{
+ MutexGuard aGuard(m_rMutex);
+ checkDisposed(WeakComponentImplHelperBase::rBHelper.bDisposed);
+
+ uno::Reference< XPropertySet > xColumn(m_xColumns->getByName(rColName), UNO_QUERY);
+
+ // sdbcx::Descriptor
+ const bool bNameChanged = xColumn->getPropertyValue("Name") != rDescriptor->getPropertyValue("Name");
+ // sdbcx::ColumnDescriptor
+ const bool bTypeChanged = xColumn->getPropertyValue("Type") != rDescriptor->getPropertyValue("Type");
+ const bool bTypeNameChanged = xColumn->getPropertyValue("TypeName") != rDescriptor->getPropertyValue("TypeName");
+ const bool bPrecisionChanged = xColumn->getPropertyValue("Precision") != rDescriptor->getPropertyValue("Precision");
+ const bool bScaleChanged = xColumn->getPropertyValue("Scale") != rDescriptor->getPropertyValue("Scale");
+ const bool bIsNullableChanged = xColumn->getPropertyValue("IsNullable") != rDescriptor->getPropertyValue("IsNullable");
+ const bool bIsAutoIncrementChanged = xColumn->getPropertyValue("IsAutoIncrement") != rDescriptor->getPropertyValue("IsAutoIncrement");
+
+ // TODO: remainder -- these are all "optional" so have to detect presence and change.
+
+ bool bDefaultChanged = xColumn->getPropertyValue("DefaultValue")
+ != rDescriptor->getPropertyValue("DefaultValue");
+
+ if (bTypeChanged || bTypeNameChanged || bPrecisionChanged || bScaleChanged)
+ {
+ // If bPrecisionChanged this will only succeed if we have increased the
+ // precision, otherwise an exception is thrown -- however the base
+ // gui then offers to delete and recreate the column.
+ OUString sSql(getAlterTableColumn(rColName) + "TYPE " +
+ ::dbtools::createStandardTypePart(rDescriptor, getConnection()));
+ getConnection()->createStatement()->execute(sSql);
+ // TODO: could cause errors e.g. if incompatible types, deal with them here as appropriate.
+ // possibly we have to wrap things in Util::evaluateStatusVector.
+ }
+
+ if (bIsNullableChanged)
+ {
+ sal_Int32 nNullable = 0;
+ rDescriptor->getPropertyValue("IsNullable") >>= nNullable;
+
+ if (nNullable != ColumnValue::NULLABLE_UNKNOWN)
+ {
+
+ OUString sSql(getAlterTableColumn(rColName));
+ if (nNullable == ColumnValue::NULLABLE)
+ {
+ sSql += "DROP NOT NULL";
+ }
+ else if (nNullable == ColumnValue::NO_NULLS)
+ {
+ sSql += "SET NOT NULL";
+ }
+ getConnection()->createStatement()->execute(sSql);
+ }
+ else
+ {
+ SAL_WARN("connectivity.firebird", "Attempting to set Nullable to NULLABLE_UNKNOWN");
+ }
+ }
+
+ if (bIsAutoIncrementChanged)
+ {
+ ::dbtools::throwSQLException(
+ "Changing autoincrement property of existing column is not supported",
+ ::dbtools::StandardSQLState::FUNCTION_NOT_SUPPORTED,
+ *this);
+
+ }
+
+ if (bDefaultChanged)
+ {
+ OUString sNewDefault;
+ rDescriptor->getPropertyValue("DefaultValue") >>= sNewDefault;
+
+ OUString sSql;
+ if (sNewDefault.isEmpty())
+ sSql = getAlterTableColumn(rColName) + "DROP DEFAULT";
+ else
+ sSql = getAlterTableColumn(rColName) + "SET DEFAULT " + sNewDefault;
+
+ getConnection()->createStatement()->execute(sSql);
+ }
+ // TODO: quote identifiers as needed.
+ if (bNameChanged)
+ {
+ OUString sNewColName;
+ rDescriptor->getPropertyValue("Name") >>= sNewColName;
+ OUString sSql(getAlterTableColumn(rColName)
+ + " TO \"" + sNewColName + "\"");
+
+ getConnection()->createStatement()->execute(sSql);
+ }
+
+
+ m_xColumns->refresh();
+}
+
+// ----- XRename --------------------------------------------------------------
+void SAL_CALL Table::rename(const OUString&)
+{
+ throw RuntimeException("Table renaming not supported by Firebird.");
+}
+
+// ----- XInterface -----------------------------------------------------------
+Any SAL_CALL Table::queryInterface(const Type& rType)
+{
+ if (rType.getTypeName() == "com.sun.star.sdbcx.XRename")
+ return Any();
+
+ return OTableHelper::queryInterface(rType);
+}
+
+OUString Table::getAlterTableColumn(std::u16string_view rColumn)
+{
+ return ("ALTER TABLE \"" + getName() + "\" ALTER COLUMN \"" + rColumn + "\" ");
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/connectivity/source/drivers/firebird/Table.hxx b/connectivity/source/drivers/firebird/Table.hxx
new file mode 100644
index 0000000000..ed638a9c88
--- /dev/null
+++ b/connectivity/source/drivers/firebird/Table.hxx
@@ -0,0 +1,81 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <string_view>
+
+#include "Tables.hxx"
+
+#include <connectivity/TTableHelper.hxx>
+
+namespace connectivity::firebird
+ {
+
+ /**
+ * Implements sdbcx.Table. We don't support table renaming (XRename)
+ * hence the appropriate methods are overridden.
+ */
+ class Table: public OTableHelper
+ {
+ private:
+ ::osl::Mutex& m_rMutex;
+ sal_Int32 m_nPrivileges;
+
+ /**
+ * Get the ALTER TABLE [TABLE] ALTER [COLUMN] String.
+ * Includes a trailing space.
+ */
+ OUString getAlterTableColumn(std::u16string_view rColumn);
+
+ protected:
+ void construct() override;
+
+ public:
+ Table(Tables* pTables,
+ ::osl::Mutex& rMutex,
+ const css::uno::Reference< css::sdbc::XConnection >& _xConnection);
+ Table(Tables* pTables,
+ ::osl::Mutex& rMutex,
+ const css::uno::Reference< css::sdbc::XConnection >& _xConnection,
+ const OUString& rName,
+ const OUString& rType,
+ const OUString& rDescription);
+
+ // OTableHelper
+ virtual ::connectivity::sdbcx::OCollection* createColumns(
+ const ::std::vector< OUString>& rNames) override;
+ virtual ::connectivity::sdbcx::OCollection* createKeys(
+ const ::std::vector< OUString>& rNames) override;
+ virtual ::connectivity::sdbcx::OCollection* createIndexes(
+ const ::std::vector< OUString>& rNames) override;
+
+ // XAlterTable
+ /**
+ * See css::sdbcx::ColumnDescriptor for details of
+ * rDescriptor.
+ */
+ virtual void SAL_CALL alterColumnByName(
+ const OUString& rColName,
+ const css::uno::Reference< css::beans::XPropertySet >& rDescriptor) override;
+
+ // XRename -- UNSUPPORTED
+ virtual void SAL_CALL rename(const OUString& sName) override;
+
+ //XInterface
+ virtual css::uno::Any
+ SAL_CALL queryInterface(const css::uno::Type & rType) override;
+
+ };
+
+} // namespace connectivity::firebird
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/connectivity/source/drivers/firebird/Tables.cxx b/connectivity/source/drivers/firebird/Tables.cxx
new file mode 100644
index 0000000000..8b69044bef
--- /dev/null
+++ b/connectivity/source/drivers/firebird/Tables.cxx
@@ -0,0 +1,226 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "Table.hxx"
+#include "Tables.hxx"
+#include "Views.hxx"
+#include "Catalog.hxx"
+
+#include <TConnection.hxx>
+
+#include <connectivity/dbtools.hxx>
+
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/ColumnValue.hpp>
+#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
+#include <comphelper/types.hxx>
+
+using namespace ::connectivity;
+using namespace ::connectivity::firebird;
+using namespace ::connectivity::sdbcx;
+using namespace ::cppu;
+using namespace ::osl;
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::uno;
+
+
+//----- OCollection -----------------------------------------------------------
+void Tables::impl_refresh()
+{
+ static_cast<Catalog&>(m_rParent).refreshTables();
+}
+
+ObjectType Tables::createObject(const OUString& rName)
+{
+ // Only retrieving a single table, so table type is irrelevant (param 4)
+ uno::Reference< XResultSet > xTables = m_xMetaData->getTables(Any(),
+ OUString(),
+ rName,
+ uno::Sequence< OUString >());
+
+ if (!xTables.is())
+ throw RuntimeException("Could not acquire table.");
+
+ uno::Reference< XRow > xRow(xTables,UNO_QUERY_THROW);
+
+ if (!xTables->next())
+ throw RuntimeException();
+
+ ObjectType xRet(new Table(this,
+ m_rMutex,
+ m_xMetaData->getConnection(),
+ xRow->getString(3), // Name
+ xRow->getString(4), // Type
+ xRow->getString(5))); // Description / Remarks / Comments
+
+ if (xTables->next())
+ throw RuntimeException("Found more tables than expected.");
+
+ return xRet;
+}
+
+OUString Tables::createStandardColumnPart(const Reference< XPropertySet >& xColProp,const Reference< XConnection>& _xConnection)
+{
+ Reference<XDatabaseMetaData> xMetaData = _xConnection->getMetaData();
+
+ ::dbtools::OPropertyMap& rPropMap = OMetaConnection::getPropMap();
+
+ bool bIsAutoIncrement = false;
+ xColProp->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_ISAUTOINCREMENT)) >>= bIsAutoIncrement;
+
+ const OUString sQuoteString = xMetaData->getIdentifierQuoteString();
+ OUStringBuffer aSql(::dbtools::quoteName(sQuoteString,::comphelper::getString(xColProp->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_NAME)))));
+
+ // check if the user enter a specific string to create autoincrement values
+ OUString sAutoIncrementValue;
+ Reference<XPropertySetInfo> xPropInfo = xColProp->getPropertySetInfo();
+
+ if ( xPropInfo.is() && xPropInfo->hasPropertyByName(rPropMap.getNameByIndex(PROPERTY_ID_AUTOINCREMENTCREATION)) )
+ xColProp->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_AUTOINCREMENTCREATION)) >>= sAutoIncrementValue;
+
+ aSql.append(" "
+ + dbtools::createStandardTypePart(xColProp, _xConnection));
+ // Add character set for (VAR)BINARY (fix) types:
+ // (VAR) BINARY is distinguished from other CHAR types by its character set.
+ // Octets is a special character set for binary data.
+ if ( xPropInfo.is() && xPropInfo->hasPropertyByName(rPropMap.getNameByIndex(
+ PROPERTY_ID_TYPE)) )
+ {
+ sal_Int32 aType = 0;
+ xColProp->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_TYPE))
+ >>= aType;
+ if(aType == DataType::BINARY || aType == DataType::VARBINARY)
+ {
+ aSql.append(" CHARACTER SET OCTETS");
+ }
+ }
+
+ if ( bIsAutoIncrement && !sAutoIncrementValue.isEmpty())
+ {
+ aSql.append(" " + sAutoIncrementValue);
+ }
+ // AutoIncrement "IDENTITY" is implicitly "NOT NULL"
+ else if(::comphelper::getINT32(xColProp->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_ISNULLABLE))) == ColumnValue::NO_NULLS)
+ aSql.append(" NOT NULL");
+
+ return aSql.makeStringAndClear();
+}
+
+uno::Reference< XPropertySet > Tables::createDescriptor()
+{
+ // There is some internal magic so that the same class can be used as either
+ // a descriptor or as a normal table. See VTable.cxx for the details. In our
+ // case we just need to ensure we use the correct constructor.
+ return new Table(this, m_rMutex, m_xMetaData->getConnection());
+}
+
+//----- XAppend ---------------------------------------------------------------
+ObjectType Tables::appendObject(const OUString& rName,
+ const uno::Reference< XPropertySet >& rDescriptor)
+{
+ /* OUString sSql(::dbtools::createSqlCreateTableStatement(rDescriptor,
+ m_xMetaData->getConnection())); */
+ OUStringBuffer aSqlBuffer("CREATE TABLE ");
+ OUString sCatalog, sSchema, sComposedName, sTable;
+ const Reference< XConnection>& xConnection = m_xMetaData->getConnection();
+
+ ::dbtools::OPropertyMap& rPropMap = OMetaConnection::getPropMap();
+
+ rDescriptor->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_CATALOGNAME)) >>= sCatalog;
+ rDescriptor->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_SCHEMANAME)) >>= sSchema;
+ rDescriptor->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_NAME)) >>= sTable;
+
+ sComposedName = ::dbtools::composeTableName(m_xMetaData, sCatalog, sSchema, sTable, true, ::dbtools::EComposeRule::InTableDefinitions );
+ if ( sComposedName.isEmpty() )
+ ::dbtools::throwFunctionSequenceException(xConnection);
+
+ aSqlBuffer.append(sComposedName
+ + " (");
+
+ // columns
+ Reference<XColumnsSupplier> xColumnSup(rDescriptor,UNO_QUERY);
+ Reference<XIndexAccess> xColumns(xColumnSup->getColumns(),UNO_QUERY);
+ // check if there are columns
+ if(!xColumns.is() || !xColumns->getCount())
+ ::dbtools::throwFunctionSequenceException(xConnection);
+
+ Reference< XPropertySet > xColProp;
+
+ sal_Int32 nCount = xColumns->getCount();
+ for(sal_Int32 i=0;i<nCount;++i)
+ {
+ if ( (xColumns->getByIndex(i) >>= xColProp) && xColProp.is() )
+ {
+ aSqlBuffer.append(createStandardColumnPart(xColProp,xConnection)
+ + ",");
+ }
+ }
+ OUString sSql = aSqlBuffer.makeStringAndClear();
+
+ const OUString sKeyStmt = ::dbtools::createStandardKeyStatement(rDescriptor,xConnection);
+ if ( !sKeyStmt.isEmpty() )
+ sSql += sKeyStmt;
+ else
+ {
+ if ( sSql.endsWith(",") )
+ sSql = sSql.replaceAt(sSql.getLength()-1, 1, u")");
+ else
+ sSql += ")";
+ }
+
+ m_xMetaData->getConnection()->createStatement()->execute(sSql);
+
+ return createObject(rName);
+}
+
+//----- XDrop -----------------------------------------------------------------
+void Tables::dropObject(sal_Int32 nPosition, const OUString& sName)
+{
+ uno::Reference< XPropertySet > xTable(getObject(nPosition));
+
+ if (ODescriptor::isNew(xTable))
+ return;
+
+ OUString sType;
+ xTable->getPropertyValue("Type") >>= sType;
+
+ const OUString sQuoteString = m_xMetaData->getIdentifierQuoteString();
+
+ m_xMetaData->getConnection()->createStatement()->execute(
+ "DROP " + sType + " " + ::dbtools::quoteName(sQuoteString,sName));
+
+ if (sType == "VIEW")
+ {
+ Views* pViews = static_cast<Views*>(static_cast<Catalog&>(m_rParent).getPrivateViews());
+ if ( pViews && pViews->hasByName(sName) )
+ pViews->dropByNameImpl(sName);
+ }
+}
+
+void connectivity::firebird::Tables::appendNew(const OUString& _rsNewTable)
+{
+ insertElement(_rsNewTable, nullptr);
+
+ // notify our container listeners
+ css::container::ContainerEvent aEvent(static_cast<XContainer*>(this),
+ css::uno::Any(_rsNewTable), css::uno::Any(),
+ css::uno::Any());
+ comphelper::OInterfaceIteratorHelper3 aListenerLoop(m_aContainerListeners);
+ while (aListenerLoop.hasMoreElements())
+ aListenerLoop.next()->elementInserted(aEvent);
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/connectivity/source/drivers/firebird/Tables.hxx b/connectivity/source/drivers/firebird/Tables.hxx
new file mode 100644
index 0000000000..ada1827097
--- /dev/null
+++ b/connectivity/source/drivers/firebird/Tables.hxx
@@ -0,0 +1,61 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <com/sun/star/sdbc/XDatabaseMetaData.hpp>
+
+#include <connectivity/sdbcx/VCollection.hxx>
+#include <utility>
+
+namespace connectivity::firebird
+ {
+
+ /**
+ * This implements com.sun.star.sdbcx.Container, which seems to be
+ * also known by the name of Tables and Collection.
+ */
+ class Tables: public ::connectivity::sdbcx::OCollection
+ {
+ protected:
+ css::uno::Reference< css::sdbc::XDatabaseMetaData >
+ m_xMetaData;
+
+ static OUString createStandardColumnPart(const css::uno::Reference< css::beans::XPropertySet >& xColProp,const css::uno::Reference< com::sun::star::sdbc::XConnection>& _xConnection);
+
+ // OCollection
+ virtual void impl_refresh() override;
+ virtual ::connectivity::sdbcx::ObjectType createObject(
+ const OUString& rName) override;
+ virtual css::uno::Reference< css::beans::XPropertySet >
+ createDescriptor() override;
+ virtual ::connectivity::sdbcx::ObjectType appendObject(
+ const OUString& rName,
+ const css::uno::Reference< css::beans::XPropertySet >& rDescriptor) override;
+
+ public:
+ Tables(css::uno::Reference< css::sdbc::XDatabaseMetaData > xMetaData,
+ ::cppu::OWeakObject& rParent,
+ ::osl::Mutex& rMutex,
+ ::std::vector< OUString> const & rNames) : sdbcx::OCollection(rParent, true, rMutex, rNames), m_xMetaData(std::move(xMetaData)) {}
+
+ // TODO: we should also implement XDataDescriptorFactory, XRefreshable,
+ // XAppend, etc., but all are optional.
+
+ // XDrop
+ virtual void dropObject(sal_Int32 nPosition, const OUString& rName) override;
+
+ void appendNew(const OUString& _rsNewTable);
+
+ };
+
+} // namespace connectivity::firebird
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/connectivity/source/drivers/firebird/User.cxx b/connectivity/source/drivers/firebird/User.cxx
new file mode 100644
index 0000000000..9f647713a6
--- /dev/null
+++ b/connectivity/source/drivers/firebird/User.cxx
@@ -0,0 +1,53 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "User.hxx"
+
+using namespace ::connectivity;
+using namespace ::connectivity::firebird;
+using namespace ::connectivity::sdbcx;
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::sdbc;
+
+User::User(const css::uno::Reference< css::sdbc::XConnection >& rConnection):
+ OUser(true) // Case Sensitive
+ , m_xConnection(rConnection)
+{}
+
+User::User(const css::uno::Reference< css::sdbc::XConnection >& rConnection, const OUString& rName):
+ OUser(rName,
+ true) // Case Sensitive
+ , m_xConnection(rConnection)
+{}
+
+void User::changePassword(const OUString&, const OUString& newPassword)
+{
+ m_xConnection->createStatement()->execute("ALTER USER " + m_Name + " PASSWORD '" + newPassword + "'");
+}
+
+sal_Int32 User::getPrivileges(const OUString& , sal_Int32 )
+{
+ // TODO: implement.
+ return 0;
+}
+
+sal_Int32 User::getGrantablePrivileges(const OUString& , sal_Int32 )
+{
+ // TODO: implement.
+ return 0;
+}
+
+//----- IRefreshableGroups ----------------------------------------------------
+void User::refreshGroups()
+{
+ // TODO: implement.
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/connectivity/source/drivers/firebird/User.hxx b/connectivity/source/drivers/firebird/User.hxx
new file mode 100644
index 0000000000..e47565f5d5
--- /dev/null
+++ b/connectivity/source/drivers/firebird/User.hxx
@@ -0,0 +1,46 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include <sdbcx/VUser.hxx>
+#include <com/sun/star/sdbc/XConnection.hpp>
+
+namespace connectivity::firebird
+ {
+
+ /**
+ * This implements com.sun.star.sdbcx.Container.
+ */
+ class User: public ::connectivity::sdbcx::OUser
+ {
+ css::uno::Reference< css::sdbc::XConnection > m_xConnection;
+
+ public:
+ /**
+ * Create a "new" descriptor, which isn't yet in the database.
+ */
+ User(const css::uno::Reference< css::sdbc::XConnection >& rConnection);
+ /**
+ * For a user that already exists in the db.
+ */
+ User(const css::uno::Reference< css::sdbc::XConnection >& rConnection, const OUString& rName);
+
+ // XAuthorizable
+ virtual void SAL_CALL changePassword(const OUString&, const OUString& newPassword) override;
+ virtual sal_Int32 SAL_CALL getPrivileges(const OUString&, sal_Int32) override;
+ virtual sal_Int32 SAL_CALL getGrantablePrivileges(const OUString&, sal_Int32) override;
+
+ // IRefreshableGroups::
+ virtual void refreshGroups() override;
+ };
+
+} // namespace connectivity::firebird
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/connectivity/source/drivers/firebird/Users.cxx b/connectivity/source/drivers/firebird/Users.cxx
new file mode 100644
index 0000000000..50cfef84be
--- /dev/null
+++ b/connectivity/source/drivers/firebird/Users.cxx
@@ -0,0 +1,78 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "User.hxx"
+#include "Users.hxx"
+
+using namespace ::connectivity;
+using namespace ::connectivity::firebird;
+using namespace ::connectivity::sdbcx;
+using namespace ::cppu;
+using namespace ::osl;
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::uno;
+
+
+Users::Users(const uno::Reference< XDatabaseMetaData >& rMetaData,
+ OWeakObject& rParent,
+ Mutex& rMutex,
+ ::std::vector< OUString> const & rNames) :
+ OCollection(rParent,
+ true,
+ rMutex,
+ rNames),
+ m_xMetaData(rMetaData)
+{
+}
+
+//----- OCollection -----------------------------------------------------------
+void Users::impl_refresh()
+{
+ // TODO: IMPLEMENT ME
+}
+
+ObjectType Users::createObject(const OUString& rName)
+{
+ return new User(m_xMetaData->getConnection(), rName);
+}
+
+uno::Reference< XPropertySet > Users::createDescriptor()
+{
+ // There is some internal magic so that the same class can be used as either
+ // a descriptor or as a normal user. See VUser.cxx for the details. In our
+ // case we just need to ensure we use the correct constructor.
+ return new User(m_xMetaData->getConnection());
+}
+
+//----- XAppend ---------------------------------------------------------------
+ObjectType Users::appendObject(const OUString& rName,
+ const uno::Reference< XPropertySet >&)
+{
+ // TODO: set sSql as appropriate
+ m_xMetaData->getConnection()->createStatement()->execute(OUString());
+
+ return createObject(rName);
+}
+
+//----- XDrop -----------------------------------------------------------------
+void Users::dropObject(sal_Int32 nPosition, const OUString&)
+{
+ uno::Reference< XPropertySet > xUser(getObject(nPosition));
+
+ if (!ODescriptor::isNew(xUser))
+ {
+ // TODO: drop me
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/connectivity/source/drivers/firebird/Users.hxx b/connectivity/source/drivers/firebird/Users.hxx
new file mode 100644
index 0000000000..7e78444d11
--- /dev/null
+++ b/connectivity/source/drivers/firebird/Users.hxx
@@ -0,0 +1,53 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include <connectivity/sdbcx/VCollection.hxx>
+#include <com/sun/star/sdbc/XDatabaseMetaData.hpp>
+
+namespace connectivity::firebird
+ {
+
+ /**
+ * This implements com.sun.star.sdbcx.Container.
+ */
+ class Users: public ::connectivity::sdbcx::OCollection
+ {
+ css::uno::Reference< css::sdbc::XDatabaseMetaData >
+ m_xMetaData;
+ protected:
+
+ // OCollection
+ virtual void impl_refresh() override;
+ virtual ::connectivity::sdbcx::ObjectType createObject(
+ const OUString& rName) override;
+ virtual css::uno::Reference< css::beans::XPropertySet >
+ createDescriptor() override;
+ virtual ::connectivity::sdbcx::ObjectType appendObject(
+ const OUString& rName,
+ const css::uno::Reference< css::beans::XPropertySet >& rDescriptor) override;
+
+ public:
+ Users(const css::uno::Reference< css::sdbc::XDatabaseMetaData >& rMetaData,
+ ::cppu::OWeakObject& rParent,
+ ::osl::Mutex& rMutex,
+ ::std::vector< OUString> const & rNames);
+
+ // TODO: we should also implement XDataDescriptorFactory, XRefreshable,
+ // XAppend, etc., but all are optional.
+
+ // XDrop
+ virtual void dropObject(sal_Int32 nPosition, const OUString& rName) override;
+
+ };
+
+} // namespace connectivity::firebird
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/connectivity/source/drivers/firebird/Util.cxx b/connectivity/source/drivers/firebird/Util.cxx
new file mode 100644
index 0000000000..3cee5dab6e
--- /dev/null
+++ b/connectivity/source/drivers/firebird/Util.cxx
@@ -0,0 +1,424 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "Util.hxx"
+#include <rtl/ustrbuf.hxx>
+#include <sal/log.hxx>
+
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <o3tl/string_view.hxx>
+
+using namespace ::connectivity;
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::uno;
+
+using namespace firebird;
+
+OUString firebird::sanitizeIdentifier(std::u16string_view rIdentifier)
+{
+ std::u16string_view sRet = o3tl::trim(rIdentifier);
+ assert(sRet.size() <= 31); // Firebird identifiers cannot be longer than this.
+
+ return OUString(sRet);
+}
+
+OUString firebird::StatusVectorToString(const ISC_STATUS_ARRAY& rStatusVector,
+ std::u16string_view rCause)
+{
+ OUStringBuffer buf;
+ const ISC_STATUS* pStatus = reinterpret_cast<const ISC_STATUS*>(&rStatusVector);
+
+ buf.append("firebird_sdbc error:");
+ try
+ {
+ char msg[512]; // Size is based on suggestion in docs.
+ while(fb_interpret(msg, sizeof(msg), &pStatus))
+ {
+ // TODO: verify encoding
+ buf.append("\n*"
+ + OUString(msg, strlen(msg), RTL_TEXTENCODING_UTF8));
+ }
+ }
+ catch (...)
+ {
+ SAL_WARN("connectivity.firebird", "ignore fb_interpret exception");
+ }
+ buf.append(OUString::Concat("\ncaused by\n'") + rCause + "'\n");
+
+ OUString error = buf.makeStringAndClear();
+ SAL_WARN("connectivity.firebird", error);
+ return error;
+}
+
+void firebird::evaluateStatusVector(const ISC_STATUS_ARRAY& rStatusVector,
+ std::u16string_view rCause,
+ const uno::Reference< XInterface >& _rxContext)
+{
+ if (IndicatesError(rStatusVector))
+ {
+ OUString error = StatusVectorToString(rStatusVector, rCause);
+ throw SQLException(error, _rxContext, OUString(), 1, Any());
+ }
+}
+
+static sal_Int32 lcl_getNumberType( short aType, NumberSubType aSubType )
+{
+ switch(aSubType)
+ {
+ case NumberSubType::Numeric:
+ return DataType::NUMERIC;
+ case NumberSubType::Decimal:
+ return DataType::DECIMAL;
+ default:
+ switch(aType)
+ {
+ case SQL_SHORT:
+ return DataType::SMALLINT;
+ case SQL_LONG:
+ return DataType::INTEGER;
+ case SQL_DOUBLE:
+ return DataType::DOUBLE;
+ case SQL_INT64:
+ return DataType::BIGINT;
+ default:
+ assert(false); // not a number
+ return 0;
+ }
+ }
+}
+static sal_Int32 lcl_getCharColumnType( short aType, std::u16string_view sCharset )
+{
+ switch(aType)
+ {
+ case SQL_TEXT:
+ if( sCharset == u"OCTETS")
+ return DataType::BINARY;
+ else
+ return DataType::CHAR;
+ case SQL_VARYING:
+ if( sCharset == u"OCTETS")
+ return DataType::VARBINARY;
+ else
+ return DataType::VARCHAR;
+ default:
+ assert(false);
+ return 0;
+ }
+}
+
+sal_Int32 firebird::ColumnTypeInfo::getSdbcType() const
+{
+ short aType = m_aType & ~1; // Remove last bit -- it is used to denote whether column
+ // can store Null, not needed for type determination
+ short aSubType = m_aSubType;
+ if( m_nScale > 0 )
+ {
+ // numeric / decimal
+ if(aType == SQL_SHORT || aType == SQL_LONG || aType == SQL_DOUBLE
+ || aType == SQL_INT64)
+ {
+ // if scale is set without subtype then imply numeric
+ if( static_cast<NumberSubType>(aSubType) == NumberSubType::Other )
+ aSubType = static_cast<short>(NumberSubType::Numeric);
+ }
+ }
+
+ switch (aType)
+ {
+ case SQL_TEXT:
+ case SQL_VARYING:
+ return lcl_getCharColumnType(aType, m_sCharsetName);
+ case SQL_SHORT:
+ case SQL_LONG:
+ case SQL_DOUBLE:
+ case SQL_INT64:
+ return lcl_getNumberType(aType, static_cast<NumberSubType>(aSubType) );
+ case SQL_FLOAT:
+ return DataType::FLOAT;
+ case SQL_D_FLOAT:
+ return DataType::DOUBLE;
+ case SQL_TIMESTAMP:
+ return DataType::TIMESTAMP;
+ case SQL_BLOB:
+ switch (static_cast<BlobSubtype>(aSubType))
+ {
+ case BlobSubtype::Blob:
+ return DataType::BLOB;
+ case BlobSubtype::Clob:
+ return DataType::CLOB;
+ case BlobSubtype::Image:
+ return DataType::LONGVARBINARY;
+ default:
+ SAL_WARN("connectivity.firebird", "Unknown subtype for Blob type: " << aSubType);
+ assert(!"Unknown subtype for Blob type"); // Should never happen
+ return 0;
+ }
+ case SQL_ARRAY:
+ return DataType::ARRAY;
+ case SQL_TYPE_TIME:
+ return DataType::TIME;
+ case SQL_TYPE_DATE:
+ return DataType::DATE;
+ case SQL_NULL:
+ return DataType::SQLNULL;
+ case SQL_QUAD: // Is a "Blob ID" according to the docs
+ return 0; // TODO: verify
+ case SQL_BOOLEAN:
+ return DataType::BOOLEAN;
+ default:
+ assert(false); // Should never happen
+ return 0;
+ }
+}
+
+OUString firebird::ColumnTypeInfo::getColumnTypeName() const
+{
+ sal_Int32 nDataType = this->getSdbcType();
+ switch (nDataType)
+ {
+ case DataType::BIT:
+ return "BIT";
+ case DataType::TINYINT:
+ return "TINYINT";
+ case DataType::SMALLINT:
+ return "SMALLINT";
+ case DataType::INTEGER:
+ return "INTEGER";
+ case DataType::BIGINT:
+ return "BIGINT";
+ case DataType::FLOAT:
+ return "FLOAT";
+ case DataType::REAL:
+ return "REAL";
+ case DataType::DOUBLE:
+ return "DOUBLE";
+ case DataType::NUMERIC:
+ return "NUMERIC";
+ case DataType::DECIMAL:
+ return "DECIMAL";
+ case DataType::CHAR:
+ return "CHAR";
+ case DataType::VARCHAR:
+ return "VARCHAR";
+ case DataType::LONGVARCHAR:
+ return "LONGVARCHAR";
+ case DataType::DATE:
+ return "DATE";
+ case DataType::TIME:
+ return "TIME";
+ case DataType::TIMESTAMP:
+ return "TIMESTAMP";
+ case DataType::BINARY:
+ // in Firebird, that is the same datatype "CHAR" as DataType::CHAR,
+ // only with CHARACTER SET OCTETS; we use the synonym CHARACTER
+ // to fool LO into seeing it as different types.
+ return "CHARACTER";
+ case DataType::VARBINARY:
+ // see above comment about DataType::BINARY.
+ return "CHARACTER VARYING";
+ case DataType::LONGVARBINARY:
+ return "BLOB SUB_TYPE " + OUString::number(static_cast<short>(BlobSubtype::Image));
+ case DataType::ARRAY:
+ return "ARRAY";
+ case DataType::BLOB:
+ return "BLOB SUB_TYPE BINARY";
+ case DataType::CLOB:
+ return "BLOB SUB_TYPE TEXT";
+ case DataType::BOOLEAN:
+ return "BOOLEAN";
+ case DataType::SQLNULL:
+ return "NULL";
+ default:
+ assert(false); // Should never happen
+ return OUString();
+ }
+}
+
+short firebird::getFBTypeFromBlrType(short blrType)
+{
+ switch (blrType)
+ {
+ case blr_text:
+ return SQL_TEXT;
+ case blr_text2:
+ assert(false);
+ return 0; // No idea if this should be supported
+ case blr_varying:
+ return SQL_VARYING;
+ case blr_varying2:
+ assert(false);
+ return 0; // No idea if this should be supported
+ case blr_short:
+ return SQL_SHORT;
+ case blr_long:
+ return SQL_LONG;
+ case blr_float:
+ return SQL_FLOAT;
+ case blr_double:
+ return SQL_DOUBLE;
+ case blr_d_float:
+ return SQL_D_FLOAT;
+ case blr_timestamp:
+ return SQL_TIMESTAMP;
+ case blr_blob:
+ return SQL_BLOB;
+// case blr_SQL_ARRAY:
+// return OUString("SQL_ARRAY");
+ case blr_sql_time:
+ return SQL_TYPE_TIME;
+ case blr_sql_date:
+ return SQL_TYPE_DATE;
+ case blr_int64:
+ return SQL_INT64;
+// case SQL_NULL:
+// return OUString("SQL_NULL");
+ case blr_quad:
+ return SQL_QUAD;
+ case blr_bool:
+ return SQL_BOOLEAN;
+ default:
+ // If this happens we have hit one of the extra types in ibase.h
+ // look up blr_* for a list, e.g. blr_domain_name, blr_not_nullable etc.
+ assert(false);
+ return 0;
+ }
+}
+
+void firebird::mallocSQLVAR(XSQLDA* pSqlda)
+{
+ // TODO: confirm the sizings below.
+ XSQLVAR* pVar = pSqlda->sqlvar;
+ for (int i=0; i < pSqlda->sqld; i++, pVar++)
+ {
+ int dtype = (pVar->sqltype & ~1); /* drop flag bit for now */
+ switch(dtype) {
+ case SQL_TEXT:
+ pVar->sqldata = static_cast<char *>(malloc(sizeof(char)*pVar->sqllen));
+ break;
+ case SQL_VARYING:
+ pVar->sqldata = static_cast<char *>(malloc(sizeof(char)*pVar->sqllen + 2));
+ break;
+ case SQL_SHORT:
+ pVar->sqldata = static_cast<char*>(malloc(sizeof(sal_Int16)));
+ break;
+ case SQL_LONG:
+ pVar->sqldata = static_cast<char*>(malloc(sizeof(sal_Int32)));
+ break;
+ case SQL_FLOAT:
+ pVar->sqldata = static_cast<char *>(malloc(sizeof(float)));
+ break;
+ case SQL_DOUBLE:
+ pVar->sqldata = static_cast<char *>(malloc(sizeof(double)));
+ break;
+ case SQL_D_FLOAT:
+ pVar->sqldata = static_cast<char *>(malloc(sizeof(double)));
+ break;
+ case SQL_TIMESTAMP:
+ pVar->sqldata = static_cast<char*>(malloc(sizeof(ISC_TIMESTAMP)));
+ break;
+ // an ARRAY is in fact a BLOB of a specialized type
+ // See https://firebirdsql.org/file/documentation/reference_manuals/fblangref25-en/html/fblangref25-datatypes-bnrytypes.html#fblangref25-datatypes-array
+ case SQL_ARRAY:
+ case SQL_BLOB:
+ pVar->sqldata = static_cast<char*>(malloc(sizeof(ISC_QUAD)));
+ break;
+ case SQL_TYPE_TIME:
+ pVar->sqldata = static_cast<char*>(malloc(sizeof(ISC_TIME)));
+ break;
+ case SQL_TYPE_DATE:
+ pVar->sqldata = static_cast<char*>(malloc(sizeof(ISC_DATE)));
+ break;
+ case SQL_INT64:
+ pVar->sqldata = static_cast<char *>(malloc(sizeof(sal_Int64)));
+ break;
+ case SQL_BOOLEAN:
+ pVar->sqldata = static_cast<char *>(malloc(sizeof(sal_Bool)));
+ break;
+ // See https://www.firebirdsql.org/file/documentation/html/en/refdocs/fblangref25/firebird-25-language-reference.html#fblangref25-datatypes-special-sqlnull
+ case SQL_NULL:
+ pVar->sqldata = nullptr;
+ break;
+ case SQL_QUAD:
+ assert(false); // TODO: implement
+ break;
+ default:
+ SAL_WARN("connectivity.firebird", "Unknown type: " << dtype);
+ assert(false);
+ break;
+ }
+ /* allocate variable to hold NULL status */
+ pVar->sqlind = static_cast<short *>(malloc(sizeof(short)));
+ }
+}
+
+void firebird::freeSQLVAR(XSQLDA* pSqlda)
+{
+ XSQLVAR* pVar = pSqlda->sqlvar;
+ for (int i=0; i < pSqlda->sqld; i++, pVar++)
+ {
+ int dtype = (pVar->sqltype & ~1); /* drop flag bit for now */
+ switch(dtype) {
+ case SQL_TEXT:
+ case SQL_VARYING:
+ case SQL_SHORT:
+ case SQL_LONG:
+ case SQL_FLOAT:
+ case SQL_DOUBLE:
+ case SQL_D_FLOAT:
+ case SQL_TIMESTAMP:
+ // an ARRAY is in fact a BLOB of a specialized type
+ // See https://firebirdsql.org/file/documentation/reference_manuals/fblangref25-en/html/fblangref25-datatypes-bnrytypes.html#fblangref25-datatypes-array
+ case SQL_ARRAY:
+ case SQL_BLOB:
+ case SQL_INT64:
+ case SQL_TYPE_TIME:
+ case SQL_TYPE_DATE:
+ case SQL_BOOLEAN:
+ if(pVar->sqldata)
+ {
+ free(pVar->sqldata);
+ pVar->sqldata = nullptr;
+ }
+ break;
+ case SQL_NULL:
+ // See SQL_NULL case in mallocSQLVAR
+ assert(pVar->sqldata == nullptr);
+ break;
+ case SQL_QUAD:
+ assert(false); // TODO: implement
+ break;
+ default:
+ SAL_WARN("connectivity.firebird", "Unknown type: " << dtype);
+// assert(false);
+ break;
+ }
+
+ if(pVar->sqlind)
+ {
+ free(pVar->sqlind);
+ pVar->sqlind = nullptr;
+ }
+ }
+}
+
+
+sal_Int64 firebird::pow10Integer(int nDecimalCount)
+{
+ sal_Int64 nRet = 1;
+ for(int i=0; i< nDecimalCount; i++)
+ {
+ nRet *= 10;
+ }
+ return nRet;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/connectivity/source/drivers/firebird/Util.hxx b/connectivity/source/drivers/firebird/Util.hxx
new file mode 100644
index 0000000000..db407ef98b
--- /dev/null
+++ b/connectivity/source/drivers/firebird/Util.hxx
@@ -0,0 +1,126 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include <ibase.h>
+
+#include <rtl/ustring.hxx>
+
+#include <com/sun/star/uno/XInterface.hpp>
+#include <utility>
+
+namespace connectivity::firebird
+ {
+ // Type Blob has 2 subtypes values
+ // 0 for BLOB, 1 for CLOB
+ // see http://www.firebirdfaq.org/faq48/
+ // User-defined subtypes are negative.
+ // Use a number for image which is very unlikely to be defined by a
+ // user.
+ enum class BlobSubtype {
+ Blob = 0,
+ Clob = 1,
+ Image = -9546
+ };
+
+ /**
+ * Numeric and decimal types can be identified by their subtype in
+ * Firebird API. 1 for NUMERIC, 2 for DECIMAL.
+ */
+ enum class NumberSubType {
+ Other = 0,
+ Numeric = 1,
+ Decimal = 2
+ };
+
+ class ColumnTypeInfo {
+private:
+ short m_aType;
+ short m_aSubType;
+ short m_nScale;
+ OUString m_sCharsetName;
+public:
+ /**
+ * @param tType SQL type of column defined by Firebird (e.g.
+ * SQL_DOUBLE)
+ * @param aSubType SQL sub type as in firebird API. See
+ * NumberSubType.
+ * @param scale: Scale of the number. It is ignored in case it's not
+ * a number. Scale obtained from the Firebird API is negative, so
+ * that should be negated before passing to this constructor.
+ *
+ */
+ explicit ColumnTypeInfo( short aType, short aSubType = 0,
+ short nScale = 0, OUString sCharset = OUString() )
+ : m_aType(aType)
+ , m_aSubType(aSubType)
+ , m_nScale(nScale)
+ , m_sCharsetName(std::move(sCharset)) {}
+ explicit ColumnTypeInfo( short aType, OUString sCharset )
+ : m_aType(aType)
+ , m_aSubType(0)
+ , m_nScale(0)
+ , m_sCharsetName(std::move(sCharset)) {}
+ short getType() const { return m_aType; }
+ short getSubType() const { return m_aSubType; }
+ short getScale() const { return m_nScale; }
+ OUString const & getCharacterSet() const { return m_sCharsetName; }
+
+ sal_Int32 getSdbcType() const;
+ OUString getColumnTypeName() const;
+
+ };
+
+ /**
+ * Make sure an identifier is safe to use within the database. Currently
+ * firebird seems to return identifiers with 93 character (instead of
+ * 31), whereby the name is simply padded with trailing whitespace.
+ * This removes all trailing whitespace (i.e. if necessary so that
+ * the length is below 31 characters). Firebird automatically compensates
+ * for such shorter strings, however any trailing padding makes the gui
+ * editing of such names harder, hence we remove all trailing whitespace.
+ */
+ OUString sanitizeIdentifier(std::u16string_view rIdentifier);
+
+ inline bool IndicatesError(const ISC_STATUS_ARRAY& rStatusVector)
+ {
+ return rStatusVector[0]==1 && rStatusVector[1]; // indicates error;
+ }
+
+ OUString StatusVectorToString(const ISC_STATUS_ARRAY& rStatusVector,
+ std::u16string_view rCause);
+
+ /**
+ * Evaluate a firebird status vector and throw exceptions as necessary.
+ * The content of the status vector is included in the thrown exception.
+ *
+ * @throws css::sdbc::SQLException
+ */
+ void evaluateStatusVector(const ISC_STATUS_ARRAY& rStatusVector,
+ std::u16string_view aCause,
+ const css::uno::Reference< css::uno::XInterface >& _rxContext);
+
+ /**
+ * Internally (i.e. in RDB$FIELD_TYPE) firebird stores the data type
+ * for a column as defined in blr_*, however in the firebird
+ * api the SQL_* types are used, hence we need to be able to convert
+ * between the two when retrieving column metadata.
+ */
+ short getFBTypeFromBlrType(short blrType);
+
+ void mallocSQLVAR(XSQLDA* pSqlda);
+
+ void freeSQLVAR(XSQLDA* pSqlda);
+
+ sal_Int64 pow10Integer( int nDecimalCount );
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/connectivity/source/drivers/firebird/View.cxx b/connectivity/source/drivers/firebird/View.cxx
new file mode 100644
index 0000000000..6dcbf6bce2
--- /dev/null
+++ b/connectivity/source/drivers/firebird/View.cxx
@@ -0,0 +1,85 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+#include "View.hxx"
+
+#include <propertyids.hxx>
+
+#include <com/sun/star/sdbc/XRow.hpp>
+
+namespace connectivity::firebird
+{
+View::View(const css::uno::Reference<css::sdbc::XConnection>& _rxConnection, bool _bCaseSensitive,
+ const OUString& _rSchemaName, const OUString& _rName)
+ : View_Base(_bCaseSensitive, _rName, _rxConnection->getMetaData(), OUString(), _rSchemaName,
+ OUString())
+ , m_xConnection(_rxConnection)
+{
+}
+
+View::~View() {}
+
+void SAL_CALL View::acquire() noexcept { View_Base::acquire(); };
+void SAL_CALL View::release() noexcept { View_Base::release(); };
+css::uno::Any SAL_CALL View::queryInterface(const css::uno::Type& _rType)
+{
+ css::uno::Any aReturn = View_Base::queryInterface(_rType);
+ if (!aReturn.hasValue())
+ aReturn = View_IBASE::queryInterface(_rType);
+ return aReturn;
+}
+
+css::uno::Sequence<css::uno::Type> SAL_CALL View::getTypes()
+{
+ return ::comphelper::concatSequences(View_Base::getTypes(), View_IBASE::getTypes());
+}
+
+css::uno::Sequence<sal_Int8> SAL_CALL View::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+void SAL_CALL View::alterCommand(const OUString& _rNewCommand)
+{
+ OUString aCommand = "ALTER VIEW \"" + m_Name + "\" AS " + _rNewCommand;
+ m_xMetaData->getConnection()->createStatement()->execute(aCommand);
+}
+
+void SAL_CALL View::getFastPropertyValue(css::uno::Any& _rValue, sal_Int32 _nHandle) const
+{
+ if (_nHandle == PROPERTY_ID_COMMAND)
+ {
+ // retrieve the very current command, don't rely on the base classes cached value
+ // (which we initialized empty, anyway)
+ _rValue <<= impl_getCommand();
+ return;
+ }
+
+ View_Base::getFastPropertyValue(_rValue, _nHandle);
+}
+
+OUString View::impl_getCommand() const
+{
+ OUString aCommand("SELECT RDB$VIEW_SOURCE FROM RDB$RELATIONS WHERE RDB$RELATION_NAME = '"
+ + m_Name + "'");
+ css::uno::Reference<css::sdbc::XStatement> statement = m_xConnection->createStatement();
+ css::uno::Reference<css::sdbc::XResultSet> xResult = statement->executeQuery(aCommand);
+
+ css::uno::Reference<css::sdbc::XRow> xRow(xResult, css::uno::UNO_QUERY_THROW);
+ if (!xResult->next())
+ {
+ // hmm. There is no view the name as we know it. Can only mean some other instance
+ // dropped this view meanwhile...
+ std::abort();
+ }
+
+ return xRow->getString(1);
+}
+
+} // namespace connectivity::firebird
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/connectivity/source/drivers/firebird/View.hxx b/connectivity/source/drivers/firebird/View.hxx
new file mode 100644
index 0000000000..2b300a8d06
--- /dev/null
+++ b/connectivity/source/drivers/firebird/View.hxx
@@ -0,0 +1,60 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+#pragma once
+
+#include <connectivity/sdbcx/VView.hxx>
+
+#include <com/sun/star/sdbcx/XAlterView.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+
+#include <comphelper/sequence.hxx>
+#include <cppuhelper/implbase1.hxx>
+
+namespace connectivity::firebird
+{
+typedef ::connectivity::sdbcx::OView View_Base;
+typedef ::cppu::ImplHelper1<css::sdbcx::XAlterView> View_IBASE;
+
+class View : public View_Base, public View_IBASE
+{
+public:
+ View(const css::uno::Reference<css::sdbc::XConnection>& _rxConnection, bool _bCaseSensitive,
+ const OUString& _rSchemaName, const OUString& _rName);
+
+ // UNO
+ virtual css::uno::Any SAL_CALL queryInterface(const css::uno::Type& aType) override;
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+
+ virtual css::uno::Sequence<css::uno::Type> SAL_CALL getTypes() override;
+ virtual css::uno::Sequence<sal_Int8> SAL_CALL getImplementationId() override;
+
+ // XAlterView
+ virtual void SAL_CALL alterCommand(const OUString& NewCommand) override;
+
+protected:
+ virtual ~View() override;
+
+protected:
+ // OPropertyContainer
+ virtual void SAL_CALL getFastPropertyValue(css::uno::Any& _rValue,
+ sal_Int32 _nHandle) const override;
+
+private:
+ /** retrieves the current command of the View */
+ OUString impl_getCommand() const;
+
+private:
+ css::uno::Reference<css::sdbc::XConnection> m_xConnection;
+
+ using View_Base::getFastPropertyValue;
+};
+
+} // namespace connectivity::firebird
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/connectivity/source/drivers/firebird/Views.cxx b/connectivity/source/drivers/firebird/Views.cxx
new file mode 100644
index 0000000000..2e5bec42ad
--- /dev/null
+++ b/connectivity/source/drivers/firebird/Views.cxx
@@ -0,0 +1,112 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+#include "Tables.hxx"
+#include "Views.hxx"
+#include "View.hxx"
+#include "Catalog.hxx"
+#include <connectivity/dbtools.hxx>
+#include <comphelper/types.hxx>
+#include <TConnection.hxx>
+
+connectivity::firebird::Views::Views(
+ const css::uno::Reference<css::sdbc::XConnection>& _rxConnection, ::cppu::OWeakObject& _rParent,
+ ::osl::Mutex& _rMutex, const ::std::vector<OUString>& _rVector)
+ : sdbcx::OCollection(_rParent, true, _rMutex, _rVector)
+ , m_xConnection(_rxConnection)
+ , m_xMetaData(_rxConnection->getMetaData())
+ , m_bInDrop(false)
+{
+}
+
+connectivity::sdbcx::ObjectType connectivity::firebird::Views::createObject(const OUString& _rName)
+{
+ OUString sCatalog, sSchema, sTable;
+ ::dbtools::qualifiedNameComponents(m_xMetaData, _rName, sCatalog, sSchema, sTable,
+ ::dbtools::EComposeRule::InDataManipulation);
+ return new View(m_xConnection, isCaseSensitive(), sSchema, sTable);
+}
+
+void connectivity::firebird::Views::impl_refresh()
+{
+ static_cast<Catalog&>(m_rParent).refreshViews();
+}
+
+css::uno::Reference<css::beans::XPropertySet> connectivity::firebird::Views::createDescriptor()
+{
+ return new connectivity::sdbcx::OView(true, m_xMetaData);
+}
+
+// XAppend
+connectivity::sdbcx::ObjectType connectivity::firebird::Views::appendObject(
+ const OUString& _rForName, const css::uno::Reference<css::beans::XPropertySet>& descriptor)
+{
+ createView(descriptor);
+ return createObject(_rForName);
+}
+
+// XDrop
+void connectivity::firebird::Views::dropObject(sal_Int32 _nPos, const OUString& /*_sElementName*/)
+{
+ if (m_bInDrop)
+ return;
+
+ css::uno::Reference<XInterface> xObject(getObject(_nPos));
+ bool bIsNew = connectivity::sdbcx::ODescriptor::isNew(xObject);
+ if (!bIsNew)
+ {
+ OUString aSql("DROP VIEW");
+
+ css::uno::Reference<css::beans::XPropertySet> xProp(xObject, css::uno::UNO_QUERY);
+ aSql += ::dbtools::composeTableName(m_xMetaData, xProp,
+ ::dbtools::EComposeRule::InTableDefinitions, true);
+
+ css::uno::Reference<css::sdbc::XConnection> xConnection = m_xMetaData->getConnection();
+ css::uno::Reference<css::sdbc::XStatement> xStmt = xConnection->createStatement();
+ xStmt->execute(aSql);
+ ::comphelper::disposeComponent(xStmt);
+ }
+}
+
+void connectivity::firebird::Views::dropByNameImpl(const OUString& elementName)
+{
+ m_bInDrop = true;
+ connectivity::sdbcx::OCollection::dropByName(elementName);
+ m_bInDrop = false;
+}
+
+void connectivity::firebird::Views::createView(
+ const css::uno::Reference<css::beans::XPropertySet>& descriptor)
+{
+ css::uno::Reference<css::sdbc::XConnection> xConnection = m_xMetaData->getConnection();
+
+ OUString sCommand;
+ descriptor->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_COMMAND))
+ >>= sCommand;
+
+ OUString aSql = "CREATE VIEW "
+ + ::dbtools::composeTableName(m_xMetaData, descriptor,
+ ::dbtools::EComposeRule::InTableDefinitions, true)
+ + " AS " + sCommand;
+
+ css::uno::Reference<css::sdbc::XStatement> xStmt = xConnection->createStatement();
+ if (xStmt.is())
+ {
+ xStmt->execute(aSql);
+ ::comphelper::disposeComponent(xStmt);
+ }
+ connectivity::firebird::Tables* pTables = static_cast<connectivity::firebird::Tables*>(
+ static_cast<connectivity::firebird::Catalog&>(m_rParent).getPrivateTables());
+ if (pTables)
+ {
+ OUString sName = ::dbtools::composeTableName(
+ m_xMetaData, descriptor, ::dbtools::EComposeRule::InDataManipulation, false);
+ pTables->appendNew(sName);
+ }
+}
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/connectivity/source/drivers/firebird/Views.hxx b/connectivity/source/drivers/firebird/Views.hxx
new file mode 100644
index 0000000000..6887bdc66e
--- /dev/null
+++ b/connectivity/source/drivers/firebird/Views.hxx
@@ -0,0 +1,42 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+#pragma once
+
+#include <connectivity/sdbcx/VCollection.hxx>
+#include <com/sun/star/sdbc/XDatabaseMetaData.hpp>
+namespace connectivity::firebird
+{
+class Views final : public connectivity::sdbcx::OCollection
+{
+ css::uno::Reference<css::sdbc::XConnection> m_xConnection;
+ css::uno::Reference<css::sdbc::XDatabaseMetaData> m_xMetaData;
+ bool m_bInDrop;
+
+ // OCollection
+ virtual connectivity::sdbcx::ObjectType createObject(const OUString& _rName) override;
+ virtual void impl_refresh() override;
+ virtual css::uno::Reference<css::beans::XPropertySet> createDescriptor() override;
+ virtual sdbcx::ObjectType
+ appendObject(const OUString& _rForName,
+ const css::uno::Reference<css::beans::XPropertySet>& descriptor) override;
+
+ void createView(const css::uno::Reference<css::beans::XPropertySet>& descriptor);
+
+public:
+ Views(const css::uno::Reference<css::sdbc::XConnection>& _rxConnection,
+ ::cppu::OWeakObject& _rParent, ::osl::Mutex& _rMutex,
+ const ::std::vector<OUString>& _rVector);
+
+ // XDrop
+ virtual void dropObject(sal_Int32 _nPos, const OUString& _sElementName) override;
+
+ void dropByNameImpl(const OUString& elementName);
+};
+}
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/connectivity/source/drivers/firebird/firebird_sdbc.component b/connectivity/source/drivers/firebird/firebird_sdbc.component
new file mode 100644
index 0000000000..d80755a24d
--- /dev/null
+++ b/connectivity/source/drivers/firebird/firebird_sdbc.component
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+-->
+
+<component loader="com.sun.star.loader.SharedLibrary" environment="@CPPU_ENV@"
+ xmlns="http://openoffice.org/2010/uno-components">
+ <implementation name="com.sun.star.comp.sdbc.firebird.Driver"
+ constructor="connectivity_FirebirdDriver_get_implementation">
+ <service name="com.sun.star.sdbc.Driver"/>
+ <service name="com.sun.star.sdbcx.Driver"/>
+ </implementation>
+</component>
+
diff --git a/connectivity/source/drivers/flat/ECatalog.cxx b/connectivity/source/drivers/flat/ECatalog.cxx
new file mode 100644
index 0000000000..aed042fdd5
--- /dev/null
+++ b/connectivity/source/drivers/flat/ECatalog.cxx
@@ -0,0 +1,58 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <flat/ECatalog.hxx>
+
+#include <flat/EConnection.hxx>
+#include <flat/ETables.hxx>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XResultSet.hpp>
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::container;
+
+using namespace connectivity::flat;
+
+OFlatCatalog::OFlatCatalog(OFlatConnection* _pCon)
+ : file::OFileCatalog(_pCon)
+{
+}
+
+void OFlatCatalog::refreshTables()
+{
+ ::std::vector<OUString> aVector;
+ Sequence<OUString> aTypes;
+ Reference<XResultSet> xResult = m_xMetaData->getTables(Any(), "%", "%", aTypes);
+
+ if (xResult.is())
+ {
+ Reference<XRow> xRow(xResult, UNO_QUERY);
+ while (xResult->next())
+ aVector.push_back(xRow->getString(3));
+ }
+ if (m_pTables)
+ m_pTables->reFill(aVector);
+ else
+ m_pTables.reset(new OFlatTables(m_xMetaData, *this, m_aMutex, aVector));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/flat/EColumns.cxx b/connectivity/source/drivers/flat/EColumns.cxx
new file mode 100644
index 0000000000..a9e210321b
--- /dev/null
+++ b/connectivity/source/drivers/flat/EColumns.cxx
@@ -0,0 +1,44 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <flat/EColumns.hxx>
+#include <flat/ETable.hxx>
+
+using namespace connectivity::flat;
+using namespace connectivity;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::container;
+
+
+sdbcx::ObjectType OFlatColumns::createObject(const OUString& _rName)
+{
+ OFlatTable* pTable = static_cast<OFlatTable*>(m_pTable);
+ const ::rtl::Reference<OSQLColumns>& aCols = pTable->getTableColumns();
+ OSQLColumns::const_iterator aIter = find(aCols->begin(),aCols->end(),_rName,::comphelper::UStringMixEqual(isCaseSensitive()));
+ sdbcx::ObjectType xRet;
+ if(aIter != aCols->end())
+ xRet = sdbcx::ObjectType(*aIter,UNO_QUERY);
+ return xRet;
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/flat/EConnection.cxx b/connectivity/source/drivers/flat/EConnection.cxx
new file mode 100644
index 0000000000..288a53fa64
--- /dev/null
+++ b/connectivity/source/drivers/flat/EConnection.cxx
@@ -0,0 +1,176 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <flat/EConnection.hxx>
+#include <flat/EDatabaseMetaData.hxx>
+#include <flat/ECatalog.hxx>
+#include <flat/EDriver.hxx>
+#include <flat/EPreparedStatement.hxx>
+#include <flat/EStatement.hxx>
+#include <connectivity/dbexception.hxx>
+#include <sal/log.hxx>
+
+using namespace connectivity::flat;
+using namespace connectivity::file;
+
+typedef connectivity::file::OConnection OConnection_B;
+
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::lang;
+
+
+OFlatConnection::OFlatConnection(ODriver* _pDriver) : OConnection(_pDriver)
+ ,m_nMaxRowsToScan(50)
+ ,m_bHeaderLine(true)
+ ,m_cFieldDelimiter(';')
+ ,m_cStringDelimiter('"')
+ ,m_cDecimalDelimiter(',')
+ ,m_cThousandDelimiter('.')
+{
+}
+
+OFlatConnection::~OFlatConnection()
+{
+}
+
+// XServiceInfo
+
+IMPLEMENT_SERVICE_INFO(OFlatConnection, "com.sun.star.sdbc.drivers.flat.Connection", "com.sun.star.sdbc.Connection")
+
+
+void OFlatConnection::construct(const OUString& url,const Sequence< PropertyValue >& info)
+{
+ osl_atomic_increment( &m_refCount );
+
+ const PropertyValue *pBegin = info.getConstArray();
+ const PropertyValue *pEnd = pBegin + info.getLength();
+ for(;pBegin != pEnd;++pBegin)
+ {
+ if(pBegin->Name == "HeaderLine")
+ {
+ if( ! (pBegin->Value >>= m_bHeaderLine) )
+ SAL_WARN("connectivity.flat", "construct: unable to get property HeaderLine");
+ }
+ else if(pBegin->Name == "FieldDelimiter")
+ {
+ OUString aVal;
+ if( ! (pBegin->Value >>= aVal) )
+ SAL_WARN("connectivity.flat", "construct: unable to get property FieldDelimiter");
+
+ m_cFieldDelimiter = aVal.toChar();
+ }
+ else if(pBegin->Name == "StringDelimiter")
+ {
+ OUString aVal;
+ if( ! (pBegin->Value >>= aVal) )
+ SAL_WARN("connectivity.flat", "construct: unable to get property StringDelimiter");
+
+ m_cStringDelimiter = aVal.toChar();
+ }
+ else if(pBegin->Name == "DecimalDelimiter")
+ {
+ OUString aVal;
+ if( ! (pBegin->Value >>= aVal) )
+ SAL_WARN("connectivity.flat", "construct: unable to get property DecimalDelimiter");
+
+ m_cDecimalDelimiter = aVal.toChar();
+ }
+ else if(pBegin->Name == "ThousandDelimiter")
+ {
+ OUString aVal;
+ if( ! (pBegin->Value >>= aVal) )
+ SAL_WARN("connectivity.flat", "construct: unable to get property ThousandDelimiter");
+
+ m_cThousandDelimiter = aVal.toChar();
+ }
+ else if ( pBegin->Name == "MaxRowScan" )
+ {
+ pBegin->Value >>= m_nMaxRowsToScan;
+ }
+ }
+
+ osl_atomic_decrement( &m_refCount );
+ OConnection::construct(url,info);
+ m_bShowDeleted = true; // we do not supported rows for this type
+}
+
+Reference< XDatabaseMetaData > SAL_CALL OFlatConnection::getMetaData( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OConnection_B::rBHelper.bDisposed);
+
+
+ Reference< XDatabaseMetaData > xMetaData = m_xMetaData;
+ if(!xMetaData.is())
+ {
+ xMetaData = new OFlatDatabaseMetaData(this);
+ m_xMetaData = xMetaData;
+ }
+
+ return xMetaData;
+}
+
+css::uno::Reference< XTablesSupplier > OFlatConnection::createCatalog()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ Reference< XTablesSupplier > xTab = m_xCatalog;
+ if(!xTab.is())
+ {
+ xTab = new OFlatCatalog(this);
+ m_xCatalog = xTab;
+ }
+ return xTab;
+}
+
+Reference< XStatement > SAL_CALL OFlatConnection::createStatement( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OConnection_B::rBHelper.bDisposed);
+
+ rtl::Reference<OFlatStatement> pStmt = new OFlatStatement(this);
+ m_aStatements.push_back(WeakReferenceHelper(*pStmt));
+ return pStmt;
+}
+
+Reference< XPreparedStatement > SAL_CALL OFlatConnection::prepareStatement( const OUString& sql )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OConnection_B::rBHelper.bDisposed);
+
+ rtl::Reference<OFlatPreparedStatement> pStmt = new OFlatPreparedStatement(this);
+ pStmt->construct(sql);
+ m_aStatements.push_back(WeakReferenceHelper(*pStmt));
+ return pStmt;
+}
+
+Reference< XPreparedStatement > SAL_CALL OFlatConnection::prepareCall( const OUString& /*sql*/ )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OConnection_B::rBHelper.bDisposed);
+
+ ::dbtools::throwFeatureNotImplementedSQLException( "XConnection::prepareCall", *this );
+ return nullptr;
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/flat/EDatabaseMetaData.cxx b/connectivity/source/drivers/flat/EDatabaseMetaData.cxx
new file mode 100644
index 0000000000..729b55ef9e
--- /dev/null
+++ b/connectivity/source/drivers/flat/EDatabaseMetaData.cxx
@@ -0,0 +1,242 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <flat/EDatabaseMetaData.hxx>
+#include <com/sun/star/sdbc/ColumnSearch.hpp>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <com/sun/star/sdbc/ColumnValue.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
+#include <FDatabaseMetaDataResultSet.hxx>
+#include <comphelper/types.hxx>
+
+using namespace ::comphelper;
+
+using namespace connectivity;
+using namespace connectivity::flat;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::container;
+
+
+OFlatDatabaseMetaData::OFlatDatabaseMetaData(::connectivity::file::OConnection* _pCon) :ODatabaseMetaData(_pCon)
+{
+}
+
+OFlatDatabaseMetaData::~OFlatDatabaseMetaData()
+{
+}
+
+Reference< XResultSet > OFlatDatabaseMetaData::impl_getTypeInfo_throw( )
+{
+ rtl::Reference<::connectivity::ODatabaseMetaDataResultSet> pResult = new ::connectivity::ODatabaseMetaDataResultSet(::connectivity::ODatabaseMetaDataResultSet::eTypeInfo);
+
+ static ODatabaseMetaDataResultSet::ORows aRows = []()
+ {
+ ODatabaseMetaDataResultSet::ORows tmp;
+ ODatabaseMetaDataResultSet::ORow aRow
+ {
+ ODatabaseMetaDataResultSet::getEmptyValue() ,
+ new ORowSetValueDecorator(OUString("CHAR")) ,
+ new ORowSetValueDecorator(DataType::CHAR) ,
+ new ORowSetValueDecorator(sal_Int32(254)) ,
+ ODatabaseMetaDataResultSet::getQuoteValue() ,
+ ODatabaseMetaDataResultSet::getQuoteValue() ,
+ ODatabaseMetaDataResultSet::getEmptyValue() ,
+ new ORowSetValueDecorator(sal_Int32(ColumnValue::NULLABLE)) ,
+ ODatabaseMetaDataResultSet::get1Value() ,
+ new ORowSetValueDecorator(sal_Int32(ColumnSearch::CHAR)) ,
+ ODatabaseMetaDataResultSet::get1Value() ,
+ ODatabaseMetaDataResultSet::get0Value() ,
+ ODatabaseMetaDataResultSet::get0Value() ,
+ ODatabaseMetaDataResultSet::getEmptyValue() ,
+ ODatabaseMetaDataResultSet::get0Value() ,
+ ODatabaseMetaDataResultSet::get0Value() ,
+ ODatabaseMetaDataResultSet::getEmptyValue() ,
+ ODatabaseMetaDataResultSet::getEmptyValue() ,
+ new ORowSetValueDecorator(sal_Int32(10))
+ };
+
+ tmp.push_back(aRow);
+
+ aRow[1] = new ORowSetValueDecorator(OUString("VARCHAR"));
+ aRow[2] = new ORowSetValueDecorator(DataType::VARCHAR);
+ aRow[4] = ODatabaseMetaDataResultSet::getQuoteValue();
+ aRow[5] = ODatabaseMetaDataResultSet::getQuoteValue();
+ tmp.push_back(aRow);
+
+
+ aRow[1] = new ORowSetValueDecorator(OUString("LONGVARCHAR"));
+ aRow[2] = new ORowSetValueDecorator(DataType::LONGVARCHAR);
+ aRow[3] = new ORowSetValueDecorator(sal_Int32(65535));
+ aRow[4] = ODatabaseMetaDataResultSet::getQuoteValue();
+ aRow[5] = ODatabaseMetaDataResultSet::getQuoteValue();
+ tmp.push_back(aRow);
+
+ aRow[1] = new ORowSetValueDecorator(OUString("DATE"));
+ aRow[2] = new ORowSetValueDecorator(DataType::DATE);
+ aRow[3] = new ORowSetValueDecorator(sal_Int32(10));
+ aRow[4] = ODatabaseMetaDataResultSet::getQuoteValue();
+ aRow[5] = ODatabaseMetaDataResultSet::getQuoteValue();
+ tmp.push_back(aRow);
+
+ aRow[1] = new ORowSetValueDecorator(OUString("TIME"));
+ aRow[2] = new ORowSetValueDecorator(DataType::TIME);
+ aRow[3] = new ORowSetValueDecorator(sal_Int32(8));
+ aRow[4] = ODatabaseMetaDataResultSet::getQuoteValue();
+ aRow[5] = ODatabaseMetaDataResultSet::getQuoteValue();
+ tmp.push_back(aRow);
+
+ aRow[1] = new ORowSetValueDecorator(OUString("TIMESTAMP"));
+ aRow[2] = new ORowSetValueDecorator(DataType::TIMESTAMP);
+ aRow[3] = new ORowSetValueDecorator(sal_Int32(19));
+ aRow[4] = ODatabaseMetaDataResultSet::getQuoteValue();
+ aRow[5] = ODatabaseMetaDataResultSet::getQuoteValue();
+ tmp.push_back(aRow);
+
+ aRow[1] = new ORowSetValueDecorator(OUString("BOOL"));
+ aRow[2] = new ORowSetValueDecorator(DataType::BIT);
+ aRow[3] = ODatabaseMetaDataResultSet::get1Value();
+ aRow[9] = ODatabaseMetaDataResultSet::getBasicValue();
+ tmp.push_back(aRow);
+
+ aRow[1] = new ORowSetValueDecorator(OUString("DECIMAL"));
+ aRow[2] = new ORowSetValueDecorator(DataType::DECIMAL);
+ aRow[3] = new ORowSetValueDecorator(sal_Int32(20));
+ aRow[15] = new ORowSetValueDecorator(sal_Int32(15));
+ tmp.push_back(aRow);
+
+ aRow[1] = new ORowSetValueDecorator(OUString("DOUBLE"));
+ aRow[2] = new ORowSetValueDecorator(DataType::DOUBLE);
+ aRow[3] = new ORowSetValueDecorator(sal_Int32(20));
+ aRow[15] = ODatabaseMetaDataResultSet::get0Value();
+ tmp.push_back(aRow);
+
+ aRow[1] = new ORowSetValueDecorator(OUString("NUMERIC"));
+ aRow[2] = new ORowSetValueDecorator(DataType::NUMERIC);
+ aRow[3] = new ORowSetValueDecorator(sal_Int32(20));
+ aRow[15] = new ORowSetValueDecorator(sal_Int32(20));
+ tmp.push_back(aRow);
+
+ return tmp;
+ }();
+
+ pResult->setRows(std::move(aRows));
+ return pResult;
+}
+
+Reference< XResultSet > SAL_CALL OFlatDatabaseMetaData::getColumns(
+ const Any& /*catalog*/, const OUString& /*schemaPattern*/, const OUString& tableNamePattern,
+ const OUString& columnNamePattern )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ Reference< XTablesSupplier > xTables = m_pConnection->createCatalog();
+ if(!xTables.is())
+ throw SQLException();
+
+ Reference< XNameAccess> xNames = xTables->getTables();
+ if(!xNames.is())
+ throw SQLException();
+
+ ODatabaseMetaDataResultSet::ORows aRows;
+ ODatabaseMetaDataResultSet::ORow aRow(19);
+ aRow[10] = new ORowSetValueDecorator(sal_Int32(10));
+ Sequence< OUString> aTabNames(xNames->getElementNames());
+ const OUString* pTabBegin = aTabNames.getConstArray();
+ const OUString* pTabEnd = pTabBegin + aTabNames.getLength();
+ for(;pTabBegin != pTabEnd;++pTabBegin)
+ {
+ if(match(tableNamePattern,*pTabBegin,'\0'))
+ {
+ Reference< XColumnsSupplier> xTable(
+ xNames->getByName(*pTabBegin), css::uno::UNO_QUERY);
+ aRow[3] = new ORowSetValueDecorator(*pTabBegin);
+
+ Reference< XNameAccess> xColumns = xTable->getColumns();
+ if(!xColumns.is())
+ throw SQLException();
+
+ Sequence< OUString> aColNames(xColumns->getElementNames());
+
+ const OUString* pBegin = aColNames.getConstArray();
+ const OUString* pEnd = pBegin + aColNames.getLength();
+ Reference< XPropertySet> xColumn;
+ for(sal_Int32 i=1;pBegin != pEnd;++pBegin,++i)
+ {
+ if(match(columnNamePattern,*pBegin,'\0'))
+ {
+ aRow[4] = new ORowSetValueDecorator(*pBegin);
+
+ xColumn.set(
+ xColumns->getByName(*pBegin), css::uno::UNO_QUERY);
+ OSL_ENSURE(xColumn.is(),"Columns contains a column who isn't a fastpropertyset!");
+ aRow[5] = new ORowSetValueDecorator(getINT32(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE))));
+ aRow[6] = new ORowSetValueDecorator(getString(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPENAME))));
+ aRow[7] = new ORowSetValueDecorator(getINT32(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PRECISION))));
+ aRow[9] = new ORowSetValueDecorator(getINT32(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCALE))));
+ aRow[11] = new ORowSetValueDecorator(getINT32(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISNULLABLE))));
+ aRow[13] = new ORowSetValueDecorator(getString(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DEFAULTVALUE))));
+
+ switch(aRow[5]->getValue().getInt32())
+ {
+ case DataType::CHAR:
+ case DataType::VARCHAR:
+ aRow[16] = new ORowSetValueDecorator(sal_Int32(254));
+ break;
+ case DataType::LONGVARCHAR:
+ aRow[16] = new ORowSetValueDecorator(sal_Int32(65535));
+ break;
+ default:
+ aRow[16] = new ORowSetValueDecorator(sal_Int32(0));
+ }
+ aRow[17] = new ORowSetValueDecorator(i);
+ switch(aRow[11]->getValue().getInt32())
+ {
+ case ColumnValue::NO_NULLS:
+ aRow[18] = new ORowSetValueDecorator(OUString("NO"));
+ break;
+ case ColumnValue::NULLABLE:
+ aRow[18] = new ORowSetValueDecorator(OUString("YES"));
+ break;
+ default:
+ aRow[18] = new ORowSetValueDecorator(OUString());
+ }
+ aRows.push_back(aRow);
+ }
+ }
+ }
+ }
+
+ rtl::Reference<::connectivity::ODatabaseMetaDataResultSet> pResult = new ::connectivity::ODatabaseMetaDataResultSet(::connectivity::ODatabaseMetaDataResultSet::eColumns);
+ pResult->setRows(std::move(aRows));
+
+ return pResult;
+}
+
+OUString SAL_CALL OFlatDatabaseMetaData::getURL( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ return "sdbc:flat:" + m_pConnection->getURL();
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/flat/EDriver.cxx b/connectivity/source/drivers/flat/EDriver.cxx
new file mode 100644
index 0000000000..51e3576115
--- /dev/null
+++ b/connectivity/source/drivers/flat/EDriver.cxx
@@ -0,0 +1,135 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <flat/EDriver.hxx>
+#include <flat/EConnection.hxx>
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <connectivity/dbexception.hxx>
+#include <comphelper/sequence.hxx>
+#include <strings.hrc>
+#include <resource/sharedresources.hxx>
+
+
+using namespace connectivity::flat;
+using namespace connectivity::file;
+using namespace css::uno;
+using namespace css::beans;
+using namespace css::sdbcx;
+using namespace css::sdbc;
+using namespace css::lang;
+
+
+// XServiceInfo
+
+OUString SAL_CALL ODriver::getImplementationName( )
+{
+ return "com.sun.star.comp.sdbc.flat.ODriver";
+}
+
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+connectivity_flat_ODriver(
+ css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const&)
+{
+ rtl::Reference<ODriver> ret;
+ try {
+ ret = new ODriver(context);
+ } catch (...) {
+ }
+ if (ret)
+ ret->acquire();
+ return getXWeak(ret.get());
+}
+
+Reference< XConnection > SAL_CALL ODriver::connect( const OUString& url, const Sequence< PropertyValue >& info )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if (ODriver_BASE::rBHelper.bDisposed)
+ throw DisposedException();
+
+ if ( ! acceptsURL(url) )
+ return nullptr;
+
+ rtl::Reference<OFlatConnection> pCon = new OFlatConnection(this);
+ pCon->construct(url,info);
+ m_xConnections.push_back(WeakReferenceHelper(*pCon));
+
+ return pCon;
+}
+
+sal_Bool SAL_CALL ODriver::acceptsURL( const OUString& url )
+{
+ return url.startsWith("sdbc:flat:");
+}
+
+Sequence< DriverPropertyInfo > SAL_CALL ODriver::getPropertyInfo( const OUString& url, const Sequence< PropertyValue >& info )
+{
+ if ( acceptsURL(url) )
+ {
+ Sequence< OUString > aBoolean { "0", "1" };
+
+ std::vector< DriverPropertyInfo > aDriverInfo
+ {
+ {
+ "FieldDelimiter"
+ ,"Field separator."
+ ,false
+ ,{}
+ ,{}
+ },
+ {
+ "HeaderLine"
+ ,"Text contains headers."
+ ,false
+ ,"0"
+ ,aBoolean
+ },
+ {
+ "StringDelimiter"
+ ,"Text separator."
+ ,false
+ ,"0"
+ ,aBoolean
+ },
+ {
+ "DecimalDelimiter"
+ ,"Decimal separator."
+ ,false
+ ,"0"
+ ,aBoolean
+ },
+ {
+ "ThousandDelimiter"
+ ,"Thousands separator."
+ ,false
+ ,"0"
+ ,aBoolean
+ }
+ };
+ return ::comphelper::concatSequences(OFileDriver::getPropertyInfo(url,info ),
+ Sequence< DriverPropertyInfo >(aDriverInfo.data(),aDriverInfo.size()));
+ }
+ ::connectivity::SharedResources aResources;
+ const OUString sMessage = aResources.getResourceString(STR_URI_SYNTAX_ERROR);
+ ::dbtools::throwGenericSQLException(sMessage ,*this);
+ return Sequence< DriverPropertyInfo >();
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/flat/EPreparedStatement.cxx b/connectivity/source/drivers/flat/EPreparedStatement.cxx
new file mode 100644
index 0000000000..f4095ac2c0
--- /dev/null
+++ b/connectivity/source/drivers/flat/EPreparedStatement.cxx
@@ -0,0 +1,35 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <flat/EPreparedStatement.hxx>
+#include <flat/EResultSet.hxx>
+
+using namespace connectivity::flat;
+using namespace connectivity::file;
+using namespace ::com::sun::star::uno;
+
+rtl::Reference<OResultSet> OFlatPreparedStatement::createResultSet()
+{
+ return new OFlatResultSet(this, m_aSQLIterator);
+}
+
+IMPLEMENT_SERVICE_INFO(OFlatPreparedStatement, "com.sun.star.sdbc.driver.flat.PreparedStatement",
+ "com.sun.star.sdbc.PreparedStatement");
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/flat/EResultSet.cxx b/connectivity/source/drivers/flat/EResultSet.cxx
new file mode 100644
index 0000000000..9d1975c77e
--- /dev/null
+++ b/connectivity/source/drivers/flat/EResultSet.cxx
@@ -0,0 +1,169 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/sdbcx/CompareBookmark.hpp>
+#include <com/sun/star/sdbcx/XDeleteRows.hpp>
+#include <flat/EResultSet.hxx>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <comphelper/sequence.hxx>
+#include <comphelper/types.hxx>
+#include <cppuhelper/supportsservice.hxx>
+
+using namespace ::comphelper;
+
+using namespace connectivity::flat;
+using namespace connectivity::file;
+using namespace ::cppu;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::sdbc;
+using namespace com::sun::star::sdbcx;
+
+
+OFlatResultSet::OFlatResultSet( OStatement_Base* pStmt,connectivity::OSQLParseTreeIterator& _aSQLIterator)
+ : file::OResultSet(pStmt,_aSQLIterator)
+ ,m_bBookmarkable(true)
+{
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISBOOKMARKABLE), PROPERTY_ID_ISBOOKMARKABLE, PropertyAttribute::READONLY,&m_bBookmarkable, cppu::UnoType<bool>::get());
+}
+
+OUString SAL_CALL OFlatResultSet::getImplementationName( )
+{
+ return "com.sun.star.sdbcx.flat.ResultSet";
+}
+
+Sequence< OUString > SAL_CALL OFlatResultSet::getSupportedServiceNames( )
+{
+ return { "com.sun.star.sdbc.ResultSet", "com.sun.star.sdbcx.ResultSet" };
+}
+
+sal_Bool SAL_CALL OFlatResultSet::supportsService( const OUString& _rServiceName )
+{
+ return cppu::supportsService(this, _rServiceName);
+}
+
+Any SAL_CALL OFlatResultSet::queryInterface( const Type & rType )
+{
+ if(rType == cppu::UnoType<XDeleteRows>::get()|| rType == cppu::UnoType<XResultSetUpdate>::get()
+ || rType == cppu::UnoType<XRowUpdate>::get())
+ return Any();
+
+ const Any aRet = OResultSet::queryInterface(rType);
+ return aRet.hasValue() ? aRet : OFlatResultSet_BASE::queryInterface(rType);
+}
+
+Sequence< Type > SAL_CALL OFlatResultSet::getTypes( )
+{
+ Sequence< Type > aTypes = OResultSet::getTypes();
+ std::vector<Type> aOwnTypes;
+ aOwnTypes.reserve(aTypes.getLength());
+ const Type* pBegin = aTypes.getConstArray();
+ const Type* pEnd = pBegin + aTypes.getLength();
+ for(;pBegin != pEnd;++pBegin)
+ {
+ if(!(*pBegin == cppu::UnoType<XDeleteRows>::get()||
+ *pBegin == cppu::UnoType<XResultSetUpdate>::get()||
+ *pBegin == cppu::UnoType<XRowUpdate>::get()))
+ {
+ aOwnTypes.push_back(*pBegin);
+ }
+ }
+ Sequence< Type > aRet(aOwnTypes.data(), aOwnTypes.size());
+ return ::comphelper::concatSequences(aRet,OFlatResultSet_BASE::getTypes());
+}
+
+
+// XRowLocate
+Any SAL_CALL OFlatResultSet::getBookmark( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ return Any((*m_aRow)[0]->getValue().getInt32());
+}
+
+sal_Bool SAL_CALL OFlatResultSet::moveToBookmark( const Any& bookmark )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+
+ m_bRowDeleted = m_bRowInserted = m_bRowUpdated = false;
+
+ return Move(IResultSetHelper::BOOKMARK,comphelper::getINT32(bookmark),true);
+}
+
+sal_Bool SAL_CALL OFlatResultSet::moveRelativeToBookmark( const Any& bookmark, sal_Int32 rows )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ m_bRowDeleted = m_bRowInserted = m_bRowUpdated = false;
+
+ Move(IResultSetHelper::BOOKMARK,comphelper::getINT32(bookmark),false);
+
+ return relative(rows);
+}
+
+
+sal_Int32 SAL_CALL OFlatResultSet::compareBookmarks( const Any& lhs, const Any& rhs )
+{
+ return (lhs == rhs) ? CompareBookmark::EQUAL : CompareBookmark::NOT_EQUAL;
+}
+
+sal_Bool SAL_CALL OFlatResultSet::hasOrderedBookmarks( )
+{
+ return true;
+}
+
+sal_Int32 SAL_CALL OFlatResultSet::hashBookmark( const Any& bookmark )
+{
+ return comphelper::getINT32(bookmark);
+}
+
+IPropertyArrayHelper* OFlatResultSet::createArrayHelper( ) const
+{
+ Sequence< Property > aProps;
+ describeProperties(aProps);
+ return new ::cppu::OPropertyArrayHelper(aProps);
+}
+
+IPropertyArrayHelper & OFlatResultSet::getInfoHelper()
+{
+ return *OFlatResultSet_BASE3::getArrayHelper();
+}
+
+void SAL_CALL OFlatResultSet::acquire() noexcept
+{
+ OFlatResultSet_BASE2::acquire();
+}
+
+void SAL_CALL OFlatResultSet::release() noexcept
+{
+ OFlatResultSet_BASE2::release();
+}
+
+css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL OFlatResultSet::getPropertySetInfo( )
+{
+ return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper());
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/flat/EStatement.cxx b/connectivity/source/drivers/flat/EStatement.cxx
new file mode 100644
index 0000000000..dc801ac486
--- /dev/null
+++ b/connectivity/source/drivers/flat/EStatement.cxx
@@ -0,0 +1,34 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <flat/EStatement.hxx>
+#include <flat/EResultSet.hxx>
+
+using namespace connectivity::flat;
+using namespace connectivity::file;
+using namespace css::uno;
+
+rtl::Reference<OResultSet> OFlatStatement::createResultSet()
+{
+ return new OFlatResultSet(this,m_aSQLIterator);
+}
+
+IMPLEMENT_SERVICE_INFO(OFlatStatement,"com.sun.star.sdbc.driver.flat.Statement","com.sun.star.sdbc.Statement");
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/flat/ETable.cxx b/connectivity/source/drivers/flat/ETable.cxx
new file mode 100644
index 0000000000..9cab6b13da
--- /dev/null
+++ b/connectivity/source/drivers/flat/ETable.cxx
@@ -0,0 +1,947 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <flat/ETable.hxx>
+#include <com/sun/star/sdbc/ColumnValue.hpp>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/ucb/XContentAccess.hpp>
+#include <flat/EConnection.hxx>
+#include <flat/EColumns.hxx>
+#include <o3tl/safeint.hxx>
+#include <rtl/math.hxx>
+#include <sal/log.hxx>
+#include <tools/urlobj.hxx>
+#include <cppuhelper/queryinterface.hxx>
+#include <comphelper/numbers.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <com/sun/star/util/NumberFormat.hpp>
+#include <com/sun/star/util/NumberFormatter.hpp>
+#include <com/sun/star/util/NumberFormatsSupplier.hpp>
+#include <i18nlangtag/languagetag.hxx>
+#include <connectivity/dbconversion.hxx>
+#include <connectivity/sdbcx/VColumn.hxx>
+#include <file/quotedstring.hxx>
+#include <file/FDriver.hxx>
+#include <unotools/syslocale.hxx>
+#include <unotools/charclass.hxx>
+
+using namespace ::comphelper;
+using namespace connectivity;
+using namespace connectivity::flat;
+using namespace connectivity::file;
+using namespace ::cppu;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::ucb;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::util;
+using std::vector;
+using std::lower_bound;
+
+
+void OFlatTable::fillColumns(const css::lang::Locale& _aLocale)
+{
+ m_bNeedToReadLine = true; // we overwrite m_aCurrentLine, seek the stream, ...
+ m_pFileStream->Seek(0);
+ // tdf#123055 - start to read unicode text in order to avoid the BOM
+ m_pFileStream->StartReadingUnicodeText(RTL_TEXTENCODING_DONTKNOW);
+ m_aCurrentLine = QuotedTokenizedString();
+ bool bRead = true;
+
+ const OFlatConnection* const pConnection = getFlatConnection();
+ const bool bHasHeaderLine = pConnection->isHeaderLine();
+
+ QuotedTokenizedString aHeaderLine;
+ const sal_Int32 nPos = static_cast<sal_Int32>(m_pFileStream->Tell());
+ TRowPositionInFile rowPos(nPos, nPos);
+ sal_Int32 rowNum(0);
+ if ( bHasHeaderLine )
+ {
+ bRead = readLine(&rowPos.second, &rowPos.first, true);
+ if(bRead)
+ aHeaderLine = m_aCurrentLine;
+ }
+ setRowPos(rowNum++, rowPos);
+
+ // read first row
+ if(bRead)
+ {
+ bRead = readLine(&rowPos.second, &rowPos.first);
+ if(bRead)
+ setRowPos(rowNum++, rowPos);
+ }
+
+ if ( !bHasHeaderLine || !aHeaderLine.Len())
+ {
+ // use first non-empty row as headerline because we need the number of columns
+ while(bRead && m_aCurrentLine.Len() == 0)
+ {
+ bRead = readLine(&rowPos.second, &rowPos.first);
+ if(bRead)
+ setRowPos(rowNum++, rowPos);
+ }
+ aHeaderLine = m_aCurrentLine;
+ }
+ // column count
+ const sal_Int32 nFieldCount = aHeaderLine.GetTokenCount(m_cFieldDelimiter,m_cStringDelimiter);
+
+ if(!m_aColumns.is())
+ m_aColumns = new OSQLColumns();
+ else
+ m_aColumns->clear();
+
+ m_aTypes.clear();
+ m_aPrecisions.clear();
+ m_aScales.clear();
+ // reserve some space
+ m_aColumns->reserve(nFieldCount+1);
+ m_aTypes.assign(nFieldCount+1,DataType::SQLNULL);
+ m_aPrecisions.assign(nFieldCount+1,-1);
+ m_aScales.assign(nFieldCount+1,-1);
+
+ const bool bCase = m_pConnection->getMetaData()->supportsMixedCaseQuotedIdentifiers();
+ CharClass aCharClass( pConnection->getDriver()->getComponentContext(), LanguageTag( _aLocale));
+ // read description
+ const sal_Unicode cDecimalDelimiter = pConnection->getDecimalDelimiter();
+ const sal_Unicode cThousandDelimiter = pConnection->getThousandDelimiter();
+ ::comphelper::UStringMixEqual aCase(bCase);
+ vector<OUString> aColumnNames;
+ vector<OUString> aTypeNames;
+ aTypeNames.resize(nFieldCount);
+ const sal_Int32 nMaxRowsToScan = pConnection->getMaxRowsToScan();
+ sal_Int32 nRowCount = 0;
+
+ do
+ {
+ sal_Int32 nStartPosHeaderLine = 0; // use for efficient way to get the tokens
+ sal_Int32 nStartPosFirstLine = 0; // use for efficient way to get the tokens
+ sal_Int32 nStartPosFirstLine2 = 0;
+ for( sal_Int32 i = 0; i < nFieldCount; i++ )
+ {
+ if ( nRowCount == 0)
+ {
+ OUString aColumnName;
+ if ( bHasHeaderLine )
+ {
+ aColumnName = aHeaderLine.GetTokenSpecial(nStartPosHeaderLine,m_cFieldDelimiter,m_cStringDelimiter);
+ }
+ if ( aColumnName.isEmpty() )
+ {
+ aColumnName = "C" + OUString::number(i+1);
+ }
+ aColumnNames.push_back(aColumnName);
+ }
+ if(bRead)
+ {
+ impl_fillColumnInfo_nothrow(m_aCurrentLine, nStartPosFirstLine, nStartPosFirstLine2,
+ m_aTypes[i], m_aPrecisions[i], m_aScales[i], aTypeNames[i],
+ cDecimalDelimiter, cThousandDelimiter, aCharClass);
+ }
+ }
+ ++nRowCount;
+ bRead = readLine(&rowPos.second, &rowPos.first);
+ if(bRead)
+ setRowPos(rowNum++, rowPos);
+ }
+ while(nRowCount < nMaxRowsToScan && bRead);
+
+ for( sal_Int32 i = 0; i < nFieldCount; i++ )
+ {
+ // check if the columname already exists
+ OUString aAlias(aColumnNames[i]);
+ OSQLColumns::const_iterator aFind = connectivity::find(m_aColumns->begin(),m_aColumns->end(),aAlias,aCase);
+ sal_Int32 nExprCnt = 0;
+ while(aFind != m_aColumns->end())
+ {
+ aAlias = aColumnNames[i] + OUString::number(++nExprCnt);
+ aFind = connectivity::find(m_aColumns->begin(),m_aColumns->end(),aAlias,aCase);
+ }
+
+ rtl::Reference<sdbcx::OColumn> pColumn = new sdbcx::OColumn(aAlias,aTypeNames[i],OUString(),OUString(),
+ ColumnValue::NULLABLE,
+ m_aPrecisions[i],
+ m_aScales[i],
+ m_aTypes[i],
+ false,
+ false,
+ false,
+ bCase,
+ m_CatalogName, getSchema(), getName());
+ m_aColumns->push_back(pColumn);
+ }
+
+ m_pFileStream->Seek(m_aRowPosToFilePos[0].second);
+}
+
+void OFlatTable::impl_fillColumnInfo_nothrow(QuotedTokenizedString const & aFirstLine, sal_Int32& nStartPosFirstLine, sal_Int32& nStartPosFirstLine2,
+ sal_Int32& io_nType, sal_Int32& io_nPrecisions, sal_Int32& io_nScales, OUString& o_sTypeName,
+ const sal_Unicode cDecimalDelimiter, const sal_Unicode cThousandDelimiter, const CharClass& aCharClass)
+{
+ if ( io_nType != DataType::VARCHAR )
+ {
+ bool bNumeric = io_nType == DataType::SQLNULL || io_nType == DataType::DOUBLE || io_nType == DataType::DECIMAL || io_nType == DataType::INTEGER;
+ sal_Int32 nIndex = 0;
+
+ if ( bNumeric )
+ {
+ // first without fielddelimiter
+ OUString aField = aFirstLine.GetTokenSpecial(nStartPosFirstLine,m_cFieldDelimiter);
+ if (aField.isEmpty() ||
+ (m_cStringDelimiter && m_cStringDelimiter == aField[0]))
+ {
+ bNumeric = false;
+ if ( m_cStringDelimiter != '\0' )
+ aField = aFirstLine.GetTokenSpecial(nStartPosFirstLine2,m_cFieldDelimiter,m_cStringDelimiter);
+ else
+ nStartPosFirstLine2 = nStartPosFirstLine;
+ }
+ else
+ {
+ OUString aField2;
+ if ( m_cStringDelimiter != '\0' )
+ aField2 = aFirstLine.GetTokenSpecial(nStartPosFirstLine2,m_cFieldDelimiter,m_cStringDelimiter);
+ else
+ aField2 = aField;
+
+ if (aField2.isEmpty())
+ {
+ bNumeric = false;
+ }
+ else
+ {
+ bNumeric = true;
+ sal_Int32 nDot = 0;
+ sal_Int32 nDecimalDelCount = 0;
+ sal_Int32 nSpaceCount = 0;
+ for( sal_Int32 j = 0; j < aField2.getLength(); j++ )
+ {
+ const sal_Unicode c = aField2[j];
+ if ( j == nSpaceCount && m_cFieldDelimiter != 32 && c == 32 )
+ {
+ ++nSpaceCount;
+ continue;
+ }
+ // just digits, decimal- and thousands-delimiter?
+ if ( ( !cDecimalDelimiter || c != cDecimalDelimiter ) &&
+ ( !cThousandDelimiter || c != cThousandDelimiter ) &&
+ !aCharClass.isDigit(aField2,j) &&
+ ( j != 0 || (c != '+' && c != '-' ) ) )
+ {
+ bNumeric = false;
+ break;
+ }
+ if (cDecimalDelimiter && c == cDecimalDelimiter)
+ {
+ io_nPrecisions = 15; // we have a decimal value
+ io_nScales = 2;
+ ++nDecimalDelCount;
+ } // if (cDecimalDelimiter && c == cDecimalDelimiter)
+ if ( c == '.' )
+ ++nDot;
+ }
+
+ if (nDecimalDelCount > 1 || nDot > 1 ) // if there is more than one dot it isn't a number
+ bNumeric = false;
+ if (bNumeric && cThousandDelimiter)
+ {
+ // Is the delimiter correct?
+ const std::u16string_view aValue = o3tl::getToken(aField2, 0, cDecimalDelimiter);
+ for( sal_Int32 j = static_cast<sal_Int32>(aValue.size()) - 4; j >= 0; j -= 4)
+ {
+ const sal_Unicode c = aValue[j];
+ // just digits, decimal- and thousands-delimiter?
+ if (c == cThousandDelimiter && j)
+ continue;
+ else
+ {
+ bNumeric = false;
+ break;
+ }
+ }
+ }
+
+ // now also check for a date field
+ if (!bNumeric)
+ {
+ try
+ {
+ nIndex = m_xNumberFormatter->detectNumberFormat(css::util::NumberFormat::ALL,aField2);
+ }
+ catch(Exception&)
+ {
+ }
+ }
+ }
+ }
+ }
+ else if ( io_nType == DataType::DATE || io_nType == DataType::TIMESTAMP || io_nType == DataType::TIME)
+ {
+ OUString aField = aFirstLine.GetTokenSpecial(nStartPosFirstLine,m_cFieldDelimiter);
+ if (aField.isEmpty() ||
+ (m_cStringDelimiter && m_cStringDelimiter == aField[0]))
+ {
+ }
+ else
+ {
+ OUString aField2;
+ if ( m_cStringDelimiter != '\0' )
+ aField2 = aFirstLine.GetTokenSpecial(nStartPosFirstLine2,m_cFieldDelimiter,m_cStringDelimiter);
+ else
+ aField2 = aField;
+ if (!aField2.isEmpty() )
+ {
+ try
+ {
+ nIndex = m_xNumberFormatter->detectNumberFormat(css::util::NumberFormat::ALL,aField2);
+ }
+ catch(Exception&)
+ {
+ }
+ }
+ }
+ }
+
+ if (bNumeric)
+ {
+ if (cDecimalDelimiter)
+ {
+ if(io_nPrecisions)
+ {
+ io_nType = DataType::DECIMAL;
+ o_sTypeName = "DECIMAL";
+ }
+ else
+ {
+ io_nType = DataType::DOUBLE;
+ o_sTypeName = "DOUBLE";
+ }
+ }
+ else
+ {
+ io_nType = DataType::INTEGER;
+ io_nPrecisions = 0;
+ io_nScales = 0;
+ }
+ }
+ else
+ {
+ switch (comphelper::getNumberFormatType(m_xNumberFormatter,nIndex))
+ {
+ case css::util::NumberFormat::DATE:
+ io_nType = DataType::DATE;
+ o_sTypeName = "DATE";
+ break;
+ case css::util::NumberFormat::DATETIME:
+ io_nType = DataType::TIMESTAMP;
+ o_sTypeName = "TIMESTAMP";
+ break;
+ case css::util::NumberFormat::TIME:
+ io_nType = DataType::TIME;
+ o_sTypeName = "TIME";
+ break;
+ default:
+ io_nType = DataType::VARCHAR;
+ io_nPrecisions = 0; // nyi: Data can be longer!
+ io_nScales = 0;
+ o_sTypeName = "VARCHAR";
+ };
+ }
+ }
+ else
+ {
+ OUString aField = aFirstLine.GetTokenSpecial(nStartPosFirstLine,m_cFieldDelimiter);
+ if (aField.isEmpty() ||
+ (m_cStringDelimiter && m_cStringDelimiter == aField[0]))
+ {
+ if ( m_cStringDelimiter != '\0' )
+ aField = aFirstLine.GetTokenSpecial(nStartPosFirstLine2, m_cFieldDelimiter, m_cStringDelimiter);
+ else
+ nStartPosFirstLine2 = nStartPosFirstLine;
+ }
+ else
+ {
+ if ( m_cStringDelimiter != '\0' )
+ aFirstLine.GetTokenSpecial(nStartPosFirstLine2, m_cFieldDelimiter, m_cStringDelimiter);
+ }
+ }
+}
+
+OFlatTable::OFlatTable(sdbcx::OCollection* _pTables,OFlatConnection* _pConnection,
+ const OUString& Name,
+ const OUString& Type,
+ const OUString& Description ,
+ const OUString& SchemaName,
+ const OUString& CatalogName
+ ) : OFlatTable_BASE(_pTables,_pConnection,Name,
+ Type,
+ Description,
+ SchemaName,
+ CatalogName)
+ ,m_nRowPos(0)
+ ,m_nMaxRowCount(0)
+ ,m_cStringDelimiter(_pConnection->getStringDelimiter())
+ ,m_cFieldDelimiter(_pConnection->getFieldDelimiter())
+ ,m_bNeedToReadLine(false)
+{
+
+}
+
+void OFlatTable::construct()
+{
+ SvtSysLocale aLocale;
+ css::lang::Locale aAppLocale(aLocale.GetLanguageTag().getLocale());
+
+ Reference< XNumberFormatsSupplier > xSupplier = NumberFormatsSupplier::createWithLocale( m_pConnection->getDriver()->getComponentContext(), aAppLocale );
+ m_xNumberFormatter.set( NumberFormatter::create( m_pConnection->getDriver()->getComponentContext()), UNO_QUERY_THROW);
+ m_xNumberFormatter->attachNumberFormatsSupplier(xSupplier);
+ Reference<XPropertySet> xProp = xSupplier->getNumberFormatSettings();
+ xProp->getPropertyValue("NullDate") >>= m_aNullDate;
+
+ INetURLObject aURL;
+ aURL.SetURL(getEntry());
+
+ if(aURL.getExtension() != m_pConnection->getExtension())
+ aURL.setExtension(m_pConnection->getExtension());
+
+ OUString aFileName = aURL.GetMainURL(INetURLObject::DecodeMechanism::NONE);
+
+ m_pFileStream = createStream_simpleError( aFileName, StreamMode::READWRITE | StreamMode::NOCREATE | StreamMode::SHARE_DENYWRITE);
+
+ if(!m_pFileStream)
+ m_pFileStream = createStream_simpleError( aFileName, StreamMode::READ | StreamMode::NOCREATE | StreamMode::SHARE_DENYNONE);
+
+ if(!m_pFileStream)
+ return;
+
+ sal_uInt64 const nSize = m_pFileStream->remainingSize();
+
+ // Buffersize is dependent on the file-size
+ m_pFileStream->SetBufferSize(nSize > 1000000 ? 32768 :
+ nSize > 100000 ? 16384 :
+ nSize > 10000 ? 4096 : 1024);
+
+ fillColumns(aAppLocale);
+
+ refreshColumns();
+}
+
+OUString OFlatTable::getEntry() const
+{
+ OUString sURL;
+ try
+ {
+ Reference< XResultSet > xDir = m_pConnection->getDir()->getStaticResultSet();
+ Reference< XRow> xRow(xDir,UNO_QUERY);
+ OUString sName;
+ OUString sExt;
+
+ INetURLObject aURL;
+ xDir->beforeFirst();
+ while(xDir->next())
+ {
+ sName = xRow->getString(1);
+ aURL.SetSmartProtocol(INetProtocol::File);
+ OUString sUrl = m_pConnection->getURL() + "/" + sName;
+ aURL.SetSmartURL( sUrl );
+
+ // cut the extension
+ sExt = aURL.getExtension();
+
+ // name and extension have to coincide
+ if ( m_pConnection->matchesExtension( sExt ) )
+ {
+ if ( !sExt.isEmpty() )
+ sName = sName.replaceAt(sName.getLength() - (sExt.getLength() + 1), sExt.getLength()+1, u"");
+ if ( sName == m_Name )
+ {
+ Reference< XContentAccess > xContentAccess( xDir, UNO_QUERY );
+ sURL = xContentAccess->queryContentIdentifierString();
+ break;
+ }
+ }
+ }
+ xDir->beforeFirst(); // move back to before first record
+ }
+ catch(const Exception&)
+ {
+ OSL_ASSERT(false);
+ }
+ return sURL;
+}
+
+void OFlatTable::refreshColumns()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ ::std::vector< OUString> aVector;
+ aVector.reserve(m_aColumns->size());
+
+ for (auto const& column : *m_aColumns)
+ aVector.push_back(Reference< XNamed>(column,UNO_QUERY_THROW)->getName());
+
+ if(m_xColumns)
+ m_xColumns->reFill(aVector);
+ else
+ m_xColumns.reset(new OFlatColumns(this,m_aMutex,aVector));
+}
+
+
+void SAL_CALL OFlatTable::disposing()
+{
+ OFileTable::disposing();
+ ::osl::MutexGuard aGuard(m_aMutex);
+ m_aColumns = nullptr;
+}
+
+Sequence< Type > SAL_CALL OFlatTable::getTypes( )
+{
+ Sequence< Type > aTypes = OTable_TYPEDEF::getTypes();
+ vector<Type> aOwnTypes;
+ aOwnTypes.reserve(aTypes.getLength());
+ const Type* pBegin = aTypes.getConstArray();
+ const Type* pEnd = pBegin + aTypes.getLength();
+ for(;pBegin != pEnd;++pBegin)
+ {
+ if(!(*pBegin == cppu::UnoType<XKeysSupplier>::get()||
+ *pBegin == cppu::UnoType<XRename>::get()||
+ *pBegin == cppu::UnoType<XIndexesSupplier>::get()||
+ *pBegin == cppu::UnoType<XAlterTable>::get()||
+ *pBegin == cppu::UnoType<XDataDescriptorFactory>::get()))
+ {
+ aOwnTypes.push_back(*pBegin);
+ }
+ }
+ return Sequence< Type >(aOwnTypes.data(), aOwnTypes.size());
+}
+
+
+Any SAL_CALL OFlatTable::queryInterface( const Type & rType )
+{
+ if( rType == cppu::UnoType<XKeysSupplier>::get()||
+ rType == cppu::UnoType<XIndexesSupplier>::get()||
+ rType == cppu::UnoType<XRename>::get()||
+ rType == cppu::UnoType<XAlterTable>::get()||
+ rType == cppu::UnoType<XDataDescriptorFactory>::get())
+ return Any();
+
+ Any aRet = OTable_TYPEDEF::queryInterface(rType);
+ return aRet;
+}
+
+
+bool OFlatTable::fetchRow(OValueRefRow& _rRow, const OSQLColumns & _rCols, bool bRetrieveData)
+{
+ *(*_rRow)[0] = m_nFilePos;
+
+ if (!bRetrieveData)
+ return true;
+
+ bool result = false;
+ if ( m_bNeedToReadLine )
+ {
+ m_pFileStream->Seek(m_nFilePos);
+ TRowPositionInFile rowPos(0, 0);
+ if(readLine(&rowPos.second, &rowPos.first))
+ {
+ setRowPos(m_nRowPos, rowPos);
+ m_bNeedToReadLine = false;
+ result = true;
+ }
+ // else let run through so that we set _rRow to all NULL
+ }
+
+ const OFlatConnection * const pConnection = getFlatConnection();
+ const sal_Unicode cDecimalDelimiter = pConnection->getDecimalDelimiter();
+ const sal_Unicode cThousandDelimiter = pConnection->getThousandDelimiter();
+ // Fields:
+ sal_Int32 nStartPos = 0;
+ OSQLColumns::const_iterator aIter = _rCols.begin();
+ OSQLColumns::const_iterator aEnd = _rCols.end();
+ const OValueRefVector::size_type nCount = _rRow->size();
+ for (OValueRefVector::size_type i = 1;
+ aIter != aEnd && i < nCount;
+ ++aIter, i++)
+ {
+ OUString aStr = m_aCurrentLine.GetTokenSpecial(nStartPos,m_cFieldDelimiter,m_cStringDelimiter);
+
+ if (aStr.isEmpty())
+ {
+ (*_rRow)[i]->setNull();
+ }
+ else
+ {
+ sal_Int32 nType = m_aTypes[i-1];
+ switch(nType)
+ {
+ case DataType::TIMESTAMP:
+ case DataType::DATE:
+ case DataType::TIME:
+ {
+ try
+ {
+ double nRes = m_xNumberFormatter->convertStringToNumber(css::util::NumberFormat::ALL,aStr);
+
+ switch(nType)
+ {
+ case DataType::DATE:
+ *(*_rRow)[i] = ::dbtools::DBTypeConversion::toDouble(::dbtools::DBTypeConversion::toDate(nRes,m_aNullDate));
+ break;
+ case DataType::TIMESTAMP:
+ *(*_rRow)[i] = ::dbtools::DBTypeConversion::toDouble(::dbtools::DBTypeConversion::toDateTime(nRes,m_aNullDate));
+ break;
+ default:
+ *(*_rRow)[i] = ::dbtools::DBTypeConversion::toDouble(::dbtools::DBTypeConversion::toTime(nRes));
+ }
+ }
+ catch(Exception&)
+ {
+ (*_rRow)[i]->setNull();
+ }
+ } break;
+ case DataType::DOUBLE:
+ case DataType::INTEGER:
+ case DataType::DECIMAL:
+ case DataType::NUMERIC:
+ {
+
+ OUString aStrConverted;
+ if ( DataType::INTEGER != nType )
+ {
+ OSL_ENSURE((cDecimalDelimiter && nType != DataType::INTEGER) ||
+ (!cDecimalDelimiter && nType == DataType::INTEGER),
+ "Wrong type");
+
+ OUStringBuffer aBuf(aStr.getLength());
+ // convert to Standard-Notation (DecimalPOINT without thousands-comma):
+ for (sal_Int32 j = 0; j < aStr.getLength(); ++j)
+ {
+ const sal_Unicode cChar = aStr[j];
+ if (cDecimalDelimiter && cChar == cDecimalDelimiter)
+ aBuf.append('.');
+ else if ( cChar == '.' ) // special case, if decimal separator isn't '.' we have to put the string after it
+ continue;
+ else if (cThousandDelimiter && cChar == cThousandDelimiter)
+ {
+ // leave out
+ }
+ else
+ aBuf.append(cChar);
+ } // for (j = 0; j < aStr.(); ++j)
+ aStrConverted = aBuf.makeStringAndClear();
+ } // if ( DataType::INTEGER != nType )
+ else
+ {
+ if ( cThousandDelimiter )
+ aStrConverted = aStr.replaceAll(OUStringChar(cThousandDelimiter), "");
+ else
+ aStrConverted = aStr;
+ }
+ const double nVal = ::rtl::math::stringToDouble(aStrConverted,'.',',');
+
+ // #99178# OJ
+ if ( DataType::DECIMAL == nType || DataType::NUMERIC == nType )
+ *(*_rRow)[i] = OUString::number(nVal);
+ else
+ *(*_rRow)[i] = nVal;
+ } break;
+
+ default:
+ {
+ // Copy Value as String in Row-Variable
+ *(*_rRow)[i] = ORowSetValue(aStr);
+ }
+ break;
+ } // switch(nType)
+ (*_rRow)[i]->setTypeKind(nType);
+ }
+ }
+ return result;
+}
+
+
+void OFlatTable::refreshHeader()
+{
+ SAL_INFO( "connectivity.flat", "flat lionel@mamane.lu OFlatTable::refreshHeader" );
+}
+
+
+namespace
+{
+ template< typename Tp, typename Te> struct RangeBefore
+ {
+ bool operator() (const Tp &p, const Te &e)
+ {
+ assert(p.first <= p.second);
+ return p.second <= e;
+ }
+ };
+}
+
+bool OFlatTable::seekRow(IResultSetHelper::Movement eCursorPosition, sal_Int32 nOffset, sal_Int32& nCurPos)
+{
+ OSL_ENSURE(m_pFileStream,"OFlatTable::seekRow: FileStream is NULL!");
+
+
+ switch(eCursorPosition)
+ {
+ case IResultSetHelper::FIRST:
+ m_nRowPos = 0;
+ [[fallthrough]];
+ case IResultSetHelper::NEXT:
+ {
+ assert(m_nRowPos >= 0);
+ if(m_nMaxRowCount != 0 && m_nRowPos > m_nMaxRowCount)
+ return false;
+ ++m_nRowPos;
+ if(m_aRowPosToFilePos.size() > o3tl::make_unsigned(m_nRowPos))
+ {
+ m_bNeedToReadLine = true;
+ m_nFilePos = m_aRowPosToFilePos[m_nRowPos].first;
+ nCurPos = m_aRowPosToFilePos[m_nRowPos].second;
+ }
+ else
+ {
+ assert(m_aRowPosToFilePos.size() == static_cast< vector< TRowPositionInFile >::size_type >(m_nRowPos));
+ const TRowPositionInFile &lastRowPos(m_aRowPosToFilePos.back());
+ // Our ResultSet is allowed to disagree with us only
+ // on the position of the first line
+ // (because of the special case of the header...)
+ assert(m_nRowPos == 1 || nCurPos == lastRowPos.second);
+
+ m_nFilePos = lastRowPos.second;
+ m_pFileStream->Seek(m_nFilePos);
+
+ TRowPositionInFile newRowPos;
+ if(!readLine(&newRowPos.second, &newRowPos.first))
+ {
+ m_nMaxRowCount = m_nRowPos - 1;
+ return false;
+ }
+
+ nCurPos = newRowPos.second;
+ setRowPos(m_nRowPos, newRowPos);
+ }
+ }
+
+ break;
+ case IResultSetHelper::PRIOR:
+ assert(m_nRowPos >= 0);
+
+ if(m_nRowPos == 0)
+ return false;
+
+ --m_nRowPos;
+ {
+ assert (m_nRowPos >= 0);
+ assert(m_aRowPosToFilePos.size() >= o3tl::make_unsigned(m_nRowPos));
+ const TRowPositionInFile &aPositions(m_aRowPosToFilePos[m_nRowPos]);
+ m_nFilePos = aPositions.first;
+ nCurPos = aPositions.second;
+ m_bNeedToReadLine = true;
+ }
+
+ break;
+ case IResultSetHelper::LAST:
+ if (m_nMaxRowCount == 0)
+ {
+ while(seekRow(IResultSetHelper::NEXT, 1, nCurPos)) ; // run through after last row
+ }
+ // m_nMaxRowCount can still be zero, but now it means there a genuinely zero rows in the table
+ return seekRow(IResultSetHelper::ABSOLUTE1, m_nMaxRowCount, nCurPos);
+ case IResultSetHelper::RELATIVE1:
+ {
+ const sal_Int32 nNewRowPos = m_nRowPos + nOffset;
+ if (nNewRowPos < 0)
+ return false;
+ // ABSOLUTE will take care of case nNewRowPos > nMaxRowCount
+ return seekRow(IResultSetHelper::ABSOLUTE1, nNewRowPos, nCurPos);
+ }
+ case IResultSetHelper::ABSOLUTE1:
+ {
+ if(nOffset < 0)
+ {
+ if (m_nMaxRowCount == 0)
+ {
+ if (!seekRow(IResultSetHelper::LAST, 0, nCurPos))
+ return false;
+ }
+ // m_nMaxRowCount can still be zero, but now it means there a genuinely zero rows in the table
+ nOffset = m_nMaxRowCount + nOffset;
+ }
+ if(nOffset < 0)
+ {
+ seekRow(IResultSetHelper::ABSOLUTE1, 0, nCurPos);
+ return false;
+ }
+ if(m_nMaxRowCount && nOffset > m_nMaxRowCount)
+ {
+ m_nRowPos = m_nMaxRowCount + 1;
+ const TRowPositionInFile &lastRowPos(m_aRowPosToFilePos.back());
+ m_nFilePos = lastRowPos.second;
+ nCurPos = lastRowPos.second;
+ return false;
+ }
+
+ assert(m_nRowPos >=0);
+ assert(m_aRowPosToFilePos.size() > o3tl::make_unsigned(m_nRowPos));
+ assert(nOffset >= 0);
+ if(m_aRowPosToFilePos.size() > o3tl::make_unsigned(nOffset))
+ {
+ m_nFilePos = m_aRowPosToFilePos[nOffset].first;
+ nCurPos = m_aRowPosToFilePos[nOffset].second;
+ m_nRowPos = nOffset;
+ m_bNeedToReadLine = true;
+ }
+ else
+ {
+ assert(m_nRowPos < nOffset);
+ while(m_nRowPos < nOffset)
+ {
+ if(!seekRow(IResultSetHelper::NEXT, 1, nCurPos))
+ return false;
+ }
+ assert(m_nRowPos == nOffset);
+ }
+ }
+
+ break;
+ case IResultSetHelper::BOOKMARK:
+ {
+ vector< TRowPositionInFile >::const_iterator aFind = lower_bound(m_aRowPosToFilePos.begin(),
+ m_aRowPosToFilePos.end(),
+ nOffset,
+ RangeBefore< TRowPositionInFile, sal_Int32 >());
+
+ if(aFind == m_aRowPosToFilePos.end() || aFind->first != nOffset)
+ //invalid bookmark
+ return false;
+
+ m_bNeedToReadLine = true;
+ m_nFilePos = aFind->first;
+ nCurPos = aFind->second;
+ m_nRowPos = aFind - m_aRowPosToFilePos.begin();
+ break;
+ }
+ }
+
+ return true;
+}
+
+
+bool OFlatTable::readLine(sal_Int32 * const pEndPos, sal_Int32 * const pStartPos, const bool nonEmpty)
+{
+ const rtl_TextEncoding nEncoding = m_pConnection->getTextEncoding();
+ m_aCurrentLine = QuotedTokenizedString();
+ do
+ {
+ if (pStartPos)
+ *pStartPos = static_cast<sal_Int32>(m_pFileStream->Tell());
+ m_pFileStream->ReadByteStringLine(m_aCurrentLine, nEncoding);
+ if (m_pFileStream->eof())
+ return false;
+
+ QuotedTokenizedString sLine = m_aCurrentLine; // check if the string continues on next line
+ sal_Int32 nLastOffset = 0;
+ bool isQuoted = false;
+ bool isFieldStarting = true;
+ while (true)
+ {
+ bool wasQuote = false;
+ const sal_Unicode *p = sLine.GetString().getStr() + nLastOffset;
+ while (*p)
+ {
+ if (isQuoted)
+ {
+ if (*p == m_cStringDelimiter)
+ wasQuote = !wasQuote;
+ else
+ {
+ if (wasQuote)
+ {
+ wasQuote = false;
+ isQuoted = false;
+ if (*p == m_cFieldDelimiter)
+ isFieldStarting = true;
+ }
+ }
+ }
+ else
+ {
+ if (isFieldStarting)
+ {
+ isFieldStarting = false;
+ if (*p == m_cStringDelimiter)
+ isQuoted = true;
+ else if (*p == m_cFieldDelimiter)
+ isFieldStarting = true;
+ }
+ else if (*p == m_cFieldDelimiter)
+ isFieldStarting = true;
+ }
+ ++p;
+ }
+
+ if (wasQuote)
+ isQuoted = false;
+
+ if (isQuoted)
+ {
+ nLastOffset = sLine.Len();
+ m_pFileStream->ReadByteStringLine(sLine,nEncoding);
+ if ( !m_pFileStream->eof() )
+ {
+ OUString aStr = m_aCurrentLine.GetString() + "\n" + sLine.GetString();
+ m_aCurrentLine.SetString(aStr);
+ sLine = m_aCurrentLine;
+ }
+ else
+ break;
+ }
+ else
+ break;
+ }
+ }
+ while(nonEmpty && m_aCurrentLine.Len() == 0);
+
+ if(pEndPos)
+ *pEndPos = static_cast<sal_Int32>(m_pFileStream->Tell());
+ return true;
+}
+
+
+void OFlatTable::setRowPos(const vector<TRowPositionInFile>::size_type rowNum, const TRowPositionInFile &rowPos)
+{
+ assert(m_aRowPosToFilePos.size() >= rowNum);
+ if(m_aRowPosToFilePos.size() == rowNum)
+ m_aRowPosToFilePos.push_back(rowPos);
+ else
+ {
+ SAL_WARN_IF(m_aRowPosToFilePos[rowNum] != rowPos,
+ "connectivity.flat",
+ "Setting position for row " << rowNum << " to (" << rowPos.first << ", " << rowPos.second << "), "
+ "but already had different position (" << m_aRowPosToFilePos[rowNum].first << ", " << m_aRowPosToFilePos[rowNum].second << ")");
+ m_aRowPosToFilePos[rowNum] = rowPos;
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/flat/ETables.cxx b/connectivity/source/drivers/flat/ETables.cxx
new file mode 100644
index 0000000000..2e4dd377ed
--- /dev/null
+++ b/connectivity/source/drivers/flat/ETables.cxx
@@ -0,0 +1,44 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <flat/ETables.hxx>
+#include <flat/ETable.hxx>
+#include <file/FCatalog.hxx>
+
+using namespace connectivity;
+using namespace ::comphelper;
+using namespace connectivity::flat;
+using namespace connectivity::file;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::container;
+
+sdbcx::ObjectType OFlatTables::createObject(const OUString& _rName)
+{
+ rtl::Reference<OFlatTable> pRet = new OFlatTable(this, static_cast<OFlatConnection*>(static_cast<OFileCatalog&>(m_rParent).getConnection()),
+ _rName,"TABLE");
+ pRet->construct();
+ return pRet;
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/flat/flat.component b/connectivity/source/drivers/flat/flat.component
new file mode 100644
index 0000000000..715fbecd89
--- /dev/null
+++ b/connectivity/source/drivers/flat/flat.component
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ -->
+
+<component loader="com.sun.star.loader.SharedLibrary" environment="@CPPU_ENV@"
+ xmlns="http://openoffice.org/2010/uno-components">
+ <implementation name="com.sun.star.comp.sdbc.flat.ODriver"
+ constructor="connectivity_flat_ODriver">
+ <service name="com.sun.star.sdbc.Driver"/>
+ <service name="com.sun.star.sdbcx.Driver"/>
+ </implementation>
+</component>
diff --git a/connectivity/source/drivers/hsqldb/HCatalog.cxx b/connectivity/source/drivers/hsqldb/HCatalog.cxx
new file mode 100644
index 0000000000..1074be5355
--- /dev/null
+++ b/connectivity/source/drivers/hsqldb/HCatalog.cxx
@@ -0,0 +1,148 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <hsqldb/HCatalog.hxx>
+#include <hsqldb/HUsers.hxx>
+#include <hsqldb/HTables.hxx>
+#include <hsqldb/HViews.hxx>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XResultSet.hpp>
+#include <comphelper/types.hxx>
+
+
+using namespace connectivity;
+using namespace connectivity::hsqldb;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+
+OHCatalog::OHCatalog(const Reference< XConnection >& _xConnection) : sdbcx::OCatalog(_xConnection)
+ ,m_xConnection(_xConnection)
+{
+}
+
+void OHCatalog::refreshObjects(const Sequence< OUString >& _sKindOfObject,::std::vector< OUString>& _rNames)
+{
+ Reference< XResultSet > xResult = m_xMetaData->getTables(Any(),
+ "%",
+ "%",
+ _sKindOfObject);
+ fillNames(xResult,_rNames);
+}
+
+void OHCatalog::refreshTables()
+{
+ ::std::vector< OUString> aVector;
+
+ Sequence< OUString > sTableTypes {"VIEW", "TABLE"};
+
+ refreshObjects(sTableTypes,aVector);
+
+ if ( m_pTables )
+ m_pTables->reFill(aVector);
+ else
+ m_pTables.reset( new OTables(m_xMetaData,*this,m_aMutex,aVector) );
+}
+
+void OHCatalog::refreshViews()
+{
+ Sequence< OUString > aTypes { "VIEW" };
+
+ bool bSupportsViews = false;
+ try
+ {
+ Reference<XResultSet> xRes = m_xMetaData->getTableTypes();
+ Reference<XRow> xRow(xRes,UNO_QUERY);
+ while ( xRow.is() && xRes->next() )
+ {
+ if ( (bSupportsViews = xRow->getString(1).equalsIgnoreAsciiCase(aTypes[0])) )
+ {
+ break;
+ }
+ }
+ }
+ catch(const SQLException&)
+ {
+ }
+
+ ::std::vector< OUString> aVector;
+ if ( bSupportsViews )
+ refreshObjects(aTypes,aVector);
+
+ if ( m_pViews )
+ m_pViews->reFill(aVector);
+ else
+ m_pViews.reset( new HViews( m_xConnection, *this, m_aMutex, aVector ) );
+}
+
+void OHCatalog::refreshGroups()
+{
+}
+
+void OHCatalog::refreshUsers()
+{
+ ::std::vector< OUString> aVector;
+ Reference< XStatement > xStmt = m_xConnection->createStatement( );
+ Reference< XResultSet > xResult = xStmt->executeQuery("select User from hsqldb.user group by User");
+ if ( xResult.is() )
+ {
+ Reference< XRow > xRow(xResult,UNO_QUERY);
+ while( xResult->next() )
+ aVector.push_back(xRow->getString(1));
+ ::comphelper::disposeComponent(xResult);
+ }
+ ::comphelper::disposeComponent(xStmt);
+
+ if(m_pUsers)
+ m_pUsers->reFill(aVector);
+ else
+ m_pUsers.reset( new OUsers(*this,m_aMutex,aVector,m_xConnection,this) );
+}
+
+Any SAL_CALL OHCatalog::queryInterface( const Type & rType )
+{
+ if ( rType == cppu::UnoType<XGroupsSupplier>::get())
+ return Any();
+
+ return OCatalog::queryInterface(rType);
+}
+
+Sequence< Type > SAL_CALL OHCatalog::getTypes( )
+{
+ Sequence< Type > aTypes = OCatalog::getTypes();
+ std::vector<Type> aOwnTypes;
+ aOwnTypes.reserve(aTypes.getLength());
+ const Type* pBegin = aTypes.getConstArray();
+ const Type* pEnd = pBegin + aTypes.getLength();
+ for(;pBegin != pEnd;++pBegin)
+ {
+ if ( *pBegin != cppu::UnoType<XGroupsSupplier>::get())
+ {
+ aOwnTypes.push_back(*pBegin);
+ }
+ }
+ return Sequence< Type >(aOwnTypes.data(), aOwnTypes.size());
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/hsqldb/HColumns.cxx b/connectivity/source/drivers/hsqldb/HColumns.cxx
new file mode 100644
index 0000000000..3f03c3616b
--- /dev/null
+++ b/connectivity/source/drivers/hsqldb/HColumns.cxx
@@ -0,0 +1,76 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <hsqldb/HColumns.hxx>
+#include <TConnection.hxx>
+
+
+using namespace ::comphelper;
+using namespace connectivity::hsqldb;
+using namespace connectivity::sdbcx;
+using namespace connectivity;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+
+OHSQLColumns::OHSQLColumns( ::cppu::OWeakObject& _rParent
+ ,::osl::Mutex& _rMutex
+ ,const ::std::vector< OUString> &_rVector
+ ) : OColumnsHelper(_rParent,true/*_bCase*/,_rMutex,_rVector,true/*_bUseHardRef*/)
+{
+}
+
+Reference< XPropertySet > OHSQLColumns::createDescriptor()
+{
+ return new OHSQLColumn;
+}
+
+
+OHSQLColumn::OHSQLColumn()
+ : connectivity::sdbcx::OColumn( true/*_bCase*/ )
+{
+ construct();
+}
+
+void OHSQLColumn::construct()
+{
+ m_sAutoIncrement = "IDENTITY";
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_AUTOINCREMENTCREATION),PROPERTY_ID_AUTOINCREMENTCREATION,0,&m_sAutoIncrement, cppu::UnoType<decltype(m_sAutoIncrement)>::get());
+}
+
+::cppu::IPropertyArrayHelper* OHSQLColumn::createArrayHelper( sal_Int32 /*_nId*/ ) const
+{
+ return doCreateArrayHelper();
+}
+
+::cppu::IPropertyArrayHelper & SAL_CALL OHSQLColumn::getInfoHelper()
+{
+ return *OHSQLColumn_PROP::getArrayHelper(isNew() ? 1 : 0);
+}
+
+Sequence< OUString > SAL_CALL OHSQLColumn::getSupportedServiceNames( )
+{
+ return { "com.sun.star.sdbcx.Column" };
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/hsqldb/HConnection.cxx b/connectivity/source/drivers/hsqldb/HConnection.cxx
new file mode 100644
index 0000000000..28feb95fce
--- /dev/null
+++ b/connectivity/source/drivers/hsqldb/HConnection.cxx
@@ -0,0 +1,336 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <hsqldb/HConnection.hxx>
+#include <hsqldb/HTools.hxx>
+#include <bitmaps.hlst>
+
+#include <connectivity/dbtools.hxx>
+
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <com/sun/star/sdbcx/XDataDefinitionSupplier.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/graphic/GraphicProvider.hpp>
+#include <com/sun/star/graphic/XGraphicProvider.hpp>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/sdbc/XDatabaseMetaData2.hpp>
+
+#include <comphelper/propertyvalue.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <sal/log.hxx>
+#include <comphelper/diagnose_ex.hxx>
+
+#include <resource/sharedresources.hxx>
+#include <strings.hrc>
+
+using ::com::sun::star::util::XFlushListener;
+using ::com::sun::star::lang::EventObject;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::Exception;
+using ::com::sun::star::uno::RuntimeException;
+using ::com::sun::star::uno::UNO_QUERY;
+using ::com::sun::star::uno::UNO_QUERY_THROW;
+using ::com::sun::star::uno::XComponentContext;
+using ::com::sun::star::sdbc::XStatement;
+using ::com::sun::star::sdbc::XConnection;
+using ::com::sun::star::sdbcx::XDataDefinitionSupplier;
+using ::com::sun::star::sdbcx::XTablesSupplier;
+using ::com::sun::star::container::XNameAccess;
+using ::com::sun::star::uno::Sequence;
+using ::com::sun::star::lang::WrappedTargetException;
+using ::com::sun::star::sdbc::XDriver;
+using ::com::sun::star::graphic::XGraphic;
+using ::com::sun::star::graphic::GraphicProvider;
+using ::com::sun::star::graphic::XGraphicProvider;
+using ::com::sun::star::uno::XInterface;
+using ::com::sun::star::lang::IllegalArgumentException;
+using ::com::sun::star::sdbc::XResultSet;
+using ::com::sun::star::sdbc::XDatabaseMetaData;
+using ::com::sun::star::sdbc::XDatabaseMetaData2;
+using ::com::sun::star::sdbc::XRow;
+using ::com::sun::star::sdb::application::XDatabaseDocumentUI;
+using ::com::sun::star::beans::PropertyValue;
+
+
+namespace connectivity::hsqldb
+{
+ void SAL_CALL OHsqlConnection::disposing()
+ {
+ m_aFlushListeners.disposeAndClear( EventObject( *this ) );
+ OHsqlConnection_BASE::disposing();
+ OConnectionWrapper::disposing();
+ }
+
+ OHsqlConnection::OHsqlConnection( const Reference< XDriver >& _rxDriver,
+ const Reference< XConnection >& _xConnection ,const Reference< XComponentContext >& _rxContext )
+ :OHsqlConnection_BASE( m_aMutex )
+ ,m_aFlushListeners( m_aMutex )
+ ,m_xDriver( _rxDriver )
+ ,m_xContext( _rxContext )
+ ,m_bIni(true)
+ ,m_bReadOnly(false)
+ {
+ setDelegation(_xConnection,_rxContext,m_refCount);
+ }
+
+ OHsqlConnection::~OHsqlConnection()
+ {
+ if ( !OHsqlConnection_BASE::rBHelper.bDisposed )
+ {
+ osl_atomic_increment( &m_refCount );
+ dispose();
+ }
+ }
+
+ IMPLEMENT_FORWARD_XINTERFACE2(OHsqlConnection,OHsqlConnection_BASE,OConnectionWrapper)
+ IMPLEMENT_SERVICE_INFO(OHsqlConnection, "com.sun.star.sdbc.drivers.hsqldb.OHsqlConnection", "com.sun.star.sdbc.Connection")
+ IMPLEMENT_FORWARD_XTYPEPROVIDER2(OHsqlConnection,OHsqlConnection_BASE,OConnectionWrapper)
+
+
+ ::osl::Mutex& OHsqlConnection::getMutex() const
+ {
+ return m_aMutex;
+ }
+
+
+ void OHsqlConnection::checkDisposed() const
+ {
+ ::connectivity::checkDisposed( rBHelper.bDisposed );
+ }
+
+ // XFlushable
+
+ void SAL_CALL OHsqlConnection::flush( )
+ {
+ MethodGuard aGuard( *this );
+
+ try
+ {
+ if ( m_xConnection.is() )
+ {
+ if ( m_bIni )
+ {
+ m_bIni = false;
+ Reference< XDatabaseMetaData2 > xMeta2(m_xConnection->getMetaData(),UNO_QUERY_THROW);
+ const Sequence< PropertyValue > aInfo = xMeta2->getConnectionInfo();
+ const PropertyValue* pIter = aInfo.getConstArray();
+ const PropertyValue* pEnd = pIter + aInfo.getLength();
+ for(;pIter != pEnd;++pIter)
+ {
+ if ( pIter->Name == "readonly" )
+ m_bReadOnly = true;
+ }
+ }
+ try
+ {
+ if ( !m_bReadOnly )
+ {
+ Reference< XStatement > xStmt( m_xConnection->createStatement(), css::uno::UNO_SET_THROW );
+ xStmt->execute( "CHECKPOINT DEFRAG" );
+ }
+ }
+ catch(const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("connectivity.hsqldb");
+ }
+ }
+
+ EventObject aFlushedEvent( *this );
+ m_aFlushListeners.notifyEach( &XFlushListener::flushed, aFlushedEvent );
+ }
+ catch(const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("connectivity.hsqldb");
+ }
+ }
+
+
+ void SAL_CALL OHsqlConnection::addFlushListener( const Reference< XFlushListener >& l )
+ {
+ MethodGuard aGuard( *this );
+ m_aFlushListeners.addInterface( l );
+ }
+
+
+ void SAL_CALL OHsqlConnection::removeFlushListener( const Reference< XFlushListener >& l )
+ {
+ MethodGuard aGuard( *this );
+ m_aFlushListeners.removeInterface( l );
+ }
+
+
+ Reference< XGraphic > SAL_CALL OHsqlConnection::getTableIcon( const OUString& TableName, ::sal_Int32 /*_ColorMode*/ )
+ {
+ MethodGuard aGuard( *this );
+
+ impl_checkExistingTable_throw( TableName );
+ if ( !impl_isTextTable_nothrow( TableName ) )
+ return nullptr;
+
+ return impl_getTextTableIcon_nothrow();
+ }
+
+
+ Reference< XInterface > SAL_CALL OHsqlConnection::getTableEditor( const Reference< XDatabaseDocumentUI >& DocumentUI, const OUString& TableName )
+ {
+ MethodGuard aGuard( *this );
+
+ impl_checkExistingTable_throw( TableName );
+ if ( !impl_isTextTable_nothrow( TableName ) )
+ return nullptr;
+
+ if ( !DocumentUI.is() )
+ {
+ ::connectivity::SharedResources aResources;
+ const OUString sError( aResources.getResourceString(STR_NO_DOCUMENTUI));
+ throw IllegalArgumentException(
+ sError,
+ *this,
+ 0
+ );
+ } // if ( !_DocumentUI.is() )
+
+
+// Reference< XExecutableDialog > xEditor = impl_createLinkedTableEditor_throw( _DocumentUI, _TableName );
+// return xEditor.get();
+ return nullptr;
+ // editor not yet implemented in this CWS
+ }
+
+
+ Reference< XNameAccess > OHsqlConnection::impl_getTableContainer_throw()
+ {
+ Reference< XNameAccess > xTables;
+ try
+ {
+ Reference< XConnection > xMe( *this, UNO_QUERY );
+ Reference< XDataDefinitionSupplier > xDefinitionsSupp( m_xDriver, UNO_QUERY_THROW );
+ Reference< XTablesSupplier > xTablesSupp( xDefinitionsSupp->getDataDefinitionByConnection( xMe ), css::uno::UNO_SET_THROW );
+ xTables.set( xTablesSupp->getTables(), css::uno::UNO_SET_THROW );
+ }
+ catch( const RuntimeException& ) { throw; }
+ catch( const Exception& )
+ {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ ::connectivity::SharedResources aResources;
+ const OUString sError( aResources.getResourceString(STR_NO_TABLE_CONTAINER));
+ throw WrappedTargetException( sError ,*this, anyEx );
+ }
+
+ SAL_WARN_IF( !xTables.is(), "connectivity.hsqldb", "OHsqlConnection::impl_getTableContainer_throw: post condition not met!" );
+ return xTables;
+ }
+
+ //TODO: resource
+
+ void OHsqlConnection::impl_checkExistingTable_throw( const OUString& _rTableName )
+ {
+ bool bDoesExist = false;
+ try
+ {
+ Reference< XNameAccess > xTables( impl_getTableContainer_throw(), css::uno::UNO_SET_THROW );
+ bDoesExist = xTables->hasByName( _rTableName );
+ }
+ catch( const Exception& )
+ {
+ // that's a serious error in impl_getTableContainer_throw, or hasByName, however, we're only
+ // allowed to throw an IllegalArgumentException ourself
+ DBG_UNHANDLED_EXCEPTION("connectivity.hsqldb");
+ }
+
+ if ( !bDoesExist )
+ {
+ ::connectivity::SharedResources aResources;
+ const OUString sError( aResources.getResourceStringWithSubstitution(
+ STR_NO_TABLENAME,
+ "$tablename$", _rTableName
+ ));
+ throw IllegalArgumentException( sError,*this, 0 );
+ } // if ( !bDoesExist )
+ }
+
+
+ bool OHsqlConnection::impl_isTextTable_nothrow( const OUString& _rTableName )
+ {
+ bool bIsTextTable = false;
+ try
+ {
+ Reference< XConnection > xMe( *this, UNO_QUERY_THROW );
+
+ // split the fully qualified name
+ Reference< XDatabaseMetaData > xMetaData( xMe->getMetaData(), css::uno::UNO_SET_THROW );
+ OUString sCatalog, sSchema, sName;
+ ::dbtools::qualifiedNameComponents( xMetaData, _rTableName, sCatalog, sSchema, sName, ::dbtools::EComposeRule::Complete );
+
+ // get the table information
+ OUStringBuffer sSQL( "SELECT HSQLDB_TYPE FROM INFORMATION_SCHEMA.SYSTEM_TABLES" );
+ HTools::appendTableFilterCrit( sSQL, sCatalog, sSchema, sName, true );
+ sSQL.append( " AND TABLE_TYPE = 'TABLE'" );
+
+ Reference< XStatement > xStatement( xMe->createStatement(), css::uno::UNO_SET_THROW );
+ Reference< XResultSet > xTableHsqlType( xStatement->executeQuery( sSQL.makeStringAndClear() ), css::uno::UNO_SET_THROW );
+
+ if ( xTableHsqlType->next() ) // might not succeed in case of VIEWs
+ {
+ Reference< XRow > xValueAccess( xTableHsqlType, UNO_QUERY_THROW );
+ OUString sTableType = xValueAccess->getString( 1 );
+ bIsTextTable = sTableType == "TEXT";
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("connectivity.hsqldb");
+ }
+
+ return bIsTextTable;
+ }
+
+
+ Reference< XGraphic > OHsqlConnection::impl_getTextTableIcon_nothrow()
+ {
+ Reference< XGraphic > xGraphic;
+ try
+ {
+ // create a graphic provider
+ Reference< XGraphicProvider > xProvider;
+ if ( m_xContext.is() )
+ xProvider.set( GraphicProvider::create(m_xContext) );
+
+ // ask the provider to obtain a graphic
+ Sequence< PropertyValue > aMediaProperties{ comphelper::makePropertyValue(
+ "URL", OUString(
+ // load the graphic from the global graphic repository
+ "private:graphicrepository/"
+ // the relative path within the images.zip
+ LINKED_TEXT_TABLE_IMAGE_RESOURCE)) };
+ xGraphic = xProvider->queryGraphic( aMediaProperties );
+ OSL_ENSURE( xGraphic.is(), "OHsqlConnection::impl_getTextTableIcon_nothrow: the provider did not give us a graphic object!" );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("connectivity.hsqldb");
+ }
+ return xGraphic;
+ }
+
+} // namespace connectivity::hsqldb
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/hsqldb/HDriver.cxx b/connectivity/source/drivers/hsqldb/HDriver.cxx
new file mode 100644
index 0000000000..0439ffde75
--- /dev/null
+++ b/connectivity/source/drivers/hsqldb/HDriver.cxx
@@ -0,0 +1,892 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <hsqldb/HDriver.hxx>
+#include <hsqldb/HConnection.hxx>
+#include <osl/diagnose.h>
+#include <sal/log.hxx>
+#include <connectivity/dbexception.hxx>
+#include <com/sun/star/configuration/theDefaultProvider.hpp>
+#include <com/sun/star/sdbc/DriverManager.hpp>
+#include <com/sun/star/sdbc/XResultSet.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/embed/XTransactionBroadcaster.hpp>
+#include <com/sun/star/embed/ElementModes.hpp>
+#include <TConnection.hxx>
+#include <hsqldb/HStorageMap.hxx>
+#include <jvmfwk/framework.hxx>
+#include <com/sun/star/reflection/XProxyFactory.hpp>
+#include <com/sun/star/embed/XStorage.hpp>
+#include <com/sun/star/frame/Desktop.hpp>
+#include <com/sun/star/util/XFlushable.hpp>
+#include "HTerminateListener.hxx"
+#include <hsqldb/HCatalog.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <osl/file.h>
+#include <osl/process.h>
+#include <comphelper/namedvaluecollection.hxx>
+#include <comphelper/propertysequence.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <comphelper/types.hxx>
+#include <unotools/confignode.hxx>
+#include <unotools/ucbstreamhelper.hxx>
+#include <strings.hrc>
+#include <resource/sharedresources.hxx>
+#include <i18nlangtag/languagetag.hxx>
+#include <comphelper/diagnose_ex.hxx>
+#include <o3tl/string_view.hxx>
+
+#include <memory>
+
+
+namespace connectivity
+{
+
+ using namespace hsqldb;
+ using namespace css::uno;
+ using namespace css::sdbc;
+ using namespace css::sdbcx;
+ using namespace css::beans;
+ using namespace css::frame;
+ using namespace css::lang;
+ using namespace css::embed;
+ using namespace css::io;
+ using namespace css::util;
+ using namespace css::reflection;
+
+ constexpr OUString IMPL_NAME = u"com.sun.star.sdbcx.comp.hsqldb.Driver"_ustr;
+
+
+
+ ODriverDelegator::ODriverDelegator(const Reference< XComponentContext >& _rxContext)
+ : ODriverDelegator_BASE(m_aMutex)
+ ,m_xContext(_rxContext)
+ ,m_bInShutDownConnections(false)
+ {
+ }
+
+
+ ODriverDelegator::~ODriverDelegator()
+ {
+ try
+ {
+ ::comphelper::disposeComponent(m_xDriver);
+ }
+ catch(const Exception&)
+ {
+ }
+ }
+
+
+ void SAL_CALL ODriverDelegator::disposing()
+ {
+ ::osl::MutexGuard aGuard(m_aMutex);
+
+ try
+ {
+ for (const auto& rConnection : m_aConnections)
+ {
+ Reference<XInterface > xTemp = rConnection.first.get();
+ ::comphelper::disposeComponent(xTemp);
+ }
+ }
+ catch(Exception&)
+ {
+ // not interested in
+ }
+ m_aConnections.clear();
+ TWeakPairVector().swap(m_aConnections);
+
+ cppu::WeakComponentImplHelperBase::disposing();
+ }
+
+ Reference< XDriver > const & ODriverDelegator::loadDriver( )
+ {
+ if ( !m_xDriver.is() )
+ {
+ Reference<XDriverManager2> xDriverAccess = DriverManager::create( m_xContext );
+ m_xDriver = xDriverAccess->getDriverByURL("jdbc:hsqldb:db");
+ }
+
+ return m_xDriver;
+ }
+
+
+ namespace
+ {
+ OUString lcl_getPermittedJavaMethods_nothrow( const Reference< XComponentContext >& _rxContext )
+ {
+ OUString aConfigPath =
+ "/org.openoffice.Office.DataAccess/DriverSettings/" +
+ IMPL_NAME +
+ "/PermittedJavaMethods";
+ ::utl::OConfigurationTreeRoot aConfig( ::utl::OConfigurationTreeRoot::createWithComponentContext(
+ _rxContext, aConfigPath ) );
+
+ OUStringBuffer aPermittedMethods;
+ const Sequence< OUString > aNodeNames( aConfig.getNodeNames() );
+ for ( auto const & nodeName : aNodeNames )
+ {
+ OUString sPermittedMethod;
+ OSL_VERIFY( aConfig.getNodeValue( nodeName ) >>= sPermittedMethod );
+
+ if ( !aPermittedMethods.isEmpty() )
+ aPermittedMethods.append( ';' );
+ aPermittedMethods.append( sPermittedMethod );
+ }
+
+ return aPermittedMethods.makeStringAndClear();
+ }
+ }
+
+
+ Reference< XConnection > SAL_CALL ODriverDelegator::connect( const OUString& url, const Sequence< PropertyValue >& info )
+ {
+ Reference< XConnection > xConnection;
+ if ( acceptsURL(url) )
+ {
+ Reference< XDriver > xDriver = loadDriver();
+ if ( xDriver.is() )
+ {
+ OUString sURL;
+ Reference<XStorage> xStorage;
+ const PropertyValue* pIter = info.getConstArray();
+ const PropertyValue* pEnd = pIter + info.getLength();
+
+ for (;pIter != pEnd; ++pIter)
+ {
+ if ( pIter->Name == "Storage" )
+ {
+ xStorage.set(pIter->Value,UNO_QUERY);
+ }
+ else if ( pIter->Name == "URL" )
+ {
+ pIter->Value >>= sURL;
+ }
+ }
+
+ if ( !xStorage.is() || sURL.isEmpty() )
+ {
+ ::connectivity::SharedResources aResources;
+ const OUString sMessage = aResources.getResourceString(STR_NO_STORAGE);
+ ::dbtools::throwGenericSQLException(sMessage ,*this);
+ }
+
+ OUString sSystemPath;
+ osl_getSystemPathFromFileURL( sURL.pData, &sSystemPath.pData );
+ if ( sURL.isEmpty() || sSystemPath.isEmpty() )
+ {
+ ::connectivity::SharedResources aResources;
+ const OUString sMessage = aResources.getResourceString(STR_INVALID_FILE_URL);
+ ::dbtools::throwGenericSQLException(sMessage ,*this);
+ }
+
+ bool bIsNewDatabase = !xStorage->hasElements();
+
+ ::comphelper::NamedValueCollection aProperties;
+
+ // properties for accessing the embedded storage
+ OUString sKey = StorageContainer::registerStorage( xStorage, sSystemPath );
+ aProperties.put( "storage_key", sKey );
+ aProperties.put( "storage_class_name",
+ OUString( "com.sun.star.sdbcx.comp.hsqldb.StorageAccess" ) );
+ aProperties.put( "fileaccess_class_name",
+ OUString( "com.sun.star.sdbcx.comp.hsqldb.StorageFileAccess" ) );
+
+ // JDBC driver and driver's classpath
+ aProperties.put( "JavaDriverClass",
+ OUString( "org.hsqldb.jdbcDriver" ) );
+ aProperties.put( "JavaDriverClassPath",
+ OUString(
+#ifdef SYSTEM_HSQLDB
+ HSQLDB_JAR
+#else
+ "vnd.sun.star.expand:$LO_JAVA_DIR/hsqldb.jar"
+#endif
+ " vnd.sun.star.expand:$LO_JAVA_DIR/sdbc_hsqldb.jar"
+ ) );
+
+ // auto increment handling
+ aProperties.put( "IsAutoRetrievingEnabled", true );
+ aProperties.put( "AutoRetrievingStatement",
+ OUString( "CALL IDENTITY()" ) );
+ aProperties.put( "IgnoreDriverPrivileges", true );
+
+ // don't want to expose HSQLDB's schema capabilities which exist since 1.8.0RC10
+ aProperties.put( "default_schema",
+ OUString( "true" ) );
+
+ // security: permitted Java classes
+ NamedValue aPermittedClasses(
+ "hsqldb.method_class_names",
+ Any( lcl_getPermittedJavaMethods_nothrow( m_xContext ) )
+ );
+ aProperties.put( "SystemProperties", Sequence< NamedValue >( &aPermittedClasses, 1 ) );
+
+ OUString sMessage;
+ try
+ {
+ static constexpr OUString sProperties( u"properties"_ustr );
+ if ( !bIsNewDatabase && xStorage->isStreamElement(sProperties) )
+ {
+ Reference<XStream > xStream = xStorage->openStreamElement(sProperties,ElementModes::READ);
+ if ( xStream.is() )
+ {
+ std::unique_ptr<SvStream> pStream( ::utl::UcbStreamHelper::CreateStream(xStream) );
+ if (pStream)
+ {
+ OStringBuffer sLine;
+ OString sVersionString;
+ while ( pStream->ReadLine(sLine) )
+ {
+ if ( sLine.isEmpty() )
+ continue;
+ sal_Int32 nIdx {0};
+ const std::string_view sIniKey = o3tl::getToken(sLine, 0, '=', nIdx);
+ const OString sValue(o3tl::getToken(sLine, 0, '=', nIdx));
+ if( sIniKey == "hsqldb.compatible_version" )
+ {
+ sVersionString = sValue;
+ }
+ else
+ {
+ if (sIniKey == "version" && sVersionString.isEmpty())
+ {
+ sVersionString = sValue;
+ }
+ }
+ }
+ if (!sVersionString.isEmpty())
+ {
+ sal_Int32 nIdx {0};
+ const sal_Int32 nMajor = o3tl::toInt32(o3tl::getToken(sVersionString, 0, '.', nIdx));
+ const sal_Int32 nMinor = o3tl::toInt32(o3tl::getToken(sVersionString, 0, '.', nIdx));
+ const sal_Int32 nMicro = o3tl::toInt32(o3tl::getToken(sVersionString, 0, '.', nIdx));
+ if ( nMajor > 1
+ || ( nMajor == 1 && nMinor > 8 )
+ || ( nMajor == 1 && nMinor == 8 && nMicro > 0 ) )
+ {
+ ::connectivity::SharedResources aResources;
+ sMessage = aResources.getResourceString(STR_ERROR_NEW_VERSION);
+ }
+ }
+ }
+ } // if ( xStream.is() )
+ ::comphelper::disposeComponent(xStream);
+ }
+
+ // disallow any database/script files that contain a "SCRIPT[.*]" entry (this is belt and braces
+ // in that bundled hsqldb 1.8.0 is patched to also reject them)
+ //
+ // hsqldb 2.6.0 release notes have: added system role SCRIPT_OPS for export / import of database structure and data
+ // which seems to provide a builtin way to do this with contemporary hsqldb
+ static constexpr OUString sScript(u"script"_ustr);
+ if (!bIsNewDatabase && xStorage->isStreamElement(sScript))
+ {
+ Reference<XStream > xStream = xStorage->openStreamElement(sScript, ElementModes::READ);
+ if (xStream.is())
+ {
+ std::unique_ptr<SvStream> pStream(::utl::UcbStreamHelper::CreateStream(xStream));
+ if (pStream)
+ {
+ OStringBuffer sLine;
+ while (pStream->ReadLine(sLine))
+ {
+ OString sText = sLine.makeStringAndClear().trim();
+ if (sText.startsWithIgnoreAsciiCase("SCRIPT"))
+ {
+ ::connectivity::SharedResources aResources;
+ sMessage = aResources.getResourceString(STR_COULD_NOT_LOAD_FILE).replaceFirst("$filename$", sSystemPath);
+ break;
+ }
+ }
+ }
+ } // if ( xStream.is() )
+ ::comphelper::disposeComponent(xStream);
+ }
+
+ }
+ catch(Exception&)
+ {
+ }
+ if ( !sMessage.isEmpty() )
+ {
+ ::dbtools::throwGenericSQLException(sMessage ,*this);
+ }
+
+ // readonly?
+ Reference<XPropertySet> xProp(xStorage,UNO_QUERY);
+ if ( xProp.is() )
+ {
+ sal_Int32 nMode = 0;
+ xProp->getPropertyValue("OpenMode") >>= nMode;
+ if ( (nMode & ElementModes::WRITE) != ElementModes::WRITE )
+ {
+ aProperties.put( "readonly", OUString( "true" ) );
+ }
+ }
+
+ Sequence< PropertyValue > aConnectionArgs;
+ aProperties >>= aConnectionArgs;
+ OUString sConnectURL = "jdbc:hsqldb:" + sSystemPath;
+ Reference<XConnection> xOrig;
+ try
+ {
+ xOrig = xDriver->connect( sConnectURL, aConnectionArgs );
+ }
+ catch(const Exception&)
+ {
+ StorageContainer::revokeStorage(sKey,nullptr);
+ throw;
+ }
+
+ // if the storage is completely empty, then we just created a new HSQLDB
+ // In this case, do some initializations.
+ if ( bIsNewDatabase && xOrig.is() )
+ onConnectedNewDatabase( xOrig );
+
+ if ( xOrig.is() )
+ {
+ // now we have to set the URL to get the correct answer for metadata()->getURL()
+ auto pMetaConnection = comphelper::getFromUnoTunnel<OMetaConnection>(xOrig);
+ if ( pMetaConnection )
+ pMetaConnection->setURL(url);
+
+ Reference<XComponent> xComp(xOrig,UNO_QUERY);
+ if ( xComp.is() )
+ xComp->addEventListener(this);
+
+ // we want to close all connections when the office shuts down
+ static Reference< XTerminateListener> s_xTerminateListener = [&]()
+ {
+ Reference< XDesktop2 > xDesktop = Desktop::create( m_xContext );
+
+ rtl::Reference<OConnectionController> tmp = new OConnectionController(this);
+ xDesktop->addTerminateListener(tmp);
+ return tmp;
+ }();
+ Reference< XComponent> xIfc = new OHsqlConnection( this, xOrig, m_xContext );
+ xConnection.set(xIfc,UNO_QUERY);
+ m_aConnections.push_back(TWeakPair(WeakReferenceHelper(xOrig),TWeakConnectionPair(sKey,TWeakRefPair(WeakReferenceHelper(xConnection),WeakReferenceHelper()))));
+
+ Reference<XTransactionBroadcaster> xBroad(xStorage,UNO_QUERY);
+ if ( xBroad.is() )
+ {
+ xBroad->addTransactionListener(Reference<XTransactionListener>(this));
+ }
+ }
+ }
+ }
+ return xConnection;
+ }
+
+
+ sal_Bool SAL_CALL ODriverDelegator::acceptsURL( const OUString& url )
+ {
+ bool bEnabled = false;
+ javaFrameworkError e = jfw_getEnabled(&bEnabled);
+ switch (e) {
+ case JFW_E_NONE:
+ break;
+ case JFW_E_DIRECT_MODE:
+ SAL_INFO(
+ "connectivity.hsqldb",
+ "jfw_getEnabled: JFW_E_DIRECT_MODE, assuming true");
+ bEnabled = true;
+ break;
+ default:
+ SAL_WARN(
+ "connectivity.hsqldb", "jfw_getEnabled: error code " << +e);
+ break;
+ }
+ return bEnabled && url == "sdbc:embedded:hsqldb";
+ }
+
+
+ Sequence< DriverPropertyInfo > SAL_CALL ODriverDelegator::getPropertyInfo( const OUString& url, const Sequence< PropertyValue >& /*info*/ )
+ {
+ if ( !acceptsURL(url) )
+ return Sequence< DriverPropertyInfo >();
+ return
+ {
+ {
+ "Storage",
+ "Defines the storage where the database will be stored.",
+ true,
+ {},
+ {}
+ },
+ {
+ "URL",
+ "Defines the url of the data source.",
+ true,
+ {},
+ {}
+ },
+ {
+ "AutoRetrievingStatement",
+ "Defines the statement which will be executed to retrieve auto increment values.",
+ false,
+ "CALL IDENTITY()",
+ {}
+ }
+ };
+ }
+
+
+ sal_Int32 SAL_CALL ODriverDelegator::getMajorVersion( )
+ {
+ return 1;
+ }
+
+
+ sal_Int32 SAL_CALL ODriverDelegator::getMinorVersion( )
+ {
+ return 0;
+ }
+
+
+ Reference< XTablesSupplier > SAL_CALL ODriverDelegator::getDataDefinitionByConnection( const Reference< XConnection >& connection )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(ODriverDelegator_BASE::rBHelper.bDisposed);
+
+ Reference< XTablesSupplier > xTab;
+
+ TWeakPairVector::iterator i = std::find_if(m_aConnections.begin(), m_aConnections.end(),
+ [&connection](const TWeakPairVector::value_type& rConnection) {
+ return rConnection.second.second.first.get() == connection.get(); });
+ if (i != m_aConnections.end())
+ {
+ xTab.set(i->second.second.second,UNO_QUERY);
+ if ( !xTab.is() )
+ {
+ xTab = new OHCatalog(connection);
+ i->second.second.second = WeakReferenceHelper(xTab);
+ }
+ }
+
+ return xTab;
+ }
+
+
+ Reference< XTablesSupplier > SAL_CALL ODriverDelegator::getDataDefinitionByURL( const OUString& url, const Sequence< PropertyValue >& info )
+ {
+ if ( ! acceptsURL(url) )
+ {
+ ::connectivity::SharedResources aResources;
+ const OUString sMessage = aResources.getResourceString(STR_URI_SYNTAX_ERROR);
+ ::dbtools::throwGenericSQLException(sMessage ,*this);
+ }
+
+ return getDataDefinitionByConnection(connect(url,info));
+ }
+
+ // XServiceInfo
+
+ OUString SAL_CALL ODriverDelegator::getImplementationName( )
+ {
+ return IMPL_NAME;
+ }
+
+ sal_Bool SAL_CALL ODriverDelegator::supportsService( const OUString& _rServiceName )
+ {
+ return cppu::supportsService(this, _rServiceName);
+ }
+
+ Sequence< OUString > SAL_CALL ODriverDelegator::getSupportedServiceNames( )
+ {
+ return { "com.sun.star.sdbc.Driver", "com.sun.star.sdbcx.Driver" };
+ }
+
+ void SAL_CALL ODriverDelegator::createCatalog( const Sequence< PropertyValue >& /*info*/ )
+ {
+ ::dbtools::throwFeatureNotImplementedSQLException( "XCreateCatalog::createCatalog", *this );
+ }
+
+ void ODriverDelegator::shutdownConnection(const TWeakPairVector::iterator& _aIter )
+ {
+ OSL_ENSURE(m_aConnections.end() != _aIter,"Iterator equals .end()");
+ bool bLastOne = true;
+ try
+ {
+ Reference<XConnection> _xConnection(_aIter->first.get(),UNO_QUERY);
+
+ if ( _xConnection.is() )
+ {
+ Reference<XStatement> xStmt = _xConnection->createStatement();
+ if ( xStmt.is() )
+ {
+ Reference<XResultSet> xRes = xStmt->executeQuery("SELECT COUNT(*) FROM INFORMATION_SCHEMA.SYSTEM_SESSIONS WHERE USER_NAME ='SA'");
+ Reference<XRow> xRow(xRes,UNO_QUERY);
+ if ( xRow.is() && xRes->next() )
+ bLastOne = xRow->getInt(1) == 1;
+ if ( bLastOne )
+ xStmt->execute("SHUTDOWN");
+ }
+ }
+ }
+ catch(Exception&)
+ {
+ }
+ if ( bLastOne )
+ {
+ // Reference<XTransactionListener> xListener(*this,UNO_QUERY);
+ // a shutdown should commit all changes to the db files
+ StorageContainer::revokeStorage(_aIter->second.first,nullptr);
+ }
+ if ( !m_bInShutDownConnections )
+ m_aConnections.erase(_aIter);
+ }
+
+ void SAL_CALL ODriverDelegator::disposing( const css::lang::EventObject& Source )
+ {
+ ::osl::MutexGuard aGuard(m_aMutex);
+ Reference<XConnection> xCon(Source.Source,UNO_QUERY);
+ if ( xCon.is() )
+ {
+ TWeakPairVector::iterator i = std::find_if(m_aConnections.begin(), m_aConnections.end(),
+ [&xCon](const TWeakPairVector::value_type& rConnection) { return rConnection.first.get() == xCon.get(); });
+
+ if (i != m_aConnections.end())
+ shutdownConnection(i);
+ }
+ else
+ {
+ Reference< XStorage> xStorage(Source.Source,UNO_QUERY);
+ if ( xStorage.is() )
+ {
+ OUString sKey = StorageContainer::getRegisteredKey(xStorage);
+ TWeakPairVector::iterator i = std::find_if(m_aConnections.begin(),m_aConnections.end(),
+ [&sKey] (const TWeakPairVector::value_type& conn) {
+ return conn.second.first == sKey;
+ });
+
+ if ( i != m_aConnections.end() )
+ shutdownConnection(i);
+ }
+ }
+ }
+
+ void ODriverDelegator::shutdownConnections()
+ {
+ m_bInShutDownConnections = true;
+ for (const auto& rConnection : m_aConnections)
+ {
+ try
+ {
+ Reference<XConnection> xCon(rConnection.first,UNO_QUERY);
+ ::comphelper::disposeComponent(xCon);
+ }
+ catch(Exception&)
+ {
+ }
+ }
+ m_aConnections.clear();
+ m_bInShutDownConnections = true;
+ }
+
+ void ODriverDelegator::flushConnections()
+ {
+ for (const auto& rConnection : m_aConnections)
+ {
+ try
+ {
+ Reference<XFlushable> xCon(rConnection.second.second.first.get(),UNO_QUERY);
+ if (xCon.is())
+ xCon->flush();
+ }
+ catch(Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("connectivity.hsqldb");
+ }
+ }
+ }
+
+ void SAL_CALL ODriverDelegator::preCommit( const css::lang::EventObject& aEvent )
+ {
+ ::osl::MutexGuard aGuard(m_aMutex);
+
+ Reference< XStorage> xStorage(aEvent.Source,UNO_QUERY);
+ OUString sKey = StorageContainer::getRegisteredKey(xStorage);
+ if ( sKey.isEmpty() )
+ return;
+
+ TWeakPairVector::const_iterator i = std::find_if(m_aConnections.begin(), m_aConnections.end(),
+ [&sKey] (const TWeakPairVector::value_type& conn) {
+ return conn.second.first == sKey;
+ });
+
+ OSL_ENSURE( i != m_aConnections.end(), "ODriverDelegator::preCommit: they're committing a storage which I do not know!" );
+ if ( i == m_aConnections.end() )
+ return;
+
+ try
+ {
+ Reference<XConnection> xConnection(i->first,UNO_QUERY);
+ if ( xConnection.is() )
+ {
+ Reference< XStatement> xStmt = xConnection->createStatement();
+ OSL_ENSURE( xStmt.is(), "ODriverDelegator::preCommit: no statement!" );
+ if ( xStmt.is() )
+ xStmt->execute( "SET WRITE_DELAY 0" );
+
+ bool bPreviousAutoCommit = xConnection->getAutoCommit();
+ xConnection->setAutoCommit( false );
+ xConnection->commit();
+ xConnection->setAutoCommit( bPreviousAutoCommit );
+
+ if ( xStmt.is() )
+ xStmt->execute( "SET WRITE_DELAY 60" );
+ }
+ }
+ catch(Exception&)
+ {
+ TOOLS_WARN_EXCEPTION( "connectivity.hsqldb", "ODriverDelegator::preCommit" );
+ }
+ }
+
+ void SAL_CALL ODriverDelegator::commited( const css::lang::EventObject& /*aEvent*/ )
+ {
+ }
+
+ void SAL_CALL ODriverDelegator::preRevert( const css::lang::EventObject& /*aEvent*/ )
+ {
+ }
+
+ void SAL_CALL ODriverDelegator::reverted( const css::lang::EventObject& /*aEvent*/ )
+ {
+ }
+
+ namespace
+ {
+
+ const char* lcl_getCollationForLocale( const OUString& _rLocaleString, bool _bAcceptCountryMismatch = false )
+ {
+ static const char* pTranslations[] =
+ {
+ "af-ZA", "Afrikaans",
+ "am-ET", "Amharic",
+ "ar", "Arabic",
+ "as-IN", "Assamese",
+ "az-AZ", "Azerbaijani_Latin",
+ "az-cyrillic", "Azerbaijani_Cyrillic",
+ "be-BY", "Belarusian",
+ "bg-BG", "Bulgarian",
+ "bn-IN", "Bengali",
+ "bo-CN", "Tibetan",
+ "bs-BA", "Bosnian",
+ "ca-ES", "Catalan",
+ "cs-CZ", "Czech",
+ "cy-GB", "Welsh",
+ "da-DK", "Danish",
+ "de-DE", "German",
+ "el-GR", "Greek",
+ "en-US", "Latin1_General",
+ "es-ES", "Spanish",
+ "et-EE", "Estonian",
+ "eu", "Basque",
+ "fi-FI", "Finnish",
+ "fr-FR", "French",
+ "gn-PY", "Guarani",
+ "gu-IN", "Gujarati",
+ "ha-NG", "Hausa",
+ "he-IL", "Hebrew",
+ "hi-IN", "Hindi",
+ "hr-HR", "Croatian",
+ "hu-HU", "Hungarian",
+ "hy-AM", "Armenian",
+ "id-ID", "Indonesian",
+ "ig-NG", "Igbo",
+ "is-IS", "Icelandic",
+ "it-IT", "Italian",
+ "iu-CA", "Inuktitut",
+ "ja-JP", "Japanese",
+ "ka-GE", "Georgian",
+ "kk-KZ", "Kazakh",
+ "km-KH", "Khmer",
+ "kn-IN", "Kannada",
+ "ko-KR", "Korean",
+ "kok-IN", "Konkani",
+ "ks", "Kashmiri",
+ "ky-KG", "Kirghiz",
+ "lo-LA", "Lao",
+ "lt-LT", "Lithuanian",
+ "lv-LV", "Latvian",
+ "mi-NZ", "Maori",
+ "mk-MK", "Macedonian",
+ "ml-IN", "Malayalam",
+ "mn-MN", "Mongolian",
+ "mni-IN", "Manipuri",
+ "mr-IN", "Marathi",
+ "ms-MY", "Malay",
+ "mt-MT", "Maltese",
+ "my-MM", "Burmese",
+ "nb-NO", "Danish_Norwegian",
+ "ne-NP", "Nepali",
+ "nl-NL", "Dutch",
+ "nn-NO", "Norwegian",
+ "or-IN", "Odia",
+ "pa-IN", "Punjabi",
+ "pl-PL", "Polish",
+ "ps-AF", "Pashto",
+ "pt-PT", "Portuguese",
+ "ro-RO", "Romanian",
+ "ru-RU", "Russian",
+ "sa-IN", "Sanskrit",
+ "sd-IN", "Sindhi",
+ "sk-SK", "Slovak",
+ "sl-SI", "Slovenian",
+ "so-SO", "Somali",
+ "sq-AL", "Albanian",
+ "sr-YU", "Serbian_Cyrillic",
+ "sv-SE", "Swedish",
+ "sw-KE", "Swahili",
+ "ta-IN", "Tamil",
+ "te-IN", "Telugu",
+ "tg-TJ", "Tajik",
+ "th-TH", "Thai",
+ "tk-TM", "Turkmen",
+ "tn-BW", "Tswana",
+ "tr-TR", "Turkish",
+ "tt-RU", "Tatar",
+ "uk-UA", "Ukrainian",
+ "ur-PK", "Urdu",
+ "uz-UZ", "Uzbek_Latin",
+ "ven-ZA", "Venda",
+ "vi-VN", "Vietnamese",
+ "yo-NG", "Yoruba",
+ "zh-CN", "Chinese",
+ "zu-ZA", "Zulu",
+ nullptr, nullptr
+ };
+
+ OUString sLocaleString( _rLocaleString );
+ char nCompareTermination = 0;
+
+ if ( _bAcceptCountryMismatch )
+ {
+ // strip the country part from the compare string
+ sal_Int32 nCountrySep = sLocaleString.indexOf( '-' );
+ if ( nCountrySep > -1 )
+ sLocaleString = sLocaleString.copy( 0, nCountrySep );
+
+ // the entries in the translation table are compared until the
+ // - character only, not until the terminating 0
+ nCompareTermination = '-';
+ }
+
+ const char** pLookup = pTranslations;
+ for ( ; *pLookup; pLookup +=2 )
+ {
+ sal_Int32 nCompareUntil = 0;
+ while ( (*pLookup)[ nCompareUntil ] != nCompareTermination && (*pLookup)[ nCompareUntil ] != 0 )
+ ++nCompareUntil;
+
+ if ( sLocaleString.equalsAsciiL( *pLookup, nCompareUntil ) )
+ return *( pLookup + 1 );
+ }
+
+ if ( !_bAcceptCountryMismatch )
+ // second round, this time without matching the country
+ return lcl_getCollationForLocale( _rLocaleString, true );
+
+ OSL_FAIL( "lcl_getCollationForLocale: unknown locale string, falling back to Latin1_General!" );
+ return "Latin1_General";
+ }
+
+
+ OUString lcl_getSystemLocale( const Reference< XComponentContext >& _rxContext )
+ {
+ OUString sLocaleString = "en-US";
+ try
+ {
+
+ Reference< XMultiServiceFactory > xConfigProvider(
+ css::configuration::theDefaultProvider::get( _rxContext ) );
+
+
+ // arguments for creating the config access
+ Sequence<Any> aArguments(comphelper::InitAnyPropertySequence(
+ {
+ {"nodepath", Any(OUString("/org.openoffice.Setup/L10N" ))}, // the path to the node to open
+ {"depth", Any(sal_Int32(-1))}, // the depth: -1 means unlimited
+ }));
+ // create the access
+ Reference< XPropertySet > xNode(
+ xConfigProvider->createInstanceWithArguments(
+ "com.sun.star.configuration.ConfigurationAccess",
+ aArguments ),
+ UNO_QUERY );
+ OSL_ENSURE( xNode.is(), "lcl_getSystemLocale: invalid access returned (should throw an exception instead)!" );
+
+
+ // ask for the system locale setting
+ if ( xNode.is() )
+ xNode->getPropertyValue("ooSetupSystemLocale") >>= sLocaleString;
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "connectivity.hsqldb", "lcl_getSystemLocale" );
+ }
+ if ( sLocaleString.isEmpty() )
+ {
+ rtl_Locale* pProcessLocale = nullptr;
+ osl_getProcessLocale( &pProcessLocale );
+ sLocaleString = LanguageTag( *pProcessLocale).getBcp47();
+ }
+ return sLocaleString;
+ }
+ }
+
+ void ODriverDelegator::onConnectedNewDatabase( const Reference< XConnection >& _rxConnection )
+ {
+ try
+ {
+ Reference< XStatement > xStatement = _rxConnection->createStatement();
+ OSL_ENSURE( xStatement.is(), "ODriverDelegator::onConnectedNewDatabase: could not create a statement!" );
+ if ( xStatement.is() )
+ {
+ OUStringBuffer aStatement( "SET DATABASE COLLATION \"" );
+ aStatement.appendAscii( lcl_getCollationForLocale( lcl_getSystemLocale( m_xContext ) ) );
+ aStatement.append( "\"" );
+
+ xStatement->execute( aStatement.makeStringAndClear() );
+ }
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "connectivity.hsqldb", "ODriverDelegator::onConnectedNewDatabase" );
+ }
+ }
+
+
+} // namespace connectivity
+
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+connectivity_hsqldb_ODriverDelegator_implementation(
+ css::uno::XComponentContext* context , css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new connectivity::ODriverDelegator(context));
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/hsqldb/HStorageAccess.cxx b/connectivity/source/drivers/hsqldb/HStorageAccess.cxx
new file mode 100644
index 0000000000..3d48fd44a2
--- /dev/null
+++ b/connectivity/source/drivers/hsqldb/HStorageAccess.cxx
@@ -0,0 +1,516 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <hsqldb/HStorageAccess.hxx>
+#include <com/sun/star/embed/XStorage.hpp>
+#include <hsqldb/HStorageMap.hxx>
+#include "accesslog.hxx"
+#include <osl/diagnose.h>
+#include <comphelper/diagnose_ex.hxx>
+
+#include <string.h>
+
+#include <algorithm>
+
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::embed;
+using namespace ::com::sun::star::io;
+using namespace ::com::sun::star::lang;
+using namespace ::connectivity::hsqldb;
+
+#define ThrowException(env, type, msg) { \
+ env->ThrowNew(env->FindClass(type), msg); }
+
+/*
+ * Class: com_sun_star_sdbcx_comp_hsqldb_NativeStorageAccess
+ * Method: openStream
+ * Signature: (Ljava/lang/String;Ljava/lang/String;I)V
+ */
+extern "C" SAL_JNI_EXPORT void JNICALL Java_com_sun_star_sdbcx_comp_hsqldb_NativeStorageAccess_openStream
+ (JNIEnv * env, jobject /*obj_this*/,jstring name, jstring key, jint mode)
+{
+#ifdef HSQLDB_DBG
+ {
+ OperationLogFile( env, name, "data" ).logOperation( "openStream" );
+ LogFile( env, name, "data" ).create();
+ }
+#endif
+
+ StorageContainer::registerStream(env,name,key,mode);
+}
+
+/*
+ * Class: com_sun_star_sdbcx_comp_hsqldb_NativeStorageAccess
+ * Method: close
+ * Signature: (Ljava/lang/String;Ljava/lang/String;)V
+ */
+extern "C" SAL_JNI_EXPORT void JNICALL Java_com_sun_star_sdbcx_comp_hsqldb_NativeStorageAccess_close
+ (JNIEnv * env, jobject /*obj_this*/,jstring name, jstring key)
+{
+#ifdef HSQLDB_DBG
+ {
+ OUString sKey = StorageContainer::jstring2ustring(env,key);
+ OUString sName = StorageContainer::jstring2ustring(env,name);
+ }
+#endif
+ std::shared_ptr<StreamHelper> pHelper = StorageContainer::getRegisteredStream(env,name,key);
+ Reference< XOutputStream> xFlush = pHelper ? pHelper->getOutputStream() : Reference< XOutputStream>();
+ if ( xFlush.is() )
+ try
+ {
+ xFlush->flush();
+ }
+ catch(const Exception&)
+ {
+ TOOLS_WARN_EXCEPTION( "connectivity.hsqldb", "NativeStorageAccess::close: caught an exception while flushing!" );
+ }
+#ifdef HSQLDB_DBG
+ {
+ OperationLogFile aOpLog( env, name, "data" );
+ aOpLog.logOperation( "close" );
+ aOpLog.close();
+
+ LogFile aDataLog( env, name, "data" );
+ aDataLog.close();
+ }
+#endif
+
+ StorageContainer::revokeStream(env,name,key);
+}
+
+/*
+ * Class: com_sun_star_sdbcx_comp_hsqldb_NativeStorageAccess
+ * Method: getFilePointer
+ * Signature: (Ljava/lang/String;Ljava/lang/String;)J
+ */
+extern "C" SAL_JNI_EXPORT jlong JNICALL Java_com_sun_star_sdbcx_comp_hsqldb_NativeStorageAccess_getFilePointer
+ (JNIEnv * env, jobject /*obj_this*/,jstring name, jstring key)
+{
+#ifdef HSQLDB_DBG
+ OperationLogFile aOpLog( env, name, "data" );
+ aOpLog.logOperation( "getFilePointer" );
+#endif
+
+ std::shared_ptr<StreamHelper> pHelper = StorageContainer::getRegisteredStream(env,name,key);
+ OSL_ENSURE(pHelper,"No stream helper!");
+
+ jlong nReturn = pHelper ? pHelper->getSeek()->getPosition() : jlong(0);
+#ifdef HSQLDB_DBG
+ aOpLog.logReturn( nReturn );
+#endif
+ return nReturn;
+}
+
+
+/*
+ * Class: com_sun_star_sdbcx_comp_hsqldb_NativeStorageAccess
+ * Method: length
+ * Signature: (Ljava/lang/String;Ljava/lang/String;)J
+ */
+extern "C" SAL_JNI_EXPORT jlong JNICALL Java_com_sun_star_sdbcx_comp_hsqldb_NativeStorageAccess_length
+ (JNIEnv * env, jobject /*obj_this*/,jstring name, jstring key)
+{
+#ifdef HSQLDB_DBG
+ OperationLogFile aOpLog( env, name, "data" );
+ aOpLog.logOperation( "length" );
+#endif
+
+ std::shared_ptr<StreamHelper> pHelper = StorageContainer::getRegisteredStream(env,name,key);
+ OSL_ENSURE(pHelper,"No stream helper!");
+
+ jlong nReturn = pHelper ? pHelper->getSeek()->getLength() :jlong(0);
+#ifdef HSQLDB_DBG
+ aOpLog.logReturn( nReturn );
+#endif
+ return nReturn;
+}
+
+
+jint read_from_storage_stream( JNIEnv * env, jstring name, jstring key )
+{
+ std::shared_ptr<StreamHelper> pHelper = StorageContainer::getRegisteredStream(env,name,key);
+ Reference< XInputStream> xIn = pHelper ? pHelper->getInputStream() : Reference< XInputStream>();
+ OSL_ENSURE(xIn.is(),"Input stream is NULL!");
+ if ( !xIn.is() )
+ return -1;
+
+ Sequence< ::sal_Int8 > aData(1);
+ sal_Int32 nBytesRead = -1;
+ try
+ {
+ nBytesRead = xIn->readBytes(aData,1);
+ }
+ catch(const Exception& e)
+ {
+ StorageContainer::throwJavaException(e,env);
+ return -1;
+
+ }
+ if (nBytesRead <= 0)
+ {
+ return -1;
+ }
+ else
+ {
+ return static_cast<unsigned char>(aData[0]);
+ }
+ return -1;
+}
+
+
+/*
+ * Class: com_sun_star_sdbcx_comp_hsqldb_NativeStorageAccess
+ * Method: read
+ * Signature: (Ljava/lang/String;Ljava/lang/String;)I
+ */
+extern "C" SAL_JNI_EXPORT jint JNICALL Java_com_sun_star_sdbcx_comp_hsqldb_NativeStorageAccess_read__Ljava_lang_String_2Ljava_lang_String_2
+ (JNIEnv* env, jobject /*obj_this*/, jstring name, jstring key)
+{
+#ifdef HSQLDB_DBG
+ OperationLogFile aOpLog( env, name, "data" );
+ aOpLog.logOperation( "read" );
+
+ DataLogFile aDataLog( env, name, "data" );
+ return read_from_storage_stream( env, obj_this, name, key, &aDataLog );
+#else
+ return read_from_storage_stream( env, name, key );
+#endif
+}
+
+
+jint read_from_storage_stream_into_buffer( JNIEnv * env, jstring name, jstring key, jbyteArray buffer, jint off, jint len )
+{
+#ifdef HSQLDB_DBG
+ {
+ OUString sKey = StorageContainer::jstring2ustring(env,key);
+ OUString sName = StorageContainer::jstring2ustring(env,name);
+ }
+#endif
+ std::shared_ptr<StreamHelper> pHelper = StorageContainer::getRegisteredStream(env,name,key);
+ Reference< XInputStream> xIn = pHelper ? pHelper->getInputStream() : Reference< XInputStream>();
+ OSL_ENSURE(xIn.is(),"Input stream is NULL!");
+ if ( xIn.is() )
+ {
+ jsize nLen = env->GetArrayLength(buffer);
+ if ( nLen < len || len <= 0 )
+ {
+ ThrowException( env,
+ "java/io/IOException",
+ "len is greater or equal to the buffer size");
+ return -1;
+ }
+ sal_Int32 nBytesRead = -1;
+
+ Sequence< ::sal_Int8 > aData(nLen);
+ try
+ {
+ nBytesRead = xIn->readBytes(aData, len);
+ }
+ catch(const Exception& e)
+ {
+ StorageContainer::throwJavaException(e,env);
+ return -1;
+ }
+
+ if (nBytesRead <= 0)
+ return -1;
+ env->SetByteArrayRegion(buffer,off,nBytesRead,reinterpret_cast<const jbyte*>(&aData[0]));
+
+ return nBytesRead;
+ }
+ ThrowException( env,
+ "java/io/IOException",
+ "Stream is not valid");
+ return -1;
+}
+
+
+/*
+ * Class: com_sun_star_sdbcx_comp_hsqldb_NativeStorageAccess
+ * Method: read
+ * Signature: (Ljava/lang/String;Ljava/lang/String;[BII)I
+ */
+extern "C" SAL_JNI_EXPORT jint JNICALL Java_com_sun_star_sdbcx_comp_hsqldb_NativeStorageAccess_read__Ljava_lang_String_2Ljava_lang_String_2_3BII
+ (JNIEnv * env, jobject obj_this,jstring name, jstring key, jbyteArray buffer, jint off, jint len)
+{
+#ifdef HSQLDB_DBG
+ OperationLogFile aOpLog( env, name, "data" );
+ aOpLog.logOperation( "read( byte[], int, int )" );
+
+ DataLogFile aDataLog( env, name, "data" );
+ return read_from_storage_stream_into_buffer( env, obj_this, name, key, buffer, off, len, &aDataLog );
+#else
+ (void)obj_this;
+ return read_from_storage_stream_into_buffer( env, name, key, buffer, off, len );
+#endif
+}
+
+
+/*
+ * Class: com_sun_star_sdbcx_comp_hsqldb_NativeStorageAccess
+ * Method: readInt
+ * Signature: (Ljava/lang/String;Ljava/lang/String;)I
+ */
+extern "C" SAL_JNI_EXPORT jint JNICALL Java_com_sun_star_sdbcx_comp_hsqldb_NativeStorageAccess_readInt
+ (JNIEnv * env, jobject /*obj_this*/,jstring name, jstring key)
+{
+#ifdef HSQLDB_DBG
+ OperationLogFile aOpLog( env, name, "data" );
+ aOpLog.logOperation( "readInt" );
+#endif
+
+ std::shared_ptr<StreamHelper> pHelper = StorageContainer::getRegisteredStream(env,name,key);
+ Reference< XInputStream> xIn = pHelper ? pHelper->getInputStream() : Reference< XInputStream>();
+ OSL_ENSURE(xIn.is(),"Input stream is NULL!");
+ if ( xIn.is() )
+ {
+ Sequence< ::sal_Int8 > aData(4);
+ sal_Int32 nBytesRead = -1;
+ try
+ {
+ nBytesRead = xIn->readBytes(aData, 4);
+ }
+ catch(const Exception& e)
+ {
+ StorageContainer::throwJavaException(e,env);
+ return -1;
+ }
+
+ if ( nBytesRead != 4 ) {
+ ThrowException( env,
+ "java/io/IOException",
+ "Bytes read != 4");
+ return -1;
+ }
+
+ Sequence< sal_Int32 > ch(4);
+ std::transform(aData.begin(), aData.end(), ch.getArray(),
+ [](auto c) { return static_cast<unsigned char>(c); });
+
+ if ((ch[0] | ch[1] | ch[2] | ch[3]) < 0)
+ {
+ ThrowException( env,
+ "java/io/IOException",
+ "One byte is < 0");
+ return -1;
+ }
+ jint nRet = (ch[0] << 24) + (ch[1] << 16) + (ch[2] << 8) + (ch[3] << 0);
+#ifdef HSQLDB_DBG
+ DataLogFile aDataLog( env, name, "data" );
+ aDataLog.write( nRet );
+
+ aOpLog.logReturn( nRet );
+#endif
+ return nRet;
+ }
+ ThrowException( env,
+ "java/io/IOException",
+ "No InputStream");
+ return -1;
+}
+
+
+/*
+ * Class: com_sun_star_sdbcx_comp_hsqldb_NativeStorageAccess
+ * Method: seek
+ * Signature: (Ljava/lang/String;Ljava/lang/String;J)V
+ */
+extern "C" SAL_JNI_EXPORT void JNICALL Java_com_sun_star_sdbcx_comp_hsqldb_NativeStorageAccess_seek
+ (JNIEnv * env, jobject /*obj_this*/,jstring name, jstring key, jlong position)
+{
+#ifdef HSQLDB_DBG
+ OperationLogFile aOpLog( env, name, "data" );
+ aOpLog.logOperation( "seek", position );
+#endif
+
+ std::shared_ptr<StreamHelper> pHelper = StorageContainer::getRegisteredStream(env,name,key);
+
+ OSL_ENSURE(pHelper, "No StreamHelper!");
+ if (!pHelper)
+ return;
+
+ Reference< XSeekable> xSeek = pHelper->getSeek();
+
+ OSL_ENSURE(xSeek.is(), "No Seekable stream!");
+ if (!xSeek)
+ return;
+
+#ifdef HSQLDB_DBG
+ DataLogFile aDataLog( env, name, "data" );
+#endif
+
+ ::sal_Int64 nLen = xSeek->getLength();
+ if ( nLen < position)
+ {
+ static const ::sal_Int64 BUFFER_SIZE = 9192;
+ #ifdef HSQLDB_DBG
+ aDataLog.seek( nLen );
+ #endif
+ xSeek->seek(nLen);
+ Reference< XOutputStream> xOut = pHelper->getOutputStream();
+ OSL_ENSURE(xOut.is(),"No output stream!");
+
+ ::sal_Int64 diff = position - nLen;
+ sal_Int32 n;
+ while( diff != 0 )
+ {
+ if ( BUFFER_SIZE < diff )
+ {
+ n = static_cast<sal_Int32>(BUFFER_SIZE);
+ diff = diff - BUFFER_SIZE;
+ }
+ else
+ {
+ n = static_cast<sal_Int32>(diff);
+ diff = 0;
+ }
+ Sequence< ::sal_Int8 > aData(n);
+ memset(aData.getArray(),0,n);
+ xOut->writeBytes(aData);
+ #ifdef HSQLDB_DBG
+ aDataLog.write( aData.getConstArray(), n );
+ #endif
+ }
+ }
+ xSeek->seek(position);
+ OSL_ENSURE(xSeek->getPosition() == position,"Wrong position after seeking the stream");
+
+#ifdef HSQLDB_DBG
+ aDataLog.seek( position );
+ OSL_ENSURE( xSeek->getPosition() == aDataLog.tell(), "Wrong position after seeking the stream" );
+#endif
+}
+
+
+void write_to_storage_stream_from_buffer( JNIEnv* env, jstring name, jstring key, jbyteArray buffer, jint off, jint len )
+{
+ std::shared_ptr<StreamHelper> pHelper = StorageContainer::getRegisteredStream(env,name,key);
+ Reference< XOutputStream> xOut = pHelper ? pHelper->getOutputStream() : Reference< XOutputStream>();
+ OSL_ENSURE(xOut.is(),"Stream is NULL");
+
+ try
+ {
+ if ( xOut.is() )
+ {
+ jbyte *buf = env->GetByteArrayElements(buffer,nullptr);
+ if (env->ExceptionCheck())
+ {
+ env->ExceptionClear();
+ OSL_FAIL("ExceptionClear");
+ }
+ OSL_ENSURE(buf,"buf is NULL");
+ if ( buf && len > 0 && len <= env->GetArrayLength(buffer))
+ {
+ Sequence< ::sal_Int8 > aData(reinterpret_cast<sal_Int8 *>(buf + off),len);
+ env->ReleaseByteArrayElements(buffer, buf, JNI_ABORT);
+ xOut->writeBytes(aData);
+ }
+ }
+ else
+ {
+ ThrowException( env,
+ "java/io/IOException",
+ "No OutputStream");
+ }
+ }
+ catch(const Exception& e)
+ {
+ TOOLS_WARN_EXCEPTION( "connectivity.hsqldb", "Exception caught! : write [BII)V");
+ StorageContainer::throwJavaException(e,env);
+ }
+}
+
+
+/*
+ * Class: com_sun_star_sdbcx_comp_hsqldb_NativeStorageAccess
+ * Method: write
+ * Signature: (Ljava/lang/String;Ljava/lang/String;[BII)V
+ */
+extern "C" SAL_JNI_EXPORT void JNICALL Java_com_sun_star_sdbcx_comp_hsqldb_NativeStorageAccess_write
+ (JNIEnv * env, jobject obj_this,jstring name, jstring key, jbyteArray buffer, jint off, jint len)
+{
+#ifdef HSQLDB_DBG
+ OperationLogFile aOpLog( env, name, "data" );
+ aOpLog.logOperation( "write( byte[], int, int )" );
+
+ DataLogFile aDataLog( env, name, "data" );
+ write_to_storage_stream_from_buffer( env, obj_this, name, key, buffer, off, len, &aDataLog );
+#else
+ (void)obj_this;
+ write_to_storage_stream_from_buffer( env, name, key, buffer, off, len );
+#endif
+}
+
+
+void write_to_storage_stream( JNIEnv* env, jstring name, jstring key, jint v )
+{
+ std::shared_ptr<StreamHelper> pHelper = StorageContainer::getRegisteredStream(env,name,key);
+ Reference< XOutputStream> xOut = pHelper ? pHelper->getOutputStream() : Reference< XOutputStream>();
+ OSL_ENSURE(xOut.is(),"Stream is NULL");
+ try
+ {
+ if ( xOut.is() )
+ {
+ Sequence< ::sal_Int8 > oneByte
+ {
+ static_cast<sal_Int8>((v >> 24) & 0xFF),
+ static_cast<sal_Int8>((v >> 16) & 0xFF),
+ static_cast<sal_Int8>((v >> 8) & 0xFF),
+ static_cast<sal_Int8>((v >> 0) & 0xFF)
+ };
+
+ xOut->writeBytes(oneByte);
+ }
+ else
+ {
+ ThrowException( env,
+ "java/io/IOException",
+ "No OutputStream");
+ }
+ }
+ catch(const Exception& e)
+ {
+ TOOLS_WARN_EXCEPTION( "connectivity.hsqldb", "writeBytes(aData);");
+ StorageContainer::throwJavaException(e,env);
+ }
+}
+
+
+/*
+ * Class: com_sun_star_sdbcx_comp_hsqldb_NativeStorageAccess
+ * Method: writeInt
+ * Signature: (Ljava/lang/String;Ljava/lang/String;I)V
+ */
+extern "C" SAL_JNI_EXPORT void JNICALL Java_com_sun_star_sdbcx_comp_hsqldb_NativeStorageAccess_writeInt
+ (JNIEnv * env, jobject obj_this,jstring name, jstring key, jint v)
+{
+#ifdef HSQLDB_DBG
+ OperationLogFile aOpLog( env, name, "data" );
+ aOpLog.logOperation( "writeInt" );
+
+ DataLogFile aDataLog( env, name, "data" );
+ write_to_storage_stream( env, name, key, v, &aDataLog );
+#else
+ (void)obj_this;
+ write_to_storage_stream( env, name, key, v );
+#endif
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/hsqldb/HStorageMap.cxx b/connectivity/source/drivers/hsqldb/HStorageMap.cxx
new file mode 100644
index 0000000000..01a9c3d34b
--- /dev/null
+++ b/connectivity/source/drivers/hsqldb/HStorageMap.cxx
@@ -0,0 +1,361 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <hsqldb/HStorageMap.hxx>
+#include <comphelper/types.hxx>
+#include <com/sun/star/embed/XTransactionBroadcaster.hpp>
+#include <com/sun/star/embed/XTransactedObject.hpp>
+#include <com/sun/star/embed/ElementModes.hpp>
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <osl/diagnose.h>
+#include <sal/log.hxx>
+#include <uno/mapping.hxx>
+#include <algorithm>
+#include <comphelper/diagnose_ex.hxx>
+
+namespace connectivity::hsqldb
+{
+
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::embed;
+ using namespace ::com::sun::star::io;
+
+ StreamHelper::StreamHelper(const Reference< XStream>& _xStream)
+ : m_xStream(_xStream)
+ {
+ }
+
+ StreamHelper::~StreamHelper()
+ {
+ try
+ {
+ m_xStream.clear();
+ m_xSeek.clear();
+ if ( m_xInputStream.is() )
+ {
+ m_xInputStream->closeInput();
+ m_xInputStream.clear();
+ }
+ // this is done implicitly by the closing of the input stream
+ else if ( m_xOutputStream.is() )
+ {
+ m_xOutputStream->closeOutput();
+ try
+ {
+ ::comphelper::disposeComponent(m_xOutputStream);
+ }
+ catch(const DisposedException&)
+ {
+ }
+ catch(const Exception&)
+ {
+ OSL_FAIL("Could not dispose OutputStream");
+ }
+ m_xOutputStream.clear();
+ }
+ }
+ catch(const Exception&)
+ {
+ TOOLS_WARN_EXCEPTION( "connectivity.hsqldb", "");
+ }
+ }
+
+ Reference< XInputStream> const & StreamHelper::getInputStream()
+ {
+ if ( !m_xInputStream.is() )
+ m_xInputStream = m_xStream->getInputStream();
+ return m_xInputStream;
+ }
+
+ Reference< XOutputStream> const & StreamHelper::getOutputStream()
+ {
+ if ( !m_xOutputStream.is() )
+ m_xOutputStream = m_xStream->getOutputStream();
+ return m_xOutputStream;
+ }
+
+ Reference< XSeekable> const & StreamHelper::getSeek()
+ {
+ if ( !m_xSeek.is() )
+ m_xSeek.set(m_xStream,UNO_QUERY);
+ return m_xSeek;
+ }
+
+ css::uno::Reference<css::embed::XStorage> StorageData::mapStorage()
+ const
+ {
+ css::uno::Environment env(css::uno::Environment::getCurrent());
+ if (!(env.is() && storageEnvironment.is())) {
+ throw css::uno::RuntimeException("cannot get environments");
+ }
+ if (env.get() == storageEnvironment.get()) {
+ return storage;
+ } else {
+ css::uno::Mapping map(storageEnvironment, env);
+ if (!map.is()) {
+ throw css::uno::RuntimeException("cannot get mapping");
+ }
+ css::uno::Reference<css::embed::XStorage> mapped;
+ map.mapInterface(
+ reinterpret_cast<void **>(&mapped), storage.get(),
+ cppu::UnoType<css::embed::XStorage>::get());
+ return mapped;
+ }
+ }
+
+ static TStorages& lcl_getStorageMap()
+ {
+ static TStorages s_aMap;
+ return s_aMap;
+ }
+
+ static OUString lcl_getNextCount()
+ {
+ static sal_Int32 s_nCount = 0;
+ return OUString::number(s_nCount++);
+ }
+
+ OUString StorageContainer::removeURLPrefix(std::u16string_view _sURL, std::u16string_view _sFileURL)
+ {
+ return OUString(_sURL.substr(_sFileURL.size()+1));
+ }
+
+ OUString StorageContainer::removeOldURLPrefix(const OUString& _sURL)
+ {
+ OUString sRet = _sURL;
+#if defined(_WIN32)
+ sal_Int32 nIndex = sRet.lastIndexOf('\\');
+#else
+ sal_Int32 nIndex = sRet.lastIndexOf('/');
+#endif
+ if ( nIndex != -1 )
+ {
+ sRet = _sURL.copy(nIndex+1);
+ }
+ return sRet;
+
+ }
+ /*****************************************************************************/
+ /* convert jstring to rtl_uString */
+
+ OUString StorageContainer::jstring2ustring(JNIEnv * env, jstring jstr)
+ {
+ if (env->ExceptionCheck())
+ {
+ env->ExceptionClear();
+ OSL_FAIL("ExceptionClear");
+ }
+ OUString aStr;
+ if ( jstr )
+ {
+ jboolean bCopy(true);
+ const jchar* pChar = env->GetStringChars(jstr,&bCopy);
+ jsize len = env->GetStringLength(jstr);
+ aStr = OUString(
+ reinterpret_cast<sal_Unicode const *>(pChar), len);
+
+ if(bCopy)
+ env->ReleaseStringChars(jstr,pChar);
+ }
+
+ if (env->ExceptionCheck())
+ {
+ env->ExceptionClear();
+ OSL_FAIL("ExceptionClear");
+ }
+ return aStr;
+ }
+
+
+ OUString StorageContainer::registerStorage(const Reference< XStorage>& _xStorage,const OUString& _sURL)
+ {
+ OSL_ENSURE(_xStorage.is(),"Storage is NULL!");
+ TStorages& rMap = lcl_getStorageMap();
+ // check if the storage is already in our map
+ TStorages::const_iterator aFind = std::find_if(rMap.begin(),rMap.end(),
+ [&_xStorage] (const TStorages::value_type& storage) {
+ return storage.second.mapStorage() == _xStorage;
+ });
+
+ if ( aFind == rMap.end() )
+ {
+ aFind = rMap.insert(TStorages::value_type(lcl_getNextCount(), {_xStorage, css::uno::Environment::getCurrent(), _sURL, TStreamMap()})).first;
+ }
+
+ return aFind->first;
+ }
+
+ TStorages::mapped_type StorageContainer::getRegisteredStorage(const OUString& _sKey)
+ {
+ TStorages::mapped_type aRet;
+ TStorages& rMap = lcl_getStorageMap();
+ TStorages::const_iterator aFind = rMap.find(_sKey);
+ OSL_ENSURE(aFind != rMap.end(),"Storage could not be found in list!");
+ if ( aFind != rMap.end() )
+ aRet = aFind->second;
+
+ return aRet;
+ }
+
+ OUString StorageContainer::getRegisteredKey(const Reference< XStorage>& _xStorage)
+ {
+ OUString sKey;
+ OSL_ENSURE(_xStorage.is(),"Storage is NULL!");
+ TStorages& rMap = lcl_getStorageMap();
+ // check if the storage is already in our map
+ TStorages::const_iterator aFind = std::find_if(rMap.begin(),rMap.end(),
+ [&_xStorage] (const TStorages::value_type& storage) {
+ return storage.second.mapStorage() == _xStorage;
+ });
+
+ if ( aFind != rMap.end() )
+ sKey = aFind->first;
+ return sKey;
+ }
+
+ void StorageContainer::revokeStorage(const OUString& _sKey,const Reference<XTransactionListener>& _xListener)
+ {
+ TStorages& rMap = lcl_getStorageMap();
+ TStorages::iterator aFind = rMap.find(_sKey);
+ if ( aFind == rMap.end() )
+ return;
+
+ try
+ {
+ if ( _xListener.is() )
+ {
+ Reference<XTransactionBroadcaster> xBroad(aFind->second.mapStorage(),UNO_QUERY);
+ if ( xBroad.is() )
+ xBroad->removeTransactionListener(_xListener);
+ Reference<XTransactedObject> xTrans(aFind->second.mapStorage(),UNO_QUERY);
+ if ( xTrans.is() )
+ xTrans->commit();
+ }
+ }
+ catch(const Exception&)
+ {
+ }
+ rMap.erase(aFind);
+ }
+
+ TStreamMap::mapped_type StorageContainer::registerStream(JNIEnv * env,jstring name, jstring key,sal_Int32 _nMode)
+ {
+ TStreamMap::mapped_type pHelper;
+ TStorages& rMap = lcl_getStorageMap();
+ OUString sKey = jstring2ustring(env,key);
+ TStorages::iterator aFind = rMap.find(sKey);
+ OSL_ENSURE(aFind != rMap.end(),"Storage could not be found in list!");
+ if ( aFind != rMap.end() )
+ {
+ TStorages::mapped_type aStoragePair = StorageContainer::getRegisteredStorage(sKey);
+ auto storage = aStoragePair.mapStorage();
+ OSL_ENSURE(storage.is(),"No Storage available!");
+ if ( storage.is() )
+ {
+ OUString sOrgName = StorageContainer::jstring2ustring(env,name);
+ OUString sName = removeURLPrefix(sOrgName,aStoragePair.url);
+ TStreamMap::iterator aStreamFind = aFind->second.streams.find(sName);
+ OSL_ENSURE( aStreamFind == aFind->second.streams.end(),"A Stream was already registered for this object!");
+ if ( aStreamFind != aFind->second.streams.end() )
+ {
+ pHelper = aStreamFind->second;
+ }
+ else
+ {
+ try
+ {
+ try
+ {
+ pHelper = std::make_shared<StreamHelper>(storage->openStreamElement(sName,_nMode));
+ }
+ catch(const Exception&)
+ {
+ OUString sStrippedName = removeOldURLPrefix(sOrgName);
+
+ if ( (_nMode & ElementModes::WRITE) != ElementModes::WRITE )
+ {
+ bool bIsStream = true;
+ try
+ {
+ bIsStream = storage->isStreamElement(sStrippedName);
+ }
+ catch(const Exception&)
+ {
+ bIsStream = false;
+ }
+ if ( !bIsStream )
+ return pHelper; // readonly file without data stream
+ }
+ pHelper = std::make_shared<StreamHelper>(storage->openStreamElement( sStrippedName, _nMode ) );
+ }
+ aFind->second.streams.emplace(sName,pHelper);
+ }
+ catch(const Exception& e)
+ {
+ TOOLS_WARN_EXCEPTION( "connectivity.hsqldb", "[HSQLDB-SDBC] caught an exception while opening a stream\n"
+ "Name: " << sName
+ << "\nMode: 0x" << ( _nMode < 16 ? "0" : "")
+ << std::hex << _nMode );
+ StorageContainer::throwJavaException(e,env);
+ }
+ }
+ }
+ }
+ return pHelper;
+ }
+
+ void StorageContainer::revokeStream( JNIEnv * env,jstring name, jstring key)
+ {
+ TStorages& rMap = lcl_getStorageMap();
+ TStorages::iterator aFind = rMap.find(jstring2ustring(env,key));
+ OSL_ENSURE(aFind != rMap.end(),"Storage could not be found in list!");
+ if ( aFind != rMap.end() )
+ aFind->second.streams.erase(removeURLPrefix(jstring2ustring(env,name),aFind->second.url));
+ }
+
+ TStreamMap::mapped_type StorageContainer::getRegisteredStream( JNIEnv * env,jstring name, jstring key)
+ {
+ TStreamMap::mapped_type pRet;
+ TStorages& rMap = lcl_getStorageMap();
+ TStorages::const_iterator aFind = rMap.find(jstring2ustring(env,key));
+ OSL_ENSURE(aFind != rMap.end(),"Storage could not be found in list!");
+ if ( aFind != rMap.end() )
+ {
+ TStreamMap::const_iterator aStreamFind = aFind->second.streams.find(removeURLPrefix(jstring2ustring(env,name),aFind->second.url));
+ if ( aStreamFind != aFind->second.streams.end() )
+ pRet = aStreamFind->second;
+ }
+
+ return pRet;
+ }
+
+ void StorageContainer::throwJavaException(const Exception& _aException,JNIEnv * env)
+ {
+ if (env->ExceptionCheck())
+ env->ExceptionClear();
+ SAL_WARN("connectivity.hsqldb", "forwarding Exception: " << _aException );
+ OString cstr( OUStringToOString(_aException.Message, RTL_TEXTENCODING_JAVA_UTF8 ) );
+ env->ThrowNew(env->FindClass("java/io/IOException"), cstr.getStr());
+ }
+
+} // namespace
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/hsqldb/HTable.cxx b/connectivity/source/drivers/hsqldb/HTable.cxx
new file mode 100644
index 0000000000..63fe36a34a
--- /dev/null
+++ b/connectivity/source/drivers/hsqldb/HTable.cxx
@@ -0,0 +1,373 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <hsqldb/HTable.hxx>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/sdbcx/Privilege.hpp>
+#include <comphelper/property.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <comphelper/types.hxx>
+#include <connectivity/dbtools.hxx>
+#include <connectivity/TKeys.hxx>
+#include <connectivity/TIndexes.hxx>
+#include <hsqldb/HColumns.hxx>
+#include <TConnection.hxx>
+
+#include <comphelper/diagnose_ex.hxx>
+
+
+using namespace ::comphelper;
+using namespace connectivity::hsqldb;
+using namespace connectivity::sdbcx;
+using namespace connectivity;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+
+OHSQLTable::OHSQLTable( sdbcx::OCollection* _pTables,
+ const Reference< XConnection >& _xConnection)
+ :OTableHelper(_pTables,_xConnection,true)
+{
+ // we create a new table here, so we should have all the rights or ;-)
+ m_nPrivileges = Privilege::DROP |
+ Privilege::REFERENCE |
+ Privilege::ALTER |
+ Privilege::CREATE |
+ Privilege::READ |
+ Privilege::DELETE |
+ Privilege::UPDATE |
+ Privilege::INSERT |
+ Privilege::SELECT;
+ construct();
+}
+
+OHSQLTable::OHSQLTable( sdbcx::OCollection* _pTables,
+ const Reference< XConnection >& _xConnection,
+ const OUString& Name,
+ const OUString& Type,
+ const OUString& Description ,
+ const OUString& SchemaName,
+ const OUString& CatalogName,
+ sal_Int32 _nPrivileges
+ ) : OTableHelper( _pTables,
+ _xConnection,
+ true,
+ Name,
+ Type,
+ Description,
+ SchemaName,
+ CatalogName)
+ , m_nPrivileges(_nPrivileges)
+{
+ construct();
+}
+
+void OHSQLTable::construct()
+{
+ OTableHelper::construct();
+ if ( !isNew() )
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PRIVILEGES), PROPERTY_ID_PRIVILEGES,PropertyAttribute::READONLY,&m_nPrivileges, cppu::UnoType<decltype(m_nPrivileges)>::get());
+}
+
+::cppu::IPropertyArrayHelper* OHSQLTable::createArrayHelper( sal_Int32 /*_nId*/ ) const
+{
+ return doCreateArrayHelper();
+}
+
+::cppu::IPropertyArrayHelper & OHSQLTable::getInfoHelper()
+{
+ return *static_cast<OHSQLTable_PROP*>(this)->getArrayHelper(isNew() ? 1 : 0);
+}
+
+sdbcx::OCollection* OHSQLTable::createColumns(const ::std::vector< OUString>& _rNames)
+{
+ OHSQLColumns* pColumns = new OHSQLColumns(*this,m_aMutex,_rNames);
+ pColumns->setParent(this);
+ return pColumns;
+}
+
+sdbcx::OCollection* OHSQLTable::createKeys(const ::std::vector< OUString>& _rNames)
+{
+ return new OKeysHelper(this,m_aMutex,_rNames);
+}
+
+sdbcx::OCollection* OHSQLTable::createIndexes(const ::std::vector< OUString>& _rNames)
+{
+ return new OIndexesHelper(this,m_aMutex,_rNames);
+}
+
+
+// XAlterTable
+void SAL_CALL OHSQLTable::alterColumnByName( const OUString& colName, const Reference< XPropertySet >& descriptor )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(
+#ifdef __GNUC__
+ ::connectivity::sdbcx::OTableDescriptor_BASE::rBHelper.bDisposed
+#else
+ rBHelper.bDisposed
+#endif
+ );
+
+ if ( !m_xColumns || !m_xColumns->hasByName(colName) )
+ throw NoSuchElementException(colName,*this);
+
+
+ if ( !isNew() )
+ {
+ // first we have to check what should be altered
+ Reference<XPropertySet> xProp;
+ m_xColumns->getByName(colName) >>= xProp;
+ // first check the types
+ sal_Int32 nOldType = 0,nNewType = 0,nOldPrec = 0,nNewPrec = 0,nOldScale = 0,nNewScale = 0;
+ OUString sOldTypeName, sNewTypeName;
+
+ ::dbtools::OPropertyMap& rProp = OMetaConnection::getPropMap();
+
+ // type/typename
+ xProp->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_TYPE)) >>= nOldType;
+ descriptor->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_TYPE)) >>= nNewType;
+ xProp->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_TYPENAME)) >>= sOldTypeName;
+ descriptor->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_TYPENAME))>>= sNewTypeName;
+
+ // and precision and scale
+ xProp->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_PRECISION)) >>= nOldPrec;
+ descriptor->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_PRECISION))>>= nNewPrec;
+ xProp->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_SCALE)) >>= nOldScale;
+ descriptor->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_SCALE)) >>= nNewScale;
+
+ // second: check the "is nullable" value
+ sal_Int32 nOldNullable = 0,nNewNullable = 0;
+ xProp->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_ISNULLABLE)) >>= nOldNullable;
+ descriptor->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_ISNULLABLE)) >>= nNewNullable;
+
+ // check also the auto_increment
+ bool bOldAutoIncrement = false,bAutoIncrement = false;
+ xProp->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_ISAUTOINCREMENT)) >>= bOldAutoIncrement;
+ descriptor->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_ISAUTOINCREMENT)) >>= bAutoIncrement;
+
+ // now we should look if the name of the column changed
+ OUString sNewColumnName;
+ descriptor->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_NAME)) >>= sNewColumnName;
+ if ( sNewColumnName != colName )
+ {
+ const OUString sQuote = getMetaData()->getIdentifierQuoteString( );
+
+ OUString sSql = getAlterTableColumnPart() +
+ " ALTER COLUMN " +
+ ::dbtools::quoteName(sQuote,colName) +
+ " RENAME TO " +
+ ::dbtools::quoteName(sQuote,sNewColumnName);
+
+ executeStatement(sSql);
+ }
+
+ if ( nOldType != nNewType
+ || sOldTypeName != sNewTypeName
+ || nOldPrec != nNewPrec
+ || nOldScale != nNewScale
+ || nNewNullable != nOldNullable
+ || bOldAutoIncrement != bAutoIncrement )
+ {
+ // special handling because they change the type names to distinguish
+ // if a column should be an auto_increment one
+ if ( bOldAutoIncrement != bAutoIncrement )
+ {
+ /// TODO: insert special handling for auto increment "IDENTITY" and primary key
+ }
+ alterColumnType(nNewType,sNewColumnName,descriptor);
+ }
+
+ // third: check the default values
+ OUString sNewDefault,sOldDefault;
+ xProp->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_DEFAULTVALUE)) >>= sOldDefault;
+ descriptor->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_DEFAULTVALUE)) >>= sNewDefault;
+
+ if(!sOldDefault.isEmpty())
+ {
+ dropDefaultValue(colName);
+ if(!sNewDefault.isEmpty() && sOldDefault != sNewDefault)
+ alterDefaultValue(sNewDefault,sNewColumnName);
+ }
+ else if(sOldDefault.isEmpty() && !sNewDefault.isEmpty())
+ alterDefaultValue(sNewDefault,sNewColumnName);
+
+ m_xColumns->refresh();
+ }
+ else
+ {
+ if(m_xColumns)
+ {
+ m_xColumns->dropByName(colName);
+ m_xColumns->appendByDescriptor(descriptor);
+ }
+ }
+
+}
+
+void OHSQLTable::alterColumnType(sal_Int32 nNewType,const OUString& _rColName, const Reference<XPropertySet>& _xDescriptor)
+{
+ OUString sSql = getAlterTableColumnPart() + " ALTER COLUMN ";
+#if OSL_DEBUG_LEVEL > 0
+ try
+ {
+ OUString sDescriptorName;
+ OSL_ENSURE( _xDescriptor.is()
+ && ( _xDescriptor->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex( PROPERTY_ID_NAME ) ) >>= sDescriptorName )
+ && ( sDescriptorName == _rColName ),
+ "OHSQLTable::alterColumnType: unexpected column name!" );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("connectivity.hsqldb");
+ }
+#else
+ (void)_rColName;
+#endif
+
+ rtl::Reference<OHSQLColumn> pColumn = new OHSQLColumn;
+ ::comphelper::copyProperties(_xDescriptor,pColumn);
+ pColumn->setPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE),Any(nNewType));
+
+ sSql += ::dbtools::createStandardColumnPart(pColumn,getConnection());
+ executeStatement(sSql);
+}
+
+void OHSQLTable::alterDefaultValue(std::u16string_view _sNewDefault,const OUString& _rColName)
+{
+ const OUString sQuote = getMetaData()->getIdentifierQuoteString( );
+ OUString sSql = getAlterTableColumnPart() +
+ " ALTER COLUMN " +
+ ::dbtools::quoteName(sQuote,_rColName) +
+ " SET DEFAULT '" + _sNewDefault + "'";
+
+ executeStatement(sSql);
+}
+
+void OHSQLTable::dropDefaultValue(const OUString& _rColName)
+{
+ const OUString sQuote = getMetaData()->getIdentifierQuoteString( );
+ OUString sSql = getAlterTableColumnPart() +
+ " ALTER COLUMN " +
+ ::dbtools::quoteName(sQuote,_rColName) +
+ " DROP DEFAULT";
+
+ executeStatement(sSql);
+}
+
+OUString OHSQLTable::getAlterTableColumnPart() const
+{
+ OUString sSql( "ALTER TABLE " );
+
+ OUString sComposedName( ::dbtools::composeTableName( getMetaData(), m_CatalogName, m_SchemaName, m_Name, true, ::dbtools::EComposeRule::InTableDefinitions ) );
+ sSql += sComposedName;
+
+ return sSql;
+}
+
+void OHSQLTable::executeStatement(const OUString& _rStatement )
+{
+ OUString sSQL = _rStatement;
+ if(sSQL.endsWith(","))
+ sSQL = sSQL.replaceAt(sSQL.getLength()-1, 1, u")");
+
+ Reference< XStatement > xStmt = getConnection()->createStatement( );
+ if ( xStmt.is() )
+ {
+ try { xStmt->execute(sSQL); }
+ catch( const Exception& )
+ {
+ ::comphelper::disposeComponent(xStmt);
+ throw;
+ }
+ ::comphelper::disposeComponent(xStmt);
+ }
+}
+
+Sequence< Type > SAL_CALL OHSQLTable::getTypes( )
+{
+ if ( m_Type == "VIEW" )
+ {
+ Sequence< Type > aTypes = OTableHelper::getTypes();
+ std::vector<Type> aOwnTypes;
+ aOwnTypes.reserve(aTypes.getLength());
+ const Type* pIter = aTypes.getConstArray();
+ const Type* pEnd = pIter + aTypes.getLength();
+ for(;pIter != pEnd;++pIter)
+ {
+ if( *pIter != cppu::UnoType<XRename>::get())
+ {
+ aOwnTypes.push_back(*pIter);
+ }
+ }
+ return Sequence< Type >(aOwnTypes.data(), aOwnTypes.size());
+ }
+ return OTableHelper::getTypes();
+}
+
+// XRename
+void SAL_CALL OHSQLTable::rename( const OUString& newName )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(
+#ifdef __GNUC__
+ ::connectivity::sdbcx::OTableDescriptor_BASE::rBHelper.bDisposed
+#else
+ rBHelper.bDisposed
+#endif
+ );
+
+ if(!isNew())
+ {
+ OUString sSql = "ALTER ";
+ if ( m_Type == "VIEW" )
+ sSql += " VIEW ";
+ else
+ sSql += " TABLE ";
+
+ OUString sCatalog,sSchema,sTable;
+ ::dbtools::qualifiedNameComponents(getMetaData(),newName,sCatalog,sSchema,sTable,::dbtools::EComposeRule::InDataManipulation);
+
+ sSql +=
+ ::dbtools::composeTableName( getMetaData(), m_CatalogName, m_SchemaName, m_Name, true, ::dbtools::EComposeRule::InDataManipulation )
+ + " RENAME TO "
+ + ::dbtools::composeTableName( getMetaData(), sCatalog, sSchema, sTable, true, ::dbtools::EComposeRule::InDataManipulation );
+
+ executeStatement(sSql);
+
+ ::connectivity::OTable_TYPEDEF::rename(newName);
+ }
+ else
+ ::dbtools::qualifiedNameComponents(getMetaData(),newName,m_CatalogName,m_SchemaName,m_Name,::dbtools::EComposeRule::InTableDefinitions);
+}
+
+
+Any SAL_CALL OHSQLTable::queryInterface( const Type & rType )
+{
+ if( m_Type == "VIEW" && rType == cppu::UnoType<XRename>::get())
+ return Any();
+
+ return OTableHelper::queryInterface(rType);
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/hsqldb/HTables.cxx b/connectivity/source/drivers/hsqldb/HTables.cxx
new file mode 100644
index 0000000000..de99a3b04e
--- /dev/null
+++ b/connectivity/source/drivers/hsqldb/HTables.cxx
@@ -0,0 +1,176 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <hsqldb/HTables.hxx>
+#include <hsqldb/HViews.hxx>
+#include <hsqldb/HTable.hxx>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XResultSet.hpp>
+#include <com/sun/star/sdbcx/Privilege.hpp>
+#include <hsqldb/HCatalog.hxx>
+#include <connectivity/dbtools.hxx>
+#include <comphelper/types.hxx>
+#include <TConnection.hxx>
+
+using namespace ::comphelper;
+using namespace connectivity;
+using namespace ::cppu;
+using namespace connectivity::hsqldb;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+using namespace dbtools;
+
+sdbcx::ObjectType OTables::createObject(const OUString& _rName)
+{
+ OUString sCatalog,sSchema,sTable;
+ ::dbtools::qualifiedNameComponents(m_xMetaData,_rName,sCatalog,sSchema,sTable,::dbtools::EComposeRule::InDataManipulation);
+
+ Sequence< OUString > sTableTypes {"VIEW", "TABLE", "%"}; // this last one just to be sure to include anything else...
+
+ Any aCatalog;
+ if ( !sCatalog.isEmpty() )
+ aCatalog <<= sCatalog;
+ Reference< XResultSet > xResult = m_xMetaData->getTables(aCatalog,sSchema,sTable,sTableTypes);
+
+ sdbcx::ObjectType xRet;
+ if ( xResult.is() )
+ {
+ Reference< XRow > xRow(xResult,UNO_QUERY);
+ if ( xResult->next() ) // there can be only one table with this name
+ {
+ sal_Int32 nPrivileges = ::dbtools::getTablePrivileges( m_xMetaData, sCatalog, sSchema, sTable );
+ if ( m_xMetaData->isReadOnly() )
+ nPrivileges &= ~( Privilege::INSERT | Privilege::UPDATE | Privilege::DELETE | Privilege::CREATE | Privilege::ALTER | Privilege::DROP );
+
+ // obtain privileges
+ xRet = new OHSQLTable( this
+ ,static_cast<OHCatalog&>(m_rParent).getConnection()
+ ,sTable
+ ,xRow->getString(4)
+ ,xRow->getString(5)
+ ,sSchema
+ ,sCatalog
+ ,nPrivileges);
+ }
+ ::comphelper::disposeComponent(xResult);
+ }
+
+ return xRet;
+}
+
+void OTables::impl_refresh( )
+{
+ static_cast<OHCatalog&>(m_rParent).refreshTables();
+}
+
+void OTables::disposing()
+{
+ m_xMetaData.clear();
+ OCollection::disposing();
+}
+
+Reference< XPropertySet > OTables::createDescriptor()
+{
+ return new OHSQLTable(this,static_cast<OHCatalog&>(m_rParent).getConnection());
+}
+
+// XAppend
+sdbcx::ObjectType OTables::appendObject( const OUString& _rForName, const Reference< XPropertySet >& descriptor )
+{
+ createTable(descriptor);
+ return createObject( _rForName );
+}
+
+// XDrop
+void OTables::dropObject(sal_Int32 _nPos,const OUString& _sElementName)
+{
+ Reference< XInterface > xObject( getObject( _nPos ) );
+ bool bIsNew = connectivity::sdbcx::ODescriptor::isNew( xObject );
+ if (bIsNew)
+ return;
+
+ Reference< XConnection > xConnection = static_cast<OHCatalog&>(m_rParent).getConnection();
+
+
+ OUString sCatalog,sSchema,sTable;
+ ::dbtools::qualifiedNameComponents(m_xMetaData,_sElementName,sCatalog,sSchema,sTable,::dbtools::EComposeRule::InDataManipulation);
+
+ OUString aSql( "DROP " );
+
+ Reference<XPropertySet> xProp(xObject,UNO_QUERY);
+ bool bIsView;
+ if((bIsView = (xProp.is() && ::comphelper::getString(xProp->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE))) == "VIEW"))) // here we have a view
+ aSql += "VIEW ";
+ else
+ aSql += "TABLE ";
+
+ OUString sComposedName(
+ ::dbtools::composeTableName( m_xMetaData, sCatalog, sSchema, sTable, true, ::dbtools::EComposeRule::InDataManipulation ) );
+ aSql += sComposedName;
+ Reference< XStatement > xStmt = xConnection->createStatement( );
+ if ( xStmt.is() )
+ {
+ xStmt->execute(aSql);
+ ::comphelper::disposeComponent(xStmt);
+ }
+ // if no exception was thrown we must delete it from the views
+ if ( bIsView )
+ {
+ HViews* pViews = static_cast<HViews*>(static_cast<OHCatalog&>(m_rParent).getPrivateViews());
+ if ( pViews && pViews->hasByName(_sElementName) )
+ pViews->dropByNameImpl(_sElementName);
+ }
+}
+
+void OTables::createTable( const Reference< XPropertySet >& descriptor )
+{
+ Reference< XConnection > xConnection = static_cast<OHCatalog&>(m_rParent).getConnection();
+ OUString aSql = ::dbtools::createSqlCreateTableStatement(descriptor,xConnection);
+
+ Reference< XStatement > xStmt = xConnection->createStatement( );
+ if ( xStmt.is() )
+ {
+ xStmt->execute(aSql);
+ ::comphelper::disposeComponent(xStmt);
+ }
+}
+
+void OTables::appendNew(const OUString& _rsNewTable)
+{
+ insertElement(_rsNewTable,nullptr);
+
+ // notify our container listeners
+ ContainerEvent aEvent(static_cast<XContainer*>(this), Any(_rsNewTable), Any(), Any());
+ OInterfaceIteratorHelper3 aListenerLoop(m_aContainerListeners);
+ while (aListenerLoop.hasMoreElements())
+ aListenerLoop.next()->elementInserted(aEvent);
+}
+
+OUString OTables::getNameForObject(const sdbcx::ObjectType& _xObject)
+{
+ OSL_ENSURE(_xObject.is(),"OTables::getNameForObject: Object is NULL!");
+ return ::dbtools::composeTableName( m_xMetaData, _xObject, ::dbtools::EComposeRule::InDataManipulation, false );
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/hsqldb/HTerminateListener.cxx b/connectivity/source/drivers/hsqldb/HTerminateListener.cxx
new file mode 100644
index 0000000000..a9df5ccc9b
--- /dev/null
+++ b/connectivity/source/drivers/hsqldb/HTerminateListener.cxx
@@ -0,0 +1,45 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "HTerminateListener.hxx"
+#include <hsqldb/HDriver.hxx>
+
+namespace connectivity
+{
+using namespace hsqldb;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+
+// XEventListener
+void SAL_CALL OConnectionController::disposing(const EventObject& /*Source*/) {}
+
+// XTerminateListener
+void SAL_CALL OConnectionController::queryTermination(const EventObject& /*aEvent*/)
+{
+ m_pDriver->flushConnections();
+}
+
+void SAL_CALL OConnectionController::notifyTermination(const EventObject& /*aEvent*/)
+{
+ m_pDriver->shutdownConnections();
+}
+
+} // namespace connectivity
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/hsqldb/HTerminateListener.hxx b/connectivity/source/drivers/hsqldb/HTerminateListener.hxx
new file mode 100644
index 0000000000..baf66e90eb
--- /dev/null
+++ b/connectivity/source/drivers/hsqldb/HTerminateListener.hxx
@@ -0,0 +1,46 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <cppuhelper/implbase.hxx>
+#include <com/sun/star/frame/XTerminateListener.hpp>
+
+
+namespace connectivity::hsqldb
+ {
+ class ODriverDelegator;
+ class OConnectionController : public ::cppu::WeakImplHelper< css::frame::XTerminateListener >
+ {
+ ODriverDelegator* m_pDriver;
+ protected:
+ virtual ~OConnectionController() override {m_pDriver = nullptr;}
+ public:
+ explicit OConnectionController(ODriverDelegator* _pDriver) : m_pDriver(_pDriver){}
+
+ // XEventListener
+ virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override;
+
+ // XTerminateListener
+ virtual void SAL_CALL queryTermination( const css::lang::EventObject& aEvent ) override;
+ virtual void SAL_CALL notifyTermination( const css::lang::EventObject& aEvent ) override;
+ };
+
+} // namespace connectivity::hsqldb
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/hsqldb/HTools.cxx b/connectivity/source/drivers/hsqldb/HTools.cxx
new file mode 100644
index 0000000000..3dd388acee
--- /dev/null
+++ b/connectivity/source/drivers/hsqldb/HTools.cxx
@@ -0,0 +1,53 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <hsqldb/HTools.hxx>
+
+
+namespace connectivity::hsqldb
+{
+
+ void HTools::appendTableFilterCrit( OUStringBuffer& _inout_rBuffer, std::u16string_view _rCatalog,
+ std::u16string_view _rSchema, std::u16string_view _rName, bool _bShortForm )
+ {
+ _inout_rBuffer.append( " WHERE " );
+ if ( !_rCatalog.empty() )
+ {
+ _inout_rBuffer.appendAscii( _bShortForm ? "TABLE_CAT" : "TABLE_CATALOG" );
+ _inout_rBuffer.append( " = '" );
+ _inout_rBuffer.append ( _rCatalog );
+ _inout_rBuffer.append( "' AND " );
+ }
+ if ( !_rSchema.empty() )
+ {
+ _inout_rBuffer.appendAscii( _bShortForm ? "TABLE_SCHEM" : "TABLE_SCHEMA" );
+ _inout_rBuffer.append( " = '" );
+ _inout_rBuffer.append ( _rSchema );
+ _inout_rBuffer.append( "' AND " );
+ }
+ _inout_rBuffer.append( "TABLE_NAME = '" );
+ _inout_rBuffer.append ( _rName );
+ _inout_rBuffer.append( "'" );
+ }
+
+
+} // namespace connectivity::hsqldb
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/hsqldb/HUser.cxx b/connectivity/source/drivers/hsqldb/HUser.cxx
new file mode 100644
index 0000000000..f493e282a2
--- /dev/null
+++ b/connectivity/source/drivers/hsqldb/HUser.cxx
@@ -0,0 +1,329 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <hsqldb/HUser.hxx>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XResultSet.hpp>
+#include <connectivity/dbtools.hxx>
+#include <connectivity/dbexception.hxx>
+#include <comphelper/types.hxx>
+#include <com/sun/star/sdbcx/Privilege.hpp>
+#include <com/sun/star/sdbcx/PrivilegeObject.hpp>
+#include <TConnection.hxx>
+#include <strings.hrc>
+#include <utility>
+
+using namespace connectivity;
+using namespace connectivity::hsqldb;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+
+OHSQLUser::OHSQLUser( css::uno::Reference< css::sdbc::XConnection > _xConnection) : connectivity::sdbcx::OUser(true)
+ ,m_xConnection(std::move(_xConnection))
+{
+ construct();
+}
+
+OHSQLUser::OHSQLUser( css::uno::Reference< css::sdbc::XConnection > _xConnection,
+ const OUString& Name
+ ) : connectivity::sdbcx::OUser(Name,true)
+ ,m_xConnection(std::move(_xConnection))
+{
+ construct();
+}
+
+void OHSQLUser::refreshGroups()
+{
+}
+
+OUserExtend::OUserExtend( const css::uno::Reference< css::sdbc::XConnection >& _xConnection) : OHSQLUser(_xConnection)
+{
+ construct();
+}
+
+void OUserExtend::construct()
+{
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PASSWORD), PROPERTY_ID_PASSWORD,0,&m_Password,::cppu::UnoType<OUString>::get());
+}
+
+cppu::IPropertyArrayHelper* OUserExtend::createArrayHelper() const
+{
+ Sequence< Property > aProps;
+ describeProperties(aProps);
+ return new cppu::OPropertyArrayHelper(aProps);
+}
+
+cppu::IPropertyArrayHelper & OUserExtend::getInfoHelper()
+{
+ return *OUserExtend_PROP::getArrayHelper();
+}
+typedef connectivity::sdbcx::OUser_BASE OUser_BASE_RBHELPER;
+
+sal_Int32 SAL_CALL OHSQLUser::getPrivileges( const OUString& objName, sal_Int32 objType )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(OUser_BASE_RBHELPER::rBHelper.bDisposed);
+
+ sal_Int32 nRights,nRightsWithGrant;
+ findPrivilegesAndGrantPrivileges(objName,objType,nRights,nRightsWithGrant);
+ return nRights;
+}
+
+void OHSQLUser::findPrivilegesAndGrantPrivileges(const OUString& objName, sal_Int32 objType,sal_Int32& nRights,sal_Int32& nRightsWithGrant)
+{
+ nRightsWithGrant = nRights = 0;
+ // first we need to create the sql stmt to select the privs
+ Reference<XDatabaseMetaData> xMeta = m_xConnection->getMetaData();
+ OUString sCatalog,sSchema,sTable;
+ ::dbtools::qualifiedNameComponents(xMeta,objName,sCatalog,sSchema,sTable,::dbtools::EComposeRule::InDataManipulation);
+ Reference<XResultSet> xRes;
+ switch(objType)
+ {
+ case PrivilegeObject::TABLE:
+ case PrivilegeObject::VIEW:
+ {
+ Any aCatalog;
+ if ( !sCatalog.isEmpty() )
+ aCatalog <<= sCatalog;
+ xRes = xMeta->getTablePrivileges(aCatalog,sSchema,sTable);
+ }
+ break;
+
+ case PrivilegeObject::COLUMN:
+ {
+ Any aCatalog;
+ if ( !sCatalog.isEmpty() )
+ aCatalog <<= sCatalog;
+ xRes = xMeta->getColumnPrivileges(aCatalog,sSchema,sTable,"%");
+ }
+ break;
+ }
+
+ if ( !xRes.is() )
+ return;
+
+ static const char sYes [] = "YES";
+
+ nRightsWithGrant = nRights = 0;
+
+ Reference<XRow> xCurrentRow(xRes,UNO_QUERY);
+ while( xCurrentRow.is() && xRes->next() )
+ {
+ OUString sGrantee = xCurrentRow->getString(5);
+ OUString sPrivilege = xCurrentRow->getString(6);
+ OUString sGrantable = xCurrentRow->getString(7);
+
+ if (!m_Name.equalsIgnoreAsciiCase(sGrantee))
+ continue;
+
+ if (sPrivilege.equalsIgnoreAsciiCase("SELECT"))
+ {
+ nRights |= Privilege::SELECT;
+ if ( sGrantable.equalsIgnoreAsciiCase(sYes) )
+ nRightsWithGrant |= Privilege::SELECT;
+ }
+ else if (sPrivilege.equalsIgnoreAsciiCase("INSERT"))
+ {
+ nRights |= Privilege::INSERT;
+ if ( sGrantable.equalsIgnoreAsciiCase(sYes) )
+ nRightsWithGrant |= Privilege::INSERT;
+ }
+ else if (sPrivilege.equalsIgnoreAsciiCase("UPDATE"))
+ {
+ nRights |= Privilege::UPDATE;
+ if ( sGrantable.equalsIgnoreAsciiCase(sYes) )
+ nRightsWithGrant |= Privilege::UPDATE;
+ }
+ else if (sPrivilege.equalsIgnoreAsciiCase("DELETE"))
+ {
+ nRights |= Privilege::DELETE;
+ if ( sGrantable.equalsIgnoreAsciiCase(sYes) )
+ nRightsWithGrant |= Privilege::DELETE;
+ }
+ else if (sPrivilege.equalsIgnoreAsciiCase("READ"))
+ {
+ nRights |= Privilege::READ;
+ if ( sGrantable.equalsIgnoreAsciiCase(sYes) )
+ nRightsWithGrant |= Privilege::READ;
+ }
+ else if (sPrivilege.equalsIgnoreAsciiCase("CREATE"))
+ {
+ nRights |= Privilege::CREATE;
+ if ( sGrantable.equalsIgnoreAsciiCase(sYes) )
+ nRightsWithGrant |= Privilege::CREATE;
+ }
+ else if (sPrivilege.equalsIgnoreAsciiCase("ALTER"))
+ {
+ nRights |= Privilege::ALTER;
+ if ( sGrantable.equalsIgnoreAsciiCase(sYes) )
+ nRightsWithGrant |= Privilege::ALTER;
+ }
+ else if (sPrivilege.equalsIgnoreAsciiCase("REFERENCE"))
+ {
+ nRights |= Privilege::REFERENCE;
+ if ( sGrantable.equalsIgnoreAsciiCase(sYes) )
+ nRightsWithGrant |= Privilege::REFERENCE;
+ }
+ else if (sPrivilege.equalsIgnoreAsciiCase("DROP"))
+ {
+ nRights |= Privilege::DROP;
+ if ( sGrantable.equalsIgnoreAsciiCase(sYes) )
+ nRightsWithGrant |= Privilege::DROP;
+ }
+ }
+ ::comphelper::disposeComponent(xRes);
+}
+
+sal_Int32 SAL_CALL OHSQLUser::getGrantablePrivileges( const OUString& objName, sal_Int32 objType )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(OUser_BASE_RBHELPER::rBHelper.bDisposed);
+
+ sal_Int32 nRights,nRightsWithGrant;
+ findPrivilegesAndGrantPrivileges(objName,objType,nRights,nRightsWithGrant);
+ return nRightsWithGrant;
+}
+
+void SAL_CALL OHSQLUser::grantPrivileges( const OUString& objName, sal_Int32 objType, sal_Int32 objPrivileges )
+{
+ if ( objType != PrivilegeObject::TABLE )
+ {
+ ::connectivity::SharedResources aResources;
+ const OUString sError( aResources.getResourceString(STR_PRIVILEGE_NOT_GRANTED));
+ ::dbtools::throwGenericSQLException(sError,*this);
+ } // if ( objType != PrivilegeObject::TABLE )
+
+
+ ::osl::MutexGuard aGuard(m_aMutex);
+
+ OUString sPrivs = getPrivilegeString(objPrivileges);
+ if(!sPrivs.isEmpty())
+ {
+ Reference<XDatabaseMetaData> xMeta = m_xConnection->getMetaData();
+ OUString sGrant = "GRANT " + sPrivs +
+ " ON " + ::dbtools::quoteTableName(xMeta,objName,::dbtools::EComposeRule::InDataManipulation) +
+ " TO " + ::dbtools::quoteName(xMeta->getIdentifierQuoteString(), m_Name);
+
+ Reference<XStatement> xStmt = m_xConnection->createStatement();
+ if(xStmt.is())
+ xStmt->execute(sGrant);
+ ::comphelper::disposeComponent(xStmt);
+ }
+}
+
+void SAL_CALL OHSQLUser::revokePrivileges( const OUString& objName, sal_Int32 objType, sal_Int32 objPrivileges )
+{
+ if ( objType != PrivilegeObject::TABLE )
+ {
+ ::connectivity::SharedResources aResources;
+ const OUString sError( aResources.getResourceString(STR_PRIVILEGE_NOT_REVOKED));
+ ::dbtools::throwGenericSQLException(sError,*this);
+ } // if ( objType != PrivilegeObject::TABLE )
+
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(OUser_BASE_RBHELPER::rBHelper.bDisposed);
+ OUString sPrivs = getPrivilegeString(objPrivileges);
+ if(!sPrivs.isEmpty())
+ {
+ Reference<XDatabaseMetaData> xMeta = m_xConnection->getMetaData();
+ OUString sGrant = "REVOKE " + sPrivs +
+ " ON " + ::dbtools::quoteTableName(xMeta,objName,::dbtools::EComposeRule::InDataManipulation) +
+ " FROM " + ::dbtools::quoteName(xMeta->getIdentifierQuoteString(), m_Name);
+
+ Reference<XStatement> xStmt = m_xConnection->createStatement();
+ if(xStmt.is())
+ xStmt->execute(sGrant);
+ ::comphelper::disposeComponent(xStmt);
+ }
+}
+
+// XUser
+void SAL_CALL OHSQLUser::changePassword( const OUString& /*oldPassword*/, const OUString& newPassword )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(OUser_BASE_RBHELPER::rBHelper.bDisposed);
+
+ Reference<XDatabaseMetaData> xMeta = m_xConnection->getMetaData();
+
+ if( m_Name != xMeta->getUserName() )
+ {
+ ::dbtools::throwGenericSQLException("HSQLDB can only change password of the current user.", *this);
+ }
+
+ OUString sAlterPwd = "SET PASSWORD " +
+ ::dbtools::quoteName(xMeta->getIdentifierQuoteString(), newPassword);
+
+ Reference<XStatement> xStmt = m_xConnection->createStatement();
+ if ( xStmt.is() )
+ {
+ xStmt->execute(sAlterPwd);
+ ::comphelper::disposeComponent(xStmt);
+ }
+}
+
+OUString OHSQLUser::getPrivilegeString(sal_Int32 nRights)
+{
+ OUString sPrivs;
+ if((nRights & Privilege::INSERT) == Privilege::INSERT)
+ sPrivs += "INSERT";
+
+ if((nRights & Privilege::DELETE) == Privilege::DELETE)
+ {
+ if(!sPrivs.isEmpty())
+ sPrivs += ",";
+ sPrivs += "DELETE";
+ }
+
+ if((nRights & Privilege::UPDATE) == Privilege::UPDATE)
+ {
+ if(!sPrivs.isEmpty())
+ sPrivs += ",";
+ sPrivs += "UPDATE";
+ }
+
+ if((nRights & Privilege::ALTER) == Privilege::ALTER)
+ {
+ if(!sPrivs.isEmpty())
+ sPrivs += ",";
+ sPrivs += "ALTER";
+ }
+
+ if((nRights & Privilege::SELECT) == Privilege::SELECT)
+ {
+ if(!sPrivs.isEmpty())
+ sPrivs += ",";
+ sPrivs += "SELECT";
+ }
+
+ if((nRights & Privilege::REFERENCE) == Privilege::REFERENCE)
+ {
+ if(!sPrivs.isEmpty())
+ sPrivs += ",";
+ sPrivs += "REFERENCES";
+ }
+
+ return sPrivs;
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/hsqldb/HUsers.cxx b/connectivity/source/drivers/hsqldb/HUsers.cxx
new file mode 100644
index 0000000000..1295983333
--- /dev/null
+++ b/connectivity/source/drivers/hsqldb/HUsers.cxx
@@ -0,0 +1,99 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <hsqldb/HUsers.hxx>
+#include <hsqldb/HUser.hxx>
+#include <connectivity/sdbcx/IRefreshable.hxx>
+#include <comphelper/types.hxx>
+#include <connectivity/dbtools.hxx>
+#include <TConnection.hxx>
+#include <utility>
+
+using namespace ::comphelper;
+using namespace connectivity;
+using namespace connectivity::hsqldb;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+
+OUsers::OUsers( ::cppu::OWeakObject& _rParent,
+ ::osl::Mutex& _rMutex,
+ const ::std::vector< OUString> &_rVector,
+ css::uno::Reference< css::sdbc::XConnection > _xConnection,
+ connectivity::sdbcx::IRefreshableUsers* _pParent)
+ : sdbcx::OCollection(_rParent, true, _rMutex, _rVector)
+ ,m_xConnection(std::move(_xConnection))
+ ,m_pParent(_pParent)
+{
+}
+
+
+sdbcx::ObjectType OUsers::createObject(const OUString& _rName)
+{
+ return new OHSQLUser(m_xConnection,_rName);
+}
+
+void OUsers::impl_refresh()
+{
+ m_pParent->refreshUsers();
+}
+
+Reference< XPropertySet > OUsers::createDescriptor()
+{
+ return new OUserExtend(m_xConnection);
+}
+
+// XAppend
+sdbcx::ObjectType OUsers::appendObject( const OUString& _rForName, const Reference< XPropertySet >& descriptor )
+{
+ OUString aQuote = m_xConnection->getMetaData()->getIdentifierQuoteString( );
+ OUString sPassword;
+ descriptor->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PASSWORD)) >>= sPassword;
+ OUString aSql = "GRANT USAGE ON * TO " +
+ ::dbtools::quoteName(aQuote,_rForName) + " @\"%\" ";
+ if ( !sPassword.isEmpty() )
+ {
+ aSql += " IDENTIFIED BY '" + sPassword + "'";
+ }
+
+ Reference< XStatement > xStmt = m_xConnection->createStatement( );
+ if(xStmt.is())
+ xStmt->execute(aSql);
+ ::comphelper::disposeComponent(xStmt);
+
+ return createObject( _rForName );
+}
+
+// XDrop
+void OUsers::dropObject(sal_Int32 /*nPos*/,const OUString& _sElementName)
+{
+ OUString aSql( "REVOKE ALL ON * FROM " );
+ OUString aQuote = m_xConnection->getMetaData()->getIdentifierQuoteString( );
+ aSql += ::dbtools::quoteName(aQuote,_sElementName);
+
+ Reference< XStatement > xStmt = m_xConnection->createStatement( );
+ if(xStmt.is())
+ xStmt->execute(aSql);
+ ::comphelper::disposeComponent(xStmt);
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/hsqldb/HView.cxx b/connectivity/source/drivers/hsqldb/HView.cxx
new file mode 100644
index 0000000000..83946ee86f
--- /dev/null
+++ b/connectivity/source/drivers/hsqldb/HView.cxx
@@ -0,0 +1,216 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <hsqldb/HView.hxx>
+#include <hsqldb/HTools.hxx>
+
+#include <propertyids.hxx>
+
+#include <connectivity/dbtools.hxx>
+
+#include <com/sun/star/lang/WrappedTargetException.hpp>
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
+
+#include <cppuhelper/exc_hlp.hxx>
+#include <comphelper/diagnose_ex.hxx>
+#include <unotools/sharedunocomponent.hxx>
+
+
+namespace connectivity::hsqldb
+{
+
+
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::uno::UNO_QUERY_THROW;
+ using ::com::sun::star::uno::Exception;
+ using ::com::sun::star::uno::RuntimeException;
+ using ::com::sun::star::uno::Any;
+ using ::com::sun::star::sdbc::SQLException;
+ using ::com::sun::star::sdbc::XConnection;
+ using ::com::sun::star::lang::WrappedTargetException;
+ using ::com::sun::star::sdbc::XResultSet;
+ using ::com::sun::star::sdbc::XStatement;
+ using ::com::sun::star::lang::DisposedException;
+ using ::com::sun::star::sdbc::XRow;
+
+ HView::HView( const Reference< XConnection >& _rxConnection, bool _bCaseSensitive,
+ const OUString& _rSchemaName, const OUString& _rName )
+ :HView_Base( _bCaseSensitive, _rName, _rxConnection->getMetaData(), OUString(), _rSchemaName, OUString() )
+ ,m_xConnection( _rxConnection )
+ {
+ }
+
+
+ HView::~HView()
+ {
+ }
+
+
+ IMPLEMENT_FORWARD_XINTERFACE2( HView, HView_Base, HView_IBASE )
+ IMPLEMENT_FORWARD_XTYPEPROVIDER2( HView, HView_Base, HView_IBASE )
+
+
+ void SAL_CALL HView::alterCommand( const OUString& _rNewCommand )
+ {
+ // not really atomic ... as long as we do not have something like
+ // ALTER VIEW <name> TO <command>
+ // in HSQL, we need to do it this way ...
+ //
+ // I can imagine scenarios where this fails, e.g. when dropping the view
+ // succeeds, re-creating it fails, some other thread alters a table which
+ // the view was based on, and then we try to restore the view with the
+ // original command, which then fails, too.
+ //
+ // However, there's not much chance to prevent this kind of errors without
+ // backend support.
+
+ OUString sQualifiedName( ::dbtools::composeTableName(
+ m_xMetaData, m_CatalogName, m_SchemaName, m_Name, true, ::dbtools::EComposeRule::InDataManipulation ) );
+
+ ::utl::SharedUNOComponent< XStatement > xStatement; xStatement.set( m_xConnection->createStatement(), UNO_QUERY_THROW );
+
+ // create a statement which can be used to re-create the original view, in case
+ // dropping it succeeds, but creating it with a new statement fails
+ OUString sRestoreCommand =
+ "CREATE VIEW " +
+ sQualifiedName +
+ " AS " +
+ impl_getCommand_throwSQLException();
+
+ bool bDropSucceeded( false );
+ try
+ {
+ // drop the existing view
+ OUString aCommand ="DROP VIEW " + sQualifiedName;
+ xStatement->execute( aCommand );
+ bDropSucceeded = true;
+
+ // create a new one with the same name
+ aCommand = "CREATE VIEW " + sQualifiedName + " AS " + _rNewCommand;
+ xStatement->execute( aCommand );
+ }
+ catch( const SQLException& )
+ {
+ if ( bDropSucceeded )
+ // drop succeeded, but creation failed -> re-create the view with the original
+ // statement
+ xStatement->execute( sRestoreCommand );
+ throw;
+ }
+ catch( const RuntimeException& )
+ {
+ if ( bDropSucceeded )
+ xStatement->execute( sRestoreCommand );
+ throw;
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("connectivity.hsqldb");
+ if ( bDropSucceeded )
+ xStatement->execute( sRestoreCommand );
+ }
+ }
+
+
+ void SAL_CALL HView::getFastPropertyValue( Any& _rValue, sal_Int32 _nHandle ) const
+ {
+ if ( _nHandle == PROPERTY_ID_COMMAND )
+ {
+ // retrieve the very current command, don't rely on the base classes cached value
+ // (which we initialized empty, anyway)
+ _rValue <<= impl_getCommand_wrapSQLException();
+ return;
+ }
+
+ HView_Base::getFastPropertyValue( _rValue, _nHandle );
+ }
+
+ OUString HView::impl_getCommand() const
+ {
+ OUStringBuffer aCommand(
+ "SELECT VIEW_DEFINITION FROM INFORMATION_SCHEMA.SYSTEM_VIEWS " );
+ HTools::appendTableFilterCrit( aCommand, m_CatalogName, m_SchemaName, m_Name, false );
+ ::utl::SharedUNOComponent< XStatement > xStatement; xStatement.set( m_xConnection->createStatement(), UNO_QUERY_THROW );
+ Reference< XResultSet > xResult( xStatement->executeQuery( aCommand.makeStringAndClear() ), css::uno::UNO_SET_THROW );
+ if ( !xResult->next() )
+ {
+ // hmm. There is no view the name as we know it. Can only mean some other instance
+ // dropped this view meanwhile...
+ throw DisposedException();
+ }
+
+ Reference< XRow > xRow( xResult, UNO_QUERY_THROW );
+ return xRow->getString( 1 );
+ }
+
+ OUString HView::impl_getCommand_wrapSQLException() const
+ {
+ OUString sCommand;
+
+ try
+ {
+ sCommand = impl_getCommand();
+ }
+ catch( const RuntimeException& )
+ {
+ throw;
+ }
+ catch( const SQLException& e )
+ {
+ throw WrappedTargetException( e.Message, static_cast< XAlterView* >( const_cast< HView* >( this ) ), ::cppu::getCaughtException() );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("connectivity.hsqldb");
+ }
+
+ return sCommand;
+ }
+
+ OUString HView::impl_getCommand_throwSQLException() const
+ {
+ OUString sCommand;
+
+ try
+ {
+ sCommand = impl_getCommand();
+ }
+ catch( const RuntimeException& )
+ {
+ throw;
+ }
+ catch( const SQLException& )
+ {
+ throw;
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("connectivity.hsqldb");
+ }
+
+ return sCommand;
+ }
+
+} // namespace connectivity::hsqldb
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/hsqldb/HViews.cxx b/connectivity/source/drivers/hsqldb/HViews.cxx
new file mode 100644
index 0000000000..1f4b807484
--- /dev/null
+++ b/connectivity/source/drivers/hsqldb/HViews.cxx
@@ -0,0 +1,148 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <hsqldb/HTables.hxx>
+#include <hsqldb/HViews.hxx>
+#include <hsqldb/HView.hxx>
+#include <hsqldb/HCatalog.hxx>
+#include <connectivity/dbtools.hxx>
+#include <comphelper/types.hxx>
+#include <TConnection.hxx>
+
+using namespace ::comphelper;
+
+using namespace ::cppu;
+using namespace connectivity;
+using namespace connectivity::hsqldb;
+using namespace css::uno;
+using namespace css::beans;
+using namespace css::sdbcx;
+using namespace css::sdbc;
+using namespace css::container;
+using namespace css::lang;
+using namespace dbtools;
+typedef connectivity::sdbcx::OCollection OCollection_TYPE;
+
+
+HViews::HViews( const Reference< XConnection >& _rxConnection, ::cppu::OWeakObject& _rParent, ::osl::Mutex& _rMutex,
+ const ::std::vector< OUString> &_rVector )
+ :sdbcx::OCollection( _rParent, true, _rMutex, _rVector )
+ ,m_xConnection( _rxConnection )
+ ,m_xMetaData( _rxConnection->getMetaData() )
+ ,m_bInDrop( false )
+{
+}
+
+
+sdbcx::ObjectType HViews::createObject(const OUString& _rName)
+{
+ OUString sCatalog,sSchema,sTable;
+ ::dbtools::qualifiedNameComponents(m_xMetaData,
+ _rName,
+ sCatalog,
+ sSchema,
+ sTable,
+ ::dbtools::EComposeRule::InDataManipulation);
+ return new HView( m_xConnection, isCaseSensitive(), sSchema, sTable );
+}
+
+
+void HViews::impl_refresh( )
+{
+ static_cast<OHCatalog&>(m_rParent).refreshTables();
+}
+
+void HViews::disposing()
+{
+ m_xMetaData.clear();
+ OCollection::disposing();
+}
+
+Reference< XPropertySet > HViews::createDescriptor()
+{
+ Reference<XConnection> xConnection = static_cast<OHCatalog&>(m_rParent).getConnection();
+ return new connectivity::sdbcx::OView(true, xConnection->getMetaData());
+}
+
+// XAppend
+sdbcx::ObjectType HViews::appendObject( const OUString& _rForName, const Reference< XPropertySet >& descriptor )
+{
+ createView(descriptor);
+ return createObject( _rForName );
+}
+
+// XDrop
+void HViews::dropObject(sal_Int32 _nPos,const OUString& /*_sElementName*/)
+{
+ if ( m_bInDrop )
+ return;
+
+ Reference< XInterface > xObject( getObject( _nPos ) );
+ bool bIsNew = connectivity::sdbcx::ODescriptor::isNew( xObject );
+ if (!bIsNew)
+ {
+ OUString aSql( "DROP VIEW" );
+
+ Reference<XPropertySet> xProp(xObject,UNO_QUERY);
+ aSql += ::dbtools::composeTableName( m_xMetaData, xProp, ::dbtools::EComposeRule::InTableDefinitions, true );
+
+ Reference<XConnection> xConnection = static_cast<OHCatalog&>(m_rParent).getConnection();
+ Reference< XStatement > xStmt = xConnection->createStatement( );
+ xStmt->execute(aSql);
+ ::comphelper::disposeComponent(xStmt);
+ }
+}
+
+void HViews::dropByNameImpl(const OUString& elementName)
+{
+ m_bInDrop = true;
+ OCollection_TYPE::dropByName(elementName);
+ m_bInDrop = false;
+}
+
+void HViews::createView( const Reference< XPropertySet >& descriptor )
+{
+ Reference<XConnection> xConnection = static_cast<OHCatalog&>(m_rParent).getConnection();
+
+ OUString sCommand;
+ descriptor->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_COMMAND)) >>= sCommand;
+
+ OUString aSql = "CREATE VIEW " +
+ ::dbtools::composeTableName( m_xMetaData, descriptor, ::dbtools::EComposeRule::InTableDefinitions, true ) +
+ " AS " + sCommand;
+
+ Reference< XStatement > xStmt = xConnection->createStatement( );
+ if ( xStmt.is() )
+ {
+ xStmt->execute(aSql);
+ ::comphelper::disposeComponent(xStmt);
+ }
+
+ // insert the new view also in the tables collection
+ OTables* pTables = static_cast<OTables*>(static_cast<OHCatalog&>(m_rParent).getPrivateTables());
+ if ( pTables )
+ {
+ OUString sName = ::dbtools::composeTableName( m_xMetaData, descriptor, ::dbtools::EComposeRule::InDataManipulation, false );
+ pTables->appendNew(sName);
+ }
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/hsqldb/StorageFileAccess.cxx b/connectivity/source/drivers/hsqldb/StorageFileAccess.cxx
new file mode 100644
index 0000000000..bb07d6673f
--- /dev/null
+++ b/connectivity/source/drivers/hsqldb/StorageFileAccess.cxx
@@ -0,0 +1,167 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#if defined(HAVE_CONFIG_H) && HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <com/sun/star/embed/XStorage.hpp>
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+#include <hsqldb/HStorageMap.hxx>
+#include <comphelper/diagnose_ex.hxx>
+
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::embed;
+using namespace ::com::sun::star::io;
+using namespace ::com::sun::star::lang;
+using namespace ::connectivity::hsqldb;
+
+/*
+ * Class: com_sun_star_sdbcx_comp_hsqldb_StorageFileAccess
+ * Method: isStreamElement
+ * Signature: (Ljava/lang/String;Ljava/lang/String;)Z
+ */
+extern "C" SAL_JNI_EXPORT jboolean JNICALL Java_com_sun_star_sdbcx_comp_hsqldb_StorageFileAccess_isStreamElement
+ (JNIEnv * env, jobject /*obj_this*/,jstring key, jstring name)
+{
+ TStorages::mapped_type aStoragePair = StorageContainer::getRegisteredStorage(StorageContainer::jstring2ustring(env,key));
+ auto storage = aStoragePair.mapStorage();
+ if ( !storage )
+ return JNI_FALSE;
+
+ try
+ {
+ OUString sName = StorageContainer::jstring2ustring(env,name);
+ try
+ {
+ OUString sOldName = StorageContainer::removeOldURLPrefix(sName);
+ if ( storage->isStreamElement(sOldName) )
+ {
+ try
+ {
+ storage->renameElement(sOldName,StorageContainer::removeURLPrefix(sName,aStoragePair.url));
+ }
+ catch(const Exception&)
+ {
+ }
+ }
+ }
+ catch(const NoSuchElementException&)
+ {
+ }
+ catch(const IllegalArgumentException&)
+ {
+ }
+ return storage->isStreamElement(StorageContainer::removeURLPrefix(sName,aStoragePair.url));
+ }
+ catch(const NoSuchElementException&)
+ {
+ }
+ catch(const Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("connectivity.hsqldb", "forwarding");
+ if (env->ExceptionCheck())
+ env->ExceptionClear();
+ }
+ return JNI_FALSE;
+}
+
+
+/*
+ * Class: com_sun_star_sdbcx_comp_hsqldb_StorageFileAccess
+ * Method: removeElement
+ * Signature: (Ljava/lang/String;Ljava/lang/String;)V
+ */
+extern "C" SAL_JNI_EXPORT void JNICALL Java_com_sun_star_sdbcx_comp_hsqldb_StorageFileAccess_removeElement
+ (JNIEnv * env, jobject /*obj_this*/,jstring key, jstring name)
+{
+#ifdef HSQLDB_DBG
+ {
+ OUString sKey = StorageContainer::jstring2ustring(env,key);
+ OUString sName = StorageContainer::jstring2ustring(env,name);
+ }
+#endif
+ TStorages::mapped_type aStoragePair = StorageContainer::getRegisteredStorage(StorageContainer::jstring2ustring(env,key));
+ auto storage = aStoragePair.mapStorage();
+ if ( !storage.is() )
+ return;
+
+ try
+ {
+ storage->removeElement(StorageContainer::removeURLPrefix(StorageContainer::jstring2ustring(env,name),aStoragePair.url));
+ }
+ catch(const NoSuchElementException&)
+ {
+ if (env->ExceptionCheck())
+ env->ExceptionClear();
+ }
+ catch(const Exception& e)
+ {
+ TOOLS_WARN_EXCEPTION("connectivity.hsqldb", "");
+ StorageContainer::throwJavaException(e,env);
+ }
+}
+
+
+/*
+ * Class: com_sun_star_sdbcx_comp_hsqldb_StorageFileAccess
+ * Method: renameElement
+ * Signature: (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ */
+extern "C" SAL_JNI_EXPORT void JNICALL Java_com_sun_star_sdbcx_comp_hsqldb_StorageFileAccess_renameElement
+ (JNIEnv * env, jobject /*obj_this*/,jstring key, jstring oldname, jstring newname)
+{
+#ifdef HSQLDB_DBG
+ {
+ OUString sKey = StorageContainer::jstring2ustring(env,key);
+ OUString sNewName = StorageContainer::jstring2ustring(env,newname);
+ OUString sOldName = StorageContainer::jstring2ustring(env,oldname);
+ }
+#endif
+ TStorages::mapped_type aStoragePair = StorageContainer::getRegisteredStorage(StorageContainer::jstring2ustring(env,key));
+ auto storage = aStoragePair.mapStorage();
+ if ( !storage.is() )
+ return;
+
+ try
+ {
+ storage->renameElement(
+ StorageContainer::removeURLPrefix(StorageContainer::jstring2ustring(env,oldname),aStoragePair.url),
+ StorageContainer::removeURLPrefix(StorageContainer::jstring2ustring(env,newname),aStoragePair.url)
+ );
+#ifdef HSQLDB_DBG
+ {
+ OUString sNewName = StorageContainer::removeURLPrefix(StorageContainer::jstring2ustring(env,newname),aStoragePair.first.second);
+ OSL_ENSURE(aStoragePair.first.first->isStreamElement(sNewName),"Stream could not be renamed");
+ }
+#endif
+ }
+ catch(const NoSuchElementException&)
+ {
+ }
+ catch(const Exception& e)
+ {
+ TOOLS_WARN_EXCEPTION( "connectivity.hsqldb", "Java_com_sun_star_sdbcx_comp_hsqldb_StorageFileAccess_renameElement");
+ StorageContainer::throwJavaException(e,env);
+ }
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/hsqldb/StorageNativeInputStream.cxx b/connectivity/source/drivers/hsqldb/StorageNativeInputStream.cxx
new file mode 100644
index 0000000000..eaaf7dc033
--- /dev/null
+++ b/connectivity/source/drivers/hsqldb/StorageNativeInputStream.cxx
@@ -0,0 +1,292 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#if defined(HAVE_CONFIG_H) && HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <com/sun/star/io/XStream.hpp>
+#include <com/sun/star/document/XDocumentSubStorageSupplier.hpp>
+#include <hsqldb/HStorageAccess.hxx>
+#include <hsqldb/HStorageMap.hxx>
+
+#include <osl/diagnose.h>
+#include <comphelper/diagnose_ex.hxx>
+#include "accesslog.hxx"
+
+#include <limits>
+
+
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::document;
+using namespace ::com::sun::star::embed;
+using namespace ::com::sun::star::io;
+using namespace ::com::sun::star::lang;
+using namespace ::connectivity::hsqldb;
+
+/*****************************************************************************/
+/* exception macros */
+
+#define ThrowException(env, type, msg) { \
+ env->ThrowNew(env->FindClass(type), msg); }
+/*
+ * Class: com_sun_star_sdbcx_comp_hsqldb_StorageNativeInputStream
+ * Method: openStream
+ * Signature: (Ljava/lang/String;Ljava/lang/String;I)V
+ */
+extern "C" SAL_JNI_EXPORT void JNICALL Java_com_sun_star_sdbcx_comp_hsqldb_StorageNativeInputStream_openStream
+ (JNIEnv * env, jobject /*obj_this*/,jstring key, jstring name, jint mode)
+{
+#ifdef HSQLDB_DBG
+ {
+ OperationLogFile( env, name, "input" ).logOperation( "openStream" );
+ LogFile( env, name, "input" ).create();
+ }
+#endif
+ StorageContainer::registerStream(env,name,key,mode);
+}
+
+
+/*
+ * Class: com_sun_star_sdbcx_comp_hsqldb_StorageNativeInputStream
+ * Method: read
+ * Signature: (Ljava/lang/String;Ljava/lang/String;)I
+ */
+extern "C" SAL_JNI_EXPORT jint JNICALL Java_com_sun_star_sdbcx_comp_hsqldb_StorageNativeInputStream_read__Ljava_lang_String_2Ljava_lang_String_2
+ (JNIEnv * env, jobject /*obj_this*/, jstring key, jstring name)
+{
+#ifdef HSQLDB_DBG
+ OperationLogFile( env, name, "input" ).logOperation( "read()" );
+
+ DataLogFile aDataLog( env, name, "input" );
+ return read_from_storage_stream( env, obj_this, name, key, &aDataLog );
+#else
+ return read_from_storage_stream( env, name, key );
+#endif
+}
+
+
+/*
+ * Class: com_sun_star_sdbcx_comp_hsqldb_StorageNativeInputStream
+ * Method: read
+ * Signature: (Ljava/lang/String;Ljava/lang/String;[BII)I
+ */
+extern "C" SAL_JNI_EXPORT jint JNICALL Java_com_sun_star_sdbcx_comp_hsqldb_StorageNativeInputStream_read__Ljava_lang_String_2Ljava_lang_String_2_3BII
+ (JNIEnv * env, jobject obj_this, jstring key, jstring name, jbyteArray buffer, jint off, jint len)
+{
+#ifdef HSQLDB_DBG
+ OperationLogFile( env, name, "input" ).logOperation( "read( byte[], int, int )" );
+
+ DataLogFile aDataLog( env, name, "input" );
+ return read_from_storage_stream_into_buffer( env, obj_this, name, key, buffer, off, len, &aDataLog );
+#else
+ (void)obj_this;
+ return read_from_storage_stream_into_buffer(env, name,key,buffer,off,len);
+#endif
+}
+
+
+/*
+ * Class: com_sun_star_sdbcx_comp_hsqldb_StorageNativeInputStream
+ * Method: close
+ * Signature: (Ljava/lang/String;Ljava/lang/String;)V
+ */
+extern "C" SAL_JNI_EXPORT void JNICALL Java_com_sun_star_sdbcx_comp_hsqldb_StorageNativeInputStream_close
+ (JNIEnv * env, jobject /*obj_this*/,jstring key, jstring name)
+{
+#ifdef HSQLDB_DBG
+ OperationLogFile aOpLog( env, name, "input" );
+ aOpLog.logOperation( "close" );
+ aOpLog.close();
+
+ LogFile aDataLog( env, name, "input" );
+ aDataLog.close();
+#endif
+ StorageContainer::revokeStream(env,name,key);
+}
+
+
+/*
+ * Class: com_sun_star_sdbcx_comp_hsqldb_StorageNativeInputStream
+ * Method: skip
+ * Signature: (Ljava/lang/String;Ljava/lang/String;J)J
+ */
+extern "C" SAL_JNI_EXPORT jlong JNICALL Java_com_sun_star_sdbcx_comp_hsqldb_StorageNativeInputStream_skip
+ (JNIEnv * env, jobject /*obj_this*/,jstring key, jstring name, jlong n)
+{
+#ifdef HSQLDB_DBG
+ OperationLogFile( env, name, "input" ).logOperation( "skip()" );
+#endif
+
+ if ( n < 0 )
+ ThrowException( env,
+ "java/io/IOException",
+ "n < 0");
+
+ std::shared_ptr<StreamHelper> pHelper = StorageContainer::getRegisteredStream(env,name,key);
+ OSL_ENSURE(pHelper,"No stream helper!");
+ if ( pHelper )
+ {
+ Reference<XInputStream> xIn = pHelper->getInputStream();
+ if ( xIn.is() )
+ {
+ try
+ {
+ sal_Int64 tmpLongVal = n;
+ sal_Int32 tmpIntVal;
+
+ try
+ {
+ do {
+ if (tmpLongVal >= std::numeric_limits<sal_Int64>::max() )
+ tmpIntVal = std::numeric_limits<sal_Int32>::max();
+ else // Casting is safe here.
+ tmpIntVal = static_cast<sal_Int32>(tmpLongVal);
+
+ tmpLongVal -= tmpIntVal;
+
+ xIn->skipBytes(tmpIntVal);
+
+ } while (tmpLongVal > 0);
+ }
+ catch(const Exception&)
+ {
+ }
+
+ return n - tmpLongVal;
+ }
+ catch(const Exception& e)
+ {
+ TOOLS_WARN_EXCEPTION( "connectivity.hsqldb", "skip();");
+ StorageContainer::throwJavaException(e,env);
+ }
+ }
+ }
+ else
+ {
+ ThrowException( env,
+ "java/io/IOException",
+ "Stream is not valid");
+ }
+ return 0;
+}
+
+
+/*
+ * Class: com_sun_star_sdbcx_comp_hsqldb_StorageNativeInputStream
+ * Method: available
+ * Signature: (Ljava/lang/String;Ljava/lang/String;)I
+ */
+extern "C" SAL_JNI_EXPORT jint JNICALL Java_com_sun_star_sdbcx_comp_hsqldb_StorageNativeInputStream_available
+ (JNIEnv * env, jobject /*obj_this*/,jstring key, jstring name)
+{
+#ifdef HSQLDB_DBG
+ OperationLogFile aOpLog( env, name, "input" );
+ aOpLog.logOperation( "available" );
+#endif
+
+ std::shared_ptr<StreamHelper> pHelper = StorageContainer::getRegisteredStream(env,name,key);
+ OSL_ENSURE(pHelper,"No stream helper!");
+ Reference<XInputStream> xIn = pHelper ? pHelper->getInputStream() : Reference<XInputStream>();
+ if ( xIn.is() )
+ {
+ try
+ {
+ jint nAvailable = xIn->available();
+#ifdef HSQLDB_DBG
+ aOpLog.logReturn( nAvailable );
+#endif
+ return nAvailable;
+ }
+ catch(const Exception& e)
+ {
+ TOOLS_WARN_EXCEPTION( "connectivity.hsqldb", "available();");
+ StorageContainer::throwJavaException(e,env);
+ }
+ }
+ else
+ {
+ ThrowException( env,
+ "java/io/IOException",
+ "Stream is not valid");
+ }
+ return 0;
+}
+
+
+/*
+ * Class: com_sun_star_sdbcx_comp_hsqldb_StorageNativeInputStream
+ * Method: read
+ * Signature: (Ljava/lang/String;Ljava/lang/String;[B)I
+ */
+extern "C" SAL_JNI_EXPORT jint JNICALL Java_com_sun_star_sdbcx_comp_hsqldb_StorageNativeInputStream_read__Ljava_lang_String_2Ljava_lang_String_2_3B
+ (JNIEnv * env, jobject /*obj_this*/,jstring key, jstring name, jbyteArray buffer)
+{
+#ifdef HSQLDB_DBG
+ OperationLogFile aOpLog( env, name, "input" );
+ aOpLog.logOperation( "read( byte[] )" );
+
+ DataLogFile aDataLog( env, name, "input" );
+#endif
+
+ std::shared_ptr<StreamHelper> pHelper = StorageContainer::getRegisteredStream(env,name,key);
+ Reference< XInputStream> xIn = pHelper ? pHelper->getInputStream() : Reference< XInputStream>();
+ OSL_ENSURE(xIn.is(),"Input stream is NULL!");
+ jint nBytesRead = 0;
+ if ( xIn.is() )
+ {
+ jsize nLen = env->GetArrayLength(buffer);
+ Sequence< ::sal_Int8 > aData(nLen);
+
+ try
+ {
+ nBytesRead = xIn->readBytes(aData,nLen);
+ }
+ catch(const Exception& e)
+ {
+ TOOLS_WARN_EXCEPTION( "connectivity.hsqldb", "skip();");
+ StorageContainer::throwJavaException(e,env);
+ }
+
+ // Casting bytesRead to an int is okay, since the user can
+ // only pass in an integer length to read, so the bytesRead
+ // must <= len.
+
+ if (nBytesRead <= 0) {
+#ifdef HSQLDB_DBG
+ aOpLog.logReturn( (jint)-1 );
+#endif
+ return -1;
+ }
+ OSL_ENSURE(nLen >= nBytesRead,"Buffer is too small!");
+ OSL_ENSURE(aData.getLength() >= nBytesRead,"Buffer is too small!");
+ env->SetByteArrayRegion(buffer, 0, nBytesRead, reinterpret_cast<const jbyte*>(&aData[0]));
+#ifdef HSQLDB_DBG
+ aDataLog.write( &aData[0], nBytesRead );
+#endif
+ }
+#ifdef HSQLDB_DBG
+ aOpLog.logReturn( nBytesRead );
+#endif
+ return nBytesRead;
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/hsqldb/StorageNativeOutputStream.cxx b/connectivity/source/drivers/hsqldb/StorageNativeOutputStream.cxx
new file mode 100644
index 0000000000..f766696e0d
--- /dev/null
+++ b/connectivity/source/drivers/hsqldb/StorageNativeOutputStream.cxx
@@ -0,0 +1,195 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#if defined(HAVE_CONFIG_H) && HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <cppuhelper/bootstrap.hxx>
+#include <osl/diagnose.h>
+#include "accesslog.hxx"
+#include <com/sun/star/embed/XTransactedObject.hpp>
+#include <com/sun/star/io/XStream.hpp>
+#include <com/sun/star/document/XDocumentSubStorageSupplier.hpp>
+#include <hsqldb/HStorageAccess.hxx>
+#include <hsqldb/HStorageMap.hxx>
+
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::document;
+using namespace ::com::sun::star::embed;
+using namespace ::com::sun::star::io;
+using namespace ::com::sun::star::lang;
+using namespace ::connectivity::hsqldb;
+
+
+/*
+ * Class: com_sun_star_sdbcx_comp_hsqldb_StorageNativeOutputStream
+ * Method: openStream
+ * Signature: (Ljava/lang/String;Ljava/lang/String;I)V
+ */
+extern "C" SAL_JNI_EXPORT void JNICALL Java_com_sun_star_sdbcx_comp_hsqldb_StorageNativeOutputStream_openStream
+ (JNIEnv * env, jobject /*obj_this*/, jstring name, jstring key, jint mode)
+{
+#ifdef HSQLDB_DBG
+ {
+ OperationLogFile( env, name, "output" ).logOperation( "openStream" );
+ LogFile( env, name, "output" ).create();
+ }
+#endif
+ StorageContainer::registerStream(env,name,key,mode);
+}
+/*
+ * Class: com_sun_star_sdbcx_comp_hsqldb_StorageNativeOutputStream
+ * Method: write
+ * Signature: (Ljava/lang/String;Ljava/lang/String;[BII)V
+ */
+extern "C" SAL_JNI_EXPORT void JNICALL Java_com_sun_star_sdbcx_comp_hsqldb_StorageNativeOutputStream_write__Ljava_lang_String_2Ljava_lang_String_2_3BII
+ (JNIEnv * env, jobject obj_this, jstring key, jstring name, jbyteArray buffer, jint off, jint len)
+{
+#ifdef HSQLDB_DBG
+ OperationLogFile( env, name, "output" ).logOperation( "write( byte[], int, int )" );
+
+ DataLogFile aDataLog( env, name, "output" );
+ write_to_storage_stream_from_buffer( env, obj_this, name, key, buffer, off, len, &aDataLog );
+#else
+ (void)obj_this;
+ write_to_storage_stream_from_buffer( env, name, key, buffer, off, len );
+#endif
+}
+
+/*
+ * Class: com_sun_star_sdbcx_comp_hsqldb_StorageNativeOutputStream
+ * Method: write
+ * Signature: (Ljava/lang/String;Ljava/lang/String;[B)V
+ */
+extern "C" SAL_JNI_EXPORT void JNICALL Java_com_sun_star_sdbcx_comp_hsqldb_StorageNativeOutputStream_write__Ljava_lang_String_2Ljava_lang_String_2_3B
+ (JNIEnv * env, jobject obj_this, jstring key, jstring name, jbyteArray buffer)
+{
+#ifdef HSQLDB_DBG
+ OperationLogFile( env, name, "output" ).logOperation( "write( byte[] )" );
+
+ DataLogFile aDataLog( env, name, "output" );
+ write_to_storage_stream_from_buffer( env, obj_this, name, key, buffer, 0, env->GetArrayLength( buffer ), &aDataLog );
+#else
+ (void)obj_this;
+ write_to_storage_stream_from_buffer( env, name, key, buffer, 0, env->GetArrayLength( buffer ) );
+#endif
+}
+
+/*
+ * Class: com_sun_star_sdbcx_comp_hsqldb_StorageNativeOutputStream
+ * Method: close
+ * Signature: (Ljava/lang/String;Ljava/lang/String;)V
+ */
+extern "C" SAL_JNI_EXPORT void JNICALL Java_com_sun_star_sdbcx_comp_hsqldb_StorageNativeOutputStream_close
+ (JNIEnv * env, jobject /*obj_this*/, jstring key, jstring name)
+{
+#ifdef HSQLDB_DBG
+ OperationLogFile aOpLog( env, name, "output" );
+ aOpLog.logOperation( "close" );
+
+ LogFile aDataLog( env, name, "output" );
+#endif
+
+ std::shared_ptr<StreamHelper> pHelper = StorageContainer::getRegisteredStream(env,name,key);
+ Reference< XOutputStream> xFlush = pHelper ? pHelper->getOutputStream() : Reference< XOutputStream>();
+ if ( xFlush.is() )
+ try
+ {
+ xFlush->flush();
+ }
+ catch(Exception&)
+ {}
+
+#ifdef HSQLDB_DBG
+ aDataLog.close();
+ aOpLog.close();
+#endif
+ StorageContainer::revokeStream(env,name,key);
+}
+
+/*
+ * Class: com_sun_star_sdbcx_comp_hsqldb_StorageNativeOutputStream
+ * Method: write
+ * Signature: (Ljava/lang/String;Ljava/lang/String;I)V
+ */
+extern "C" SAL_JNI_EXPORT void JNICALL Java_com_sun_star_sdbcx_comp_hsqldb_StorageNativeOutputStream_write__Ljava_lang_String_2Ljava_lang_String_2I
+ (JNIEnv * env, jobject obj_this, jstring key, jstring name,jint b)
+{
+#ifdef HSQLDB_DBG
+ OperationLogFile( env, name, "output" ).logOperation( "write( int )" );
+
+ DataLogFile aDataLog( env, name, "output" );
+ write_to_storage_stream( env, name, key, b, &aDataLog );
+#else
+ (void)obj_this;
+ write_to_storage_stream( env, name, key, b );
+#endif
+}
+
+/*
+ * Class: com_sun_star_sdbcx_comp_hsqldb_StorageNativeOutputStream
+ * Method: flush
+ * Signature: (Ljava/lang/String;Ljava/lang/String;)V
+ */
+extern "C" SAL_JNI_EXPORT void JNICALL Java_com_sun_star_sdbcx_comp_hsqldb_StorageNativeOutputStream_flush
+ (JNIEnv * env, jobject /*obj_this*/, jstring key, jstring name)
+{
+#ifdef HSQLDB_DBG
+ OperationLogFile( env, name, "output" ).logOperation( "flush" );
+
+ OUString sKey = StorageContainer::jstring2ustring(env,key);
+ OUString sName = StorageContainer::jstring2ustring(env,name);
+#else
+ (void) env;
+ (void) key;
+ (void) name;
+#endif
+}
+
+/*
+ * Class: com_sun_star_sdbcx_comp_hsqldb_StorageNativeOutputStream
+ * Method: sync
+ * Signature: (Ljava/lang/String;Ljava/lang/String;)V
+ */
+extern "C" SAL_JNI_EXPORT void JNICALL Java_com_sun_star_sdbcx_comp_hsqldb_StorageNativeOutputStream_sync
+ (JNIEnv * env, jobject /*obj_this*/, jstring key, jstring name)
+{
+#ifdef HSQLDB_DBG
+ OperationLogFile( env, name, "output" ).logOperation( "sync" );
+#endif
+ std::shared_ptr< StreamHelper > pStream = StorageContainer::getRegisteredStream( env, name, key );
+ Reference< XOutputStream > xFlush = pStream ? pStream->getOutputStream() : Reference< XOutputStream>();
+ OSL_ENSURE( xFlush.is(), "StorageNativeOutputStream::sync: could not retrieve an output stream!" );
+ if ( xFlush.is() )
+ {
+ try
+ {
+ xFlush->flush();
+ }
+ catch(Exception&)
+ {
+ OSL_FAIL( "StorageNativeOutputStream::sync: could not flush output stream!" );
+ }
+ }
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/hsqldb/accesslog.cxx b/connectivity/source/drivers/hsqldb/accesslog.cxx
new file mode 100644
index 0000000000..f7e0f10ee1
--- /dev/null
+++ b/connectivity/source/drivers/hsqldb/accesslog.cxx
@@ -0,0 +1,78 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#ifdef HSQLDB_DBG
+
+#include <map>
+
+#include "accesslog.hxx"
+#include "hsqldb/HStorageMap.hxx"
+
+#include <osl/thread.h>
+
+namespace connectivity::hsqldb
+{
+ typedef std::map<OUString, FILE *> TDebugStreamMap;
+ TDebugStreamMap& getStreams()
+ {
+ static TDebugStreamMap streams;
+ return streams;
+ }
+
+
+ LogFile::LogFile( JNIEnv* env, jstring streamName, const char* _pAsciiSuffix )
+ : m_sFileName(StorageContainer::jstring2ustring(env,streamName) +
+ "." + OUString::createFromAscii( _pAsciiSuffix ) )
+ {
+ }
+
+
+ FILE*& LogFile::getLogFile()
+ {
+ FILE*& pLogFile = getStreams()[m_sFileName];
+ if ( !pLogFile )
+ {
+ OString sByteLogName = OUStringToOString(m_sFileName,osl_getThreadTextEncoding());
+ pLogFile = fopen( sByteLogName.getStr(), "a+" );
+ }
+ return pLogFile;
+ }
+
+
+ void LogFile::writeString( const char* _pString, bool _bEndLine )
+ {
+ FILE* pLogFile = getLogFile();
+ fwrite( _pString, sizeof( *_pString ), strlen( _pString ), pLogFile );
+ if ( _bEndLine )
+ fwrite( "\n", sizeof( *_pString ), strlen( "\n" ), pLogFile );
+ fflush( pLogFile );
+ }
+
+
+ void LogFile::close()
+ {
+ fclose( getLogFile() );
+ getLogFile() = NULL;
+ }
+} }
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/hsqldb/accesslog.hxx b/connectivity/source/drivers/hsqldb/accesslog.hxx
new file mode 100644
index 0000000000..81db98ae77
--- /dev/null
+++ b/connectivity/source/drivers/hsqldb/accesslog.hxx
@@ -0,0 +1,135 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#ifdef HSQLDB_DBG
+
+#include <jni.h>
+#include <rtl/ustring.hxx>
+#include <rtl/string.hxx>
+
+namespace connectivity::hsqldb
+{
+ class LogFile
+ {
+ private:
+ OUString m_sFileName;
+
+ public:
+ LogFile( JNIEnv* env, jstring streamName, const char* _pAsciiSuffix );
+
+ public:
+ void writeString( const char* _pString, bool _bEndLine = true );
+ void create() { getLogFile(); }
+ virtual void close();
+
+ protected:
+ FILE*& getLogFile();
+ };
+
+ class OperationLogFile : public LogFile
+ {
+ public:
+ OperationLogFile( JNIEnv* env, jstring streamName, const char* _pAsciiSuffix )
+ :LogFile( env, streamName, ( OString( _pAsciiSuffix ) += ".op" ).getStr() )
+ {
+ }
+
+ void logOperation( const char* _pOp )
+ {
+ writeString( _pOp, true );
+ }
+
+ void logOperation( const char* _pOp, jlong _nLongArg )
+ {
+ OString sLine( _pOp );
+ sLine += "( ";
+ sLine += OString::number( _nLongArg );
+ sLine += " )";
+ writeString( sLine.getStr(), true );
+ }
+
+ void logReturn( jlong _nRetVal )
+ {
+ OString sLine( " -> " );
+ sLine += OString::number( _nRetVal );
+ writeString( sLine.getStr(), true );
+ }
+
+ void logReturn( jint _nRetVal )
+ {
+ OString sLine( " -> " );
+ sLine += OString::number( _nRetVal );
+ writeString( sLine.getStr(), true );
+ }
+
+ virtual void close()
+ {
+ writeString( "-------------------------------", true );
+ writeString( "", true );
+ LogFile::close();
+ }
+ };
+
+ class DataLogFile : public LogFile
+ {
+ public:
+ DataLogFile( JNIEnv* env, jstring streamName, const char* _pAsciiSuffix )
+ :LogFile( env, streamName, _pAsciiSuffix )
+ {
+ }
+
+ void write( jint value )
+ {
+ fputc( value, getLogFile() );
+ fflush( getLogFile() );
+ }
+
+ void write( const sal_Int8* buffer, sal_Int32 bytesRead )
+ {
+ fwrite( buffer, sizeof(sal_Int8), bytesRead, getLogFile() );
+ fflush( getLogFile() );
+ }
+
+ sal_Int64 seek( sal_Int64 pos )
+ {
+ FILE* pFile = getLogFile();
+ fseek( pFile, 0, SEEK_END );
+ if ( ftell( pFile ) < pos )
+ {
+ sal_Int8 filler( 0 );
+ while ( ftell( pFile ) < pos )
+ fwrite( &filler, sizeof( sal_Int8 ), 1, pFile );
+ fflush( pFile );
+ }
+ fseek( pFile, pos, SEEK_SET );
+ return ftell( pFile );
+ }
+
+ sal_Int64 tell()
+ {
+ return ftell( getLogFile() );
+ }
+ };
+
+} }
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/hsqldb/hsqldb.component b/connectivity/source/drivers/hsqldb/hsqldb.component
new file mode 100644
index 0000000000..a541e02aa8
--- /dev/null
+++ b/connectivity/source/drivers/hsqldb/hsqldb.component
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ -->
+
+<component loader="com.sun.star.loader.SharedLibrary" environment="@CPPU_ENV@"
+ xmlns="http://openoffice.org/2010/uno-components">
+ <implementation name="com.sun.star.sdbcx.comp.hsqldb.Driver"
+ constructor="connectivity_hsqldb_ODriverDelegator_implementation">
+ <service name="com.sun.star.sdbc.Driver"/>
+ <service name="com.sun.star.sdbcx.Driver"/>
+ </implementation>
+</component>
diff --git a/connectivity/source/drivers/jdbc/Array.cxx b/connectivity/source/drivers/jdbc/Array.cxx
new file mode 100644
index 0000000000..d03b019283
--- /dev/null
+++ b/connectivity/source/drivers/jdbc/Array.cxx
@@ -0,0 +1,132 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <java/sql/Array.hxx>
+#include <java/tools.hxx>
+#include <osl/diagnose.h>
+
+using namespace connectivity;
+
+//************ Class: java.sql.Array
+
+
+jclass java_sql_Array::theClass = nullptr;
+
+java_sql_Array::~java_sql_Array()
+{}
+
+jclass java_sql_Array::getMyClass() const
+{
+ // the class must be fetched once, therefore it's static
+ if( !theClass )
+ theClass = findMyClass("java/sql/Array");
+
+ return theClass;
+}
+
+OUString SAL_CALL java_sql_Array::getBaseTypeName( )
+{
+ static jmethodID mID(nullptr);
+ return callStringMethod("getBaseTypeName",mID);
+}
+
+sal_Int32 SAL_CALL java_sql_Array::getBaseType( )
+{
+ static jmethodID mID(nullptr);
+ return callIntMethod_ThrowSQL("getBaseType", mID);
+}
+
+css::uno::Sequence< css::uno::Any > SAL_CALL java_sql_Array::getArray( const css::uno::Reference< css::container::XNameAccess >& typeMap )
+{
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+ {
+ jobject obj = convertTypeMapToJavaMap(typeMap);
+ static const char * const cSignature = "(Ljava/util/Map;)[Ljava/lang/Object;";
+ static const char * const cMethodName = "getArray";
+ static jmethodID mID(nullptr);
+ obtainMethodId_throwSQL(t.pEnv, cMethodName,cSignature, mID);
+ // submit Java-Call
+ t.pEnv->CallObjectMethod( object, mID, obj);
+ ThrowSQLException(t.pEnv,*this);
+ // and clean up
+ t.pEnv->DeleteLocalRef(obj);
+ } //t.pEnv
+ return css::uno::Sequence< css::uno::Any >();
+}
+
+css::uno::Sequence< css::uno::Any > SAL_CALL java_sql_Array::getArrayAtIndex( sal_Int32 index, sal_Int32 count, const css::uno::Reference< css::container::XNameAccess >& typeMap )
+{
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+ {
+ jobject obj = convertTypeMapToJavaMap(typeMap);
+ static const char * const cSignature = "(IILjava/util/Map;)[Ljava/lang/Object;";
+ static const char * const cMethodName = "getArray";
+ // submit Java-Call
+ static jmethodID mID(nullptr);
+ obtainMethodId_throwSQL(t.pEnv, cMethodName,cSignature, mID);
+ t.pEnv->CallObjectMethod( object, mID, index,count,obj);
+ ThrowSQLException(t.pEnv,*this);
+ // and clean up
+ t.pEnv->DeleteLocalRef(obj);
+ }
+ return css::uno::Sequence< css::uno::Any >();
+}
+
+css::uno::Reference< css::sdbc::XResultSet > SAL_CALL java_sql_Array::getResultSet( const css::uno::Reference< css::container::XNameAccess >& typeMap )
+{
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+ {
+ // convert Parameter
+ jobject obj = convertTypeMapToJavaMap(typeMap);
+ // initialize temporary variable
+ static const char * const cSignature = "(Ljava/util/Map;)Ljava/sql/ResultSet;";
+ static const char * const cMethodName = "getResultSet";
+ // submit Java-Call
+ static jmethodID mID(nullptr);
+ obtainMethodId_throwSQL(t.pEnv, cMethodName,cSignature, mID);
+ t.pEnv->CallObjectMethod( object, mID, obj);
+ ThrowSQLException(t.pEnv,*this);
+ // and cleanup
+ t.pEnv->DeleteLocalRef(obj);
+ }
+ return nullptr;
+}
+
+css::uno::Reference< css::sdbc::XResultSet > SAL_CALL java_sql_Array::getResultSetAtIndex( sal_Int32 index, sal_Int32 count, const css::uno::Reference< css::container::XNameAccess >& typeMap )
+{
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+ {
+ // convert parameter
+ jobject obj = convertTypeMapToJavaMap(typeMap);
+ // initialize temporary variable
+ static const char * const cSignature = "(Ljava/util/Map;)Ljava/sql/ResultSet;";
+ static const char * const cMethodName = "getResultSetAtIndex";
+ // submit Java-Call
+ static jmethodID mID(nullptr);
+ obtainMethodId_throwSQL(t.pEnv, cMethodName,cSignature, mID);
+ t.pEnv->CallObjectMethod( object, mID, index,count,obj);
+ ThrowSQLException(t.pEnv,*this);
+ // and cleanup
+ t.pEnv->DeleteLocalRef(obj);
+ }
+ return nullptr;
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/jdbc/Blob.cxx b/connectivity/source/drivers/jdbc/Blob.cxx
new file mode 100644
index 0000000000..4531fc9b87
--- /dev/null
+++ b/connectivity/source/drivers/jdbc/Blob.cxx
@@ -0,0 +1,144 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <java/sql/Blob.hxx>
+#include <java/io/InputStream.hxx>
+#include <connectivity/dbexception.hxx>
+#include <osl/diagnose.h>
+
+#include <string.h>
+
+using namespace connectivity;
+
+//************ Class: java.sql.Blob
+
+
+jclass java_sql_Blob::theClass = nullptr;
+java_sql_Blob::java_sql_Blob( JNIEnv * pEnv, jobject myObj )
+ : java_lang_Object( pEnv, myObj )
+{
+ SDBThreadAttach::addRef();
+}
+java_sql_Blob::~java_sql_Blob()
+{
+ SDBThreadAttach::releaseRef();
+}
+
+jclass java_sql_Blob::getMyClass() const
+{
+ // the class must be fetched only once, therefore it's static
+ if( !theClass )
+ theClass = findMyClass("java/sql/Blob");
+ return theClass;
+}
+
+sal_Int64 SAL_CALL java_sql_Blob::length( )
+{
+ jlong out(0);
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+
+ {
+ // initialize temporary variable
+ static const char * const cSignature = "()J";
+ static const char * const cMethodName = "length";
+ // submit Java-Call
+ static jmethodID mID(nullptr);
+ obtainMethodId_throwSQL(t.pEnv, cMethodName,cSignature, mID);
+ out = t.pEnv->CallLongMethod( object, mID );
+ ThrowSQLException(t.pEnv,*this);
+ } //t.pEnv
+ return static_cast<sal_Int64>(out);
+}
+css::uno::Sequence< sal_Int8 > SAL_CALL java_sql_Blob::getBytes( sal_Int64 pos, sal_Int32 count )
+{
+
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+ css::uno::Sequence< sal_Int8 > aSeq;
+ {
+ // initialize temporary variable
+ static const char * const cSignature = "(JI)[B";
+ static const char * const cMethodName = "getBytes";
+ // submit Java-Call
+ static jmethodID mID(nullptr);
+ obtainMethodId_throwSQL(t.pEnv, cMethodName,cSignature, mID);
+ jbyteArray out = static_cast<jbyteArray>(t.pEnv->CallObjectMethod( object, mID,pos,count));
+ ThrowSQLException(t.pEnv,*this);
+ if(out)
+ {
+ jboolean p = false;
+ aSeq.realloc(t.pEnv->GetArrayLength(out));
+ memcpy(aSeq.getArray(),t.pEnv->GetByteArrayElements(out,&p),aSeq.getLength());
+ t.pEnv->DeleteLocalRef(out);
+ }
+ } //t.pEnv
+ // WARNING: the caller becomes the owner of the returned pointer
+ return aSeq;
+}
+
+css::uno::Reference< css::io::XInputStream > SAL_CALL java_sql_Blob::getBinaryStream( )
+{
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+ static jmethodID mID(nullptr);
+ jobject out = callObjectMethod(t.pEnv,"getBinaryStream","()Ljava/io/InputStream;", mID);
+ // WARNING: the caller becomes the owner of the returned pointer
+ return out==nullptr ? nullptr : new java_io_InputStream( t.pEnv, out );
+}
+
+sal_Int64 SAL_CALL java_sql_Blob::position( const css::uno::Sequence< sal_Int8 >& pattern, sal_Int64 start )
+{
+ jlong out(0);
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+
+ {
+ // initialize temporary variable
+ static const char * const cSignature = "([BI)J";
+ static const char * const cMethodName = "position";
+ // submit Java-Call
+ static jmethodID mID(nullptr);
+ obtainMethodId_throwSQL(t.pEnv, cMethodName,cSignature, mID);
+ // convert Parameter
+ jbyteArray pByteArray = t.pEnv->NewByteArray(pattern.getLength());
+ jbyte * patternData = reinterpret_cast<jbyte *>(
+ const_cast<sal_Int8 *>(pattern.getConstArray()));
+ // 4th param of Set*ArrayRegion changed from pointer to non-const to
+ // pointer to const between <http://docs.oracle.com/javase/6/docs/
+ // technotes/guides/jni/spec/functions.html#wp22933> and
+ // <http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/
+ // functions.html#wp22933>; work around that difference in a way
+ // that doesn't trigger loplugin:redundantcast
+ t.pEnv->SetByteArrayRegion(pByteArray,0,pattern.getLength(),patternData);
+ out = t.pEnv->CallLongMethod( object, mID, pByteArray,start );
+ t.pEnv->DeleteLocalRef(pByteArray);
+ ThrowSQLException(t.pEnv,*this);
+ } //t.pEnv
+ return static_cast<sal_Int64>(out);
+}
+
+sal_Int64 SAL_CALL java_sql_Blob::positionOfBlob( const css::uno::Reference< css::sdbc::XBlob >& /*pattern*/, sal_Int64 /*start*/ )
+{
+ ::dbtools::throwFeatureNotImplementedSQLException( "XBlob::positionOfBlob", *this );
+ // this was put here in CWS warnings01. The previous implementation was defective, as it did ignore
+ // the pattern parameter. Since the effort for proper implementation is rather high - we would need
+ // to translated pattern into a byte[] -, we defer this functionality for the moment (hey, it was
+ // unusable, anyway)
+ // #i57457#
+ return 0;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/jdbc/Boolean.cxx b/connectivity/source/drivers/jdbc/Boolean.cxx
new file mode 100644
index 0000000000..5709674f35
--- /dev/null
+++ b/connectivity/source/drivers/jdbc/Boolean.cxx
@@ -0,0 +1,38 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <java/lang/Boolean.hxx>
+using namespace connectivity;
+
+//************ Class: java.lang.Boolean
+
+jclass java_lang_Boolean::theClass = nullptr;
+
+java_lang_Boolean::~java_lang_Boolean() {}
+jclass java_lang_Boolean::st_getMyClass()
+{
+ // the class must be fetched only once, therefore static
+ if (!theClass)
+ theClass = findMyClass("java/lang/Boolean");
+ return theClass;
+}
+
+jclass java_lang_Boolean::getMyClass() const { return st_getMyClass(); }
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/jdbc/CallableStatement.cxx b/connectivity/source/drivers/jdbc/CallableStatement.cxx
new file mode 100644
index 0000000000..884de3d4ce
--- /dev/null
+++ b/connectivity/source/drivers/jdbc/CallableStatement.cxx
@@ -0,0 +1,354 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <java/sql/CallableStatement.hxx>
+#include <java/tools.hxx>
+#include <java/sql/Array.hxx>
+#include <java/sql/Clob.hxx>
+#include <java/sql/Blob.hxx>
+#include <java/sql/Connection.hxx>
+#include <java/sql/Ref.hxx>
+#include <java/sql/Timestamp.hxx>
+#include <cppuhelper/typeprovider.hxx>
+#include <cppuhelper/queryinterface.hxx>
+#include <comphelper/sequence.hxx>
+
+#include <string.h>
+
+using namespace connectivity;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+
+
+IMPLEMENT_SERVICE_INFO(java_sql_CallableStatement,"com.sun.star.sdbcx.ACallableStatement","com.sun.star.sdbc.CallableStatement");
+
+
+//************ Class: java.sql.CallableStatement
+
+java_sql_CallableStatement::java_sql_CallableStatement( JNIEnv * pEnv, java_sql_Connection& _rCon,const OUString& sql )
+ : java_sql_PreparedStatement( pEnv, _rCon, sql )
+{
+}
+
+java_sql_CallableStatement::~java_sql_CallableStatement()
+{
+}
+
+
+Any SAL_CALL java_sql_CallableStatement::queryInterface( const Type & rType )
+{
+ Any aRet = java_sql_PreparedStatement::queryInterface(rType);
+ return aRet.hasValue() ? aRet : ::cppu::queryInterface(rType,static_cast< css::sdbc::XRow*>(this),static_cast< css::sdbc::XOutParameters*>(this));
+}
+
+css::uno::Sequence< css::uno::Type > SAL_CALL java_sql_CallableStatement::getTypes( )
+{
+ ::cppu::OTypeCollection aTypes( cppu::UnoType<css::sdbc::XRow>::get(),
+ cppu::UnoType<css::sdbc::XOutParameters>::get());
+
+ return ::comphelper::concatSequences(aTypes.getTypes(),java_sql_PreparedStatement::getTypes());
+}
+
+sal_Bool SAL_CALL java_sql_CallableStatement::wasNull( )
+{
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+ createStatement(t.pEnv);
+ static jmethodID mID(nullptr);
+ return callBooleanMethod( "wasNull", mID );
+}
+
+sal_Bool SAL_CALL java_sql_CallableStatement::getBoolean( sal_Int32 columnIndex )
+{
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+ createStatement(t.pEnv);
+ static jmethodID mID(nullptr);
+ return callBooleanMethodWithIntArg( "getBoolean", mID,columnIndex );
+}
+sal_Int8 SAL_CALL java_sql_CallableStatement::getByte( sal_Int32 columnIndex )
+{
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+ createStatement(t.pEnv);
+ static jmethodID mID(nullptr);
+ jbyte (JNIEnv::* const pCallMethod)( jobject obj, jmethodID methodID, ... ) = &JNIEnv::CallByteMethod;
+ return callMethodWithIntArg<jbyte>(pCallMethod,"getByte","(I)B",mID,columnIndex);
+}
+Sequence< sal_Int8 > SAL_CALL java_sql_CallableStatement::getBytes( sal_Int32 columnIndex )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(java_sql_Statement_BASE::rBHelper.bDisposed);
+ Sequence< sal_Int8 > aSeq;
+
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+ createStatement(t.pEnv);
+ static jmethodID mID(nullptr);
+ jbyteArray out = static_cast<jbyteArray>(callObjectMethodWithIntArg(t.pEnv,"getBytes","(I)[B", mID, columnIndex));
+ if (out)
+ {
+ jboolean p = false;
+ aSeq.realloc(t.pEnv->GetArrayLength(out));
+ memcpy(aSeq.getArray(),t.pEnv->GetByteArrayElements(out,&p),aSeq.getLength());
+ t.pEnv->DeleteLocalRef(out);
+ }
+ return aSeq;
+}
+css::util::Date SAL_CALL java_sql_CallableStatement::getDate( sal_Int32 columnIndex )
+{
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+ createStatement(t.pEnv);
+ static jmethodID mID(nullptr);
+ jobject out = callObjectMethodWithIntArg(t.pEnv,"getDate","(I)Ljava/sql/Date;", mID, columnIndex);
+ return out ? static_cast <css::util::Date>(java_sql_Date( t.pEnv, out )) : css::util::Date();
+}
+double SAL_CALL java_sql_CallableStatement::getDouble( sal_Int32 columnIndex )
+{
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+ createStatement(t.pEnv);
+ static jmethodID mID(nullptr);
+ double (JNIEnv::* const pCallMethod)( jobject obj, jmethodID methodID, ... ) = &JNIEnv::CallDoubleMethod;
+ return callMethodWithIntArg<double>(pCallMethod,"getDouble","(I)D",mID,columnIndex);
+}
+
+float SAL_CALL java_sql_CallableStatement::getFloat( sal_Int32 columnIndex )
+{
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+ createStatement(t.pEnv);
+ static jmethodID mID(nullptr);
+ jfloat (JNIEnv::* const pCallMethod)( jobject obj, jmethodID methodID, ... ) = &JNIEnv::CallFloatMethod;
+ return callMethodWithIntArg<jfloat>(pCallMethod,"getFloat","(I)F",mID,columnIndex);
+}
+
+sal_Int32 SAL_CALL java_sql_CallableStatement::getInt( sal_Int32 columnIndex )
+{
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+ createStatement(t.pEnv);
+ static jmethodID mID(nullptr);
+ return callIntMethodWithIntArg_ThrowSQL("getInt",mID,columnIndex);
+}
+
+sal_Int64 SAL_CALL java_sql_CallableStatement::getLong( sal_Int32 columnIndex )
+{
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+ createStatement(t.pEnv);
+ static jmethodID mID(nullptr);
+ jlong (JNIEnv::* const pCallMethod)( jobject obj, jmethodID methodID, ... ) = &JNIEnv::CallLongMethod;
+ return callMethodWithIntArg<jlong>(pCallMethod,"getLong","(I)J",mID,columnIndex);
+}
+
+Any SAL_CALL java_sql_CallableStatement::getObject( sal_Int32 columnIndex, const Reference< css::container::XNameAccess >& /*typeMap*/ )
+{
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+ createStatement(t.pEnv);
+ static jmethodID mID(nullptr);
+ callObjectMethodWithIntArg(t.pEnv,"getObject","(I)Ljava/lang/Object;", mID, columnIndex);
+ // WARNING: the caller becomes the owner of the returned pointer
+ return Any();
+}
+
+sal_Int16 SAL_CALL java_sql_CallableStatement::getShort( sal_Int32 columnIndex )
+{
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+ createStatement(t.pEnv);
+ static jmethodID mID(nullptr);
+ jshort (JNIEnv::* const pCallMethod)( jobject obj, jmethodID methodID, ... ) = &JNIEnv::CallShortMethod;
+ return callMethodWithIntArg<jshort>(pCallMethod,"getShort","(I)S",mID,columnIndex);
+}
+
+OUString SAL_CALL java_sql_CallableStatement::getString( sal_Int32 columnIndex )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(java_sql_Statement_BASE::rBHelper.bDisposed);
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+ createStatement(t.pEnv);
+ static jmethodID mID(nullptr);
+ return callStringMethodWithIntArg("getString",mID,columnIndex);
+}
+
+ css::util::Time SAL_CALL java_sql_CallableStatement::getTime( sal_Int32 columnIndex )
+{
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+ createStatement(t.pEnv);
+ static jmethodID mID(nullptr);
+ jobject out = callObjectMethodWithIntArg(t.pEnv,"getTime","(I)Ljava/sql/Time;", mID, columnIndex);
+ // WARNING: the caller becomes the owner of the returned pointer
+ return out ? static_cast <css::util::Time> (java_sql_Time( t.pEnv, out )) : css::util::Time();
+}
+
+ css::util::DateTime SAL_CALL java_sql_CallableStatement::getTimestamp( sal_Int32 columnIndex )
+{
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+ createStatement(t.pEnv);
+ static jmethodID mID(nullptr);
+ jobject out = callObjectMethodWithIntArg(t.pEnv,"getTimestamp","(I)Ljava/sql/Timestamp;", mID, columnIndex);
+ // WARNING: the caller becomes the owner of the returned pointer
+ return out ? static_cast <css::util::DateTime> (java_sql_Timestamp( t.pEnv, out )) : css::util::DateTime();
+}
+
+void SAL_CALL java_sql_CallableStatement::registerOutParameter( sal_Int32 parameterIndex, sal_Int32 sqlType, const OUString& typeName )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(java_sql_Statement_BASE::rBHelper.bDisposed);
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+
+ {
+ createStatement(t.pEnv);
+
+ // initialize temporary variable
+ static const char * const cSignature = "(IILjava/lang/String;)V";
+ static const char * const cMethodName = "registerOutParameter";
+ // execute Java-Call
+ static jmethodID mID(nullptr);
+ obtainMethodId_throwSQL(t.pEnv, cMethodName,cSignature, mID);
+ // Convert Parameter
+ jdbc::LocalRef< jstring > str( t.env(),convertwchar_tToJavaString(t.pEnv,typeName));
+ t.pEnv->CallVoidMethod( object, mID, parameterIndex,sqlType,str.get());
+ ThrowLoggedSQLException( m_aLogger, t.pEnv, *this );
+ }
+}
+void SAL_CALL java_sql_CallableStatement::registerNumericOutParameter( sal_Int32 parameterIndex, sal_Int32 sqlType, sal_Int32 scale )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(java_sql_Statement_BASE::rBHelper.bDisposed);
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+
+ {
+ createStatement(t.pEnv);
+ // initialize temporary variable
+ static const char * const cSignature = "(III)V";
+ static const char * const cMethodName = "registerOutParameter";
+ // execute Java-Call
+ static jmethodID mID(nullptr);
+ obtainMethodId_throwSQL(t.pEnv, cMethodName,cSignature, mID);
+ t.pEnv->CallVoidMethod( object, mID, parameterIndex,sqlType,scale);
+ ThrowLoggedSQLException( m_aLogger, t.pEnv, *this );
+ }
+}
+
+jclass java_sql_CallableStatement::theClass = nullptr;
+
+jclass java_sql_CallableStatement::getMyClass() const
+{
+ // the class must be fetched only once, therefore static
+ if( !theClass )
+ theClass = findMyClass("java/sql/CallableStatement");
+ return theClass;
+}
+
+Reference< css::io::XInputStream > SAL_CALL java_sql_CallableStatement::getBinaryStream( sal_Int32 columnIndex )
+{
+ Reference< css::sdbc::XBlob > xBlob = getBlob(columnIndex);
+ return xBlob.is() ? xBlob->getBinaryStream() : Reference< css::io::XInputStream >();
+}
+Reference< css::io::XInputStream > SAL_CALL java_sql_CallableStatement::getCharacterStream( sal_Int32 columnIndex )
+{
+ Reference< css::sdbc::XClob > xClob = getClob(columnIndex);
+ return xClob.is() ? xClob->getCharacterStream() : Reference< css::io::XInputStream >();
+}
+
+Reference< css::sdbc::XArray > SAL_CALL java_sql_CallableStatement::getArray( sal_Int32 columnIndex )
+{
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+ createStatement(t.pEnv);
+ static jmethodID mID(nullptr);
+ jobject out = callObjectMethodWithIntArg(t.pEnv,"getArray","(I)Ljava/sql/Array;", mID, columnIndex);
+ // WARNING: the caller becomes the owner of the returned pointer
+ return out==nullptr ? nullptr : new java_sql_Array( t.pEnv, out );
+}
+
+Reference< css::sdbc::XClob > SAL_CALL java_sql_CallableStatement::getClob( sal_Int32 columnIndex )
+{
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+ createStatement(t.pEnv);
+ static jmethodID mID(nullptr);
+ jobject out = callObjectMethodWithIntArg(t.pEnv,"getClob","(I)Ljava/sql/Clob;", mID, columnIndex);
+ // WARNING: the caller becomes the owner of the returned pointer
+ return out==nullptr ? nullptr : new java_sql_Clob( t.pEnv, out );
+}
+Reference< css::sdbc::XBlob > SAL_CALL java_sql_CallableStatement::getBlob( sal_Int32 columnIndex )
+{
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+ createStatement(t.pEnv);
+ static jmethodID mID(nullptr);
+ jobject out = callObjectMethodWithIntArg(t.pEnv,"getBlob","(I)Ljava/sql/Blob;", mID, columnIndex);
+ // WARNING: the caller becomes the owner of the returned pointer
+ return out==nullptr ? nullptr : new java_sql_Blob( t.pEnv, out );
+}
+
+Reference< css::sdbc::XRef > SAL_CALL java_sql_CallableStatement::getRef( sal_Int32 columnIndex )
+{
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+ createStatement(t.pEnv);
+ static jmethodID mID(nullptr);
+ jobject out = callObjectMethodWithIntArg(t.pEnv,"getRef","(I)Ljava/sql/Ref;", mID, columnIndex);
+ // WARNING: the caller becomes the owner of the returned pointer
+ return out==nullptr ? nullptr : new java_sql_Ref( t.pEnv, out );
+}
+
+void SAL_CALL java_sql_CallableStatement::acquire() noexcept
+{
+ java_sql_PreparedStatement::acquire();
+}
+
+void SAL_CALL java_sql_CallableStatement::release() noexcept
+{
+ java_sql_PreparedStatement::release();
+}
+
+void java_sql_CallableStatement::createStatement(JNIEnv* /*_pEnv*/)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(java_sql_Statement_BASE::rBHelper.bDisposed);
+
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+ if( !t.pEnv || object )
+ return;
+
+ // initialize temporary variable
+ static const char * const cMethodName = "prepareCall";
+ // execute Java-Call
+ jobject out = nullptr;
+ // convert Parameter
+ jdbc::LocalRef< jstring > str( t.env(),convertwchar_tToJavaString(t.pEnv,m_sSqlStatement));
+
+ static jmethodID mID = [&]()
+ {
+ static const char * const cSignature = "(Ljava/lang/String;II)Ljava/sql/CallableStatement;";
+ return t.pEnv->GetMethodID( m_pConnection->getMyClass(), cMethodName, cSignature );
+ }();
+ if( mID ){
+ out = t.pEnv->CallObjectMethod( m_pConnection->getJavaObject(), mID, str.get() ,m_nResultSetType,m_nResultSetConcurrency);
+ } //mID
+ else
+ {
+ static const char * const cSignature2 = "(Ljava/lang/String;)Ljava/sql/CallableStatement;";
+ static jmethodID mID2 = t.pEnv->GetMethodID( m_pConnection->getMyClass(), cMethodName, cSignature2 );OSL_ENSURE(mID2,"Unknown method id!");
+ if( mID2 ){
+ out = t.pEnv->CallObjectMethod( m_pConnection->getJavaObject(), mID2, str.get() );
+ } //mID
+ }
+ ThrowLoggedSQLException( m_aLogger, t.pEnv, *this );
+
+ if ( out )
+ object = t.pEnv->NewGlobalRef( out );
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/jdbc/Class.cxx b/connectivity/source/drivers/jdbc/Class.cxx
new file mode 100644
index 0000000000..862827d12c
--- /dev/null
+++ b/connectivity/source/drivers/jdbc/Class.cxx
@@ -0,0 +1,70 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <java/lang/Class.hxx>
+#include <rtl/ustring.hxx>
+
+using namespace connectivity;
+
+//************ Class: java.lang.Class
+
+jclass java_lang_Class::theClass = nullptr;
+
+java_lang_Class::~java_lang_Class() {}
+
+jclass java_lang_Class::getMyClass() const
+{
+ // the class must be fetched only once, therefore static
+ if (!theClass)
+ theClass = findMyClass("java/lang/Class");
+ return theClass;
+}
+
+java_lang_Class* java_lang_Class::forName(std::u16string_view _par0)
+{
+ jobject out(nullptr);
+ SDBThreadAttach t;
+
+ {
+ OString sClassName = OUStringToOString(_par0, RTL_TEXTENCODING_JAVA_UTF8);
+ sClassName = sClassName.replace('.', '/');
+ out = t.pEnv->FindClass(sClassName.getStr());
+ ThrowSQLException(t.pEnv, nullptr);
+ } //t.pEnv
+ // WARNING: the caller becomes the owner of the returned pointer
+ return out == nullptr ? nullptr : new java_lang_Class(t.pEnv, out);
+}
+
+jobject java_lang_Class::newInstanceObject()
+{
+ SDBThreadAttach t;
+ auto const id = t.pEnv->GetMethodID(static_cast<jclass>(object), "<init>", "()V");
+ if (id == nullptr)
+ {
+ ThrowSQLException(t.pEnv, nullptr);
+ }
+ auto const obj = t.pEnv->NewObject(static_cast<jclass>(object), id);
+ if (obj == nullptr)
+ {
+ ThrowSQLException(t.pEnv, nullptr);
+ }
+ return obj;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/jdbc/Clob.cxx b/connectivity/source/drivers/jdbc/Clob.cxx
new file mode 100644
index 0000000000..6108981aca
--- /dev/null
+++ b/connectivity/source/drivers/jdbc/Clob.cxx
@@ -0,0 +1,132 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <java/sql/Clob.hxx>
+#include <java/tools.hxx>
+#include <java/io/Reader.hxx>
+#include <connectivity/dbexception.hxx>
+#include <osl/diagnose.h>
+
+using namespace connectivity;
+
+//************ Class: java.sql.Clob
+
+
+jclass java_sql_Clob::theClass = nullptr;
+
+java_sql_Clob::java_sql_Clob( JNIEnv * pEnv, jobject myObj )
+ : java_lang_Object( pEnv, myObj )
+{
+ SDBThreadAttach::addRef();
+}
+java_sql_Clob::~java_sql_Clob()
+{
+ SDBThreadAttach::releaseRef();
+}
+
+jclass java_sql_Clob::getMyClass() const
+{
+ // the class must be fetched only once, therefore static
+ if( !theClass )
+ theClass = findMyClass("java/sql/Clob");
+ return theClass;
+}
+
+sal_Int64 SAL_CALL java_sql_Clob::length( )
+{
+ jlong out(0);
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+
+ {
+ // initialize temporary variable
+ static const char * const cSignature = "()J";
+ static const char * const cMethodName = "length";
+ // execute Java-Call
+ static jmethodID mID(nullptr);
+ obtainMethodId_throwSQL(t.pEnv, cMethodName,cSignature, mID);
+ out = t.pEnv->CallLongMethod( object, mID );
+ ThrowSQLException(t.pEnv,*this);
+ } //t.pEnv
+ return static_cast<sal_Int64>(out);
+}
+
+OUString SAL_CALL java_sql_Clob::getSubString( sal_Int64 pos, sal_Int32 subStringLength )
+{
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+ OUString aStr;
+ {
+ // initialize temporary variable
+ static const char * const cSignature = "(JI)Ljava/lang/String;";
+ static const char * const cMethodName = "getSubString";
+ // execute Java-Call
+ static jmethodID mID(nullptr);
+ obtainMethodId_throwSQL(t.pEnv, cMethodName,cSignature, mID);
+ jstring out = static_cast<jstring>(t.pEnv->CallObjectMethod( object, mID,pos,subStringLength));
+ ThrowSQLException(t.pEnv,*this);
+ aStr = JavaString2String(t.pEnv,out);
+ } //t.pEnv
+ // WARNING: the caller becomes the owner of the returned pointer
+ return aStr;
+}
+
+css::uno::Reference< css::io::XInputStream > SAL_CALL java_sql_Clob::getCharacterStream( )
+{
+ SDBThreadAttach t;
+ static jmethodID mID(nullptr);
+ jobject out = callObjectMethod(t.pEnv,"getCharacterStream","()Ljava/io/Reader;", mID);
+
+ // WARNING: the caller becomes the owner of the returned pointer
+ return out==nullptr ? nullptr : new java_io_Reader( t.pEnv, out );
+}
+
+sal_Int64 SAL_CALL java_sql_Clob::position( const OUString& searchstr, sal_Int32 start )
+{
+ jlong out(0);
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+
+ {
+ jvalue args[1];
+ // convert Parameter
+ args[0].l = convertwchar_tToJavaString(t.pEnv,searchstr);
+ // initialize temporary Variable
+ static const char * const cSignature = "(Ljava/lang/String;I)J";
+ static const char * const cMethodName = "position";
+ // execute Java-Call
+ static jmethodID mID(nullptr);
+ obtainMethodId_throwSQL(t.pEnv, cMethodName,cSignature, mID);
+ out = t.pEnv->CallLongMethod( object, mID, args[0].l,start );
+ ThrowSQLException(t.pEnv,*this);
+ t.pEnv->DeleteLocalRef(static_cast<jstring>(args[0].l));
+ } //t.pEnv
+ return static_cast<sal_Int64>(out);
+}
+
+sal_Int64 SAL_CALL java_sql_Clob::positionOfClob( const css::uno::Reference< css::sdbc::XClob >& /*pattern*/, sal_Int64 /*start*/ )
+{
+ ::dbtools::throwFeatureNotImplementedSQLException( "XClob::positionOfClob", *this );
+ // this was put here in CWS warnings01. The previous implementation was defective, as it did ignore
+ // the pattern parameter. Since the effort for proper implementation is rather high - we would need
+ // to translated pattern into a byte[] -, we defer this functionality for the moment (hey, it was
+ // unusable, anyway)
+ // 2005-11-15 / #i57457# / frank.schoenheit@sun.com
+ return 0;
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/jdbc/ConnectionLog.cxx b/connectivity/source/drivers/jdbc/ConnectionLog.cxx
new file mode 100644
index 0000000000..96a82fb61c
--- /dev/null
+++ b/connectivity/source/drivers/jdbc/ConnectionLog.cxx
@@ -0,0 +1,110 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <java/sql/ConnectionLog.hxx>
+
+#include <com/sun/star/util/Date.hpp>
+#include <com/sun/star/util/Time.hpp>
+#include <com/sun/star/util/DateTime.hpp>
+
+#include <stdio.h>
+
+
+namespace connectivity::java::sql {
+
+
+ namespace
+ {
+ sal_Int32 lcl_getFreeID( ConnectionLog::ObjectType _eType )
+ {
+ static oslInterlockedCount s_nCounts[ ConnectionLog::ObjectTypeCount ] = { 0, 0 };
+ return osl_atomic_increment( s_nCounts + _eType );
+ }
+ }
+
+ ConnectionLog::ConnectionLog( const ::comphelper::EventLogger& _rDriverLog )
+ :ConnectionLog_Base( _rDriverLog )
+ ,m_nObjectID( lcl_getFreeID( CONNECTION ) )
+ {
+ }
+
+
+ ConnectionLog::ConnectionLog( const ConnectionLog& _rSourceLog )
+ :ConnectionLog_Base( _rSourceLog )
+ ,m_nObjectID( _rSourceLog.m_nObjectID )
+ {
+ }
+
+
+ ConnectionLog::ConnectionLog( const ConnectionLog& _rSourceLog, ConnectionLog::ObjectType _eType )
+ :ConnectionLog_Base( _rSourceLog )
+ ,m_nObjectID( lcl_getFreeID( _eType ) )
+ {
+ }
+
+
+} // namespace connectivity::java::sql
+
+
+namespace comphelper::log::convert
+{
+
+
+ using ::com::sun::star::util::Date;
+ using ::com::sun::star::util::Time;
+ using ::com::sun::star::util::DateTime;
+
+
+ OUString convertLogArgToString( const Date& _rDate )
+ {
+ char buffer[ 30 ];
+ const size_t buffer_size = sizeof( buffer );
+ snprintf( buffer, buffer_size, "%04i-%02i-%02i",
+ static_cast<int>(_rDate.Year), static_cast<int>(_rDate.Month), static_cast<int>(_rDate.Day) );
+ return OUString::createFromAscii( buffer );
+ }
+
+
+ OUString convertLogArgToString( const css::util::Time& _rTime )
+ {
+ char buffer[ 30 ];
+ const size_t buffer_size = sizeof( buffer );
+ snprintf( buffer, buffer_size, "%02i:%02i:%02i.%09i",
+ static_cast<int>(_rTime.Hours), static_cast<int>(_rTime.Minutes), static_cast<int>(_rTime.Seconds), static_cast<int>(_rTime.NanoSeconds) );
+ return OUString::createFromAscii( buffer );
+ }
+
+
+ OUString convertLogArgToString( const DateTime& _rDateTime )
+ {
+ char buffer[ sizeof("-32768-65535-65535 65535:65535:65535.4294967295") ];
+ // reserve enough space for hypothetical max length
+ const size_t buffer_size = sizeof( buffer );
+ snprintf( buffer, buffer_size, "%04" SAL_PRIdINT32 "-%02" SAL_PRIuUINT32 "-%02" SAL_PRIuUINT32 " %02" SAL_PRIuUINT32 ":%02" SAL_PRIuUINT32 ":%02" SAL_PRIuUINT32 ".%09" SAL_PRIuUINT32,
+ static_cast<sal_Int32>(_rDateTime.Year), static_cast<sal_uInt32>(_rDateTime.Month), static_cast<sal_uInt32>(_rDateTime.Day),
+ static_cast<sal_uInt32>(_rDateTime.Hours), static_cast<sal_uInt32>(_rDateTime.Minutes), static_cast<sal_uInt32>(_rDateTime.Seconds), _rDateTime.NanoSeconds );
+ return OUString::createFromAscii( buffer );
+ }
+
+
+} // comphelper::log::convert
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/jdbc/ContextClassLoader.cxx b/connectivity/source/drivers/jdbc/ContextClassLoader.cxx
new file mode 100644
index 0000000000..3ab1b88eb3
--- /dev/null
+++ b/connectivity/source/drivers/jdbc/ContextClassLoader.cxx
@@ -0,0 +1,111 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <java/ContextClassLoader.hxx>
+#include <java/lang/Object.hxx>
+
+
+namespace connectivity::jdbc
+{
+
+
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::uno::XInterface;
+
+ using ::connectivity::java_lang_Object;
+
+ ContextClassLoaderScope::ContextClassLoaderScope( JNIEnv& environment, const GlobalRef< jobject >& newClassLoader,
+ const ::comphelper::EventLogger& _rLoggerForErrors, const Reference< XInterface >& _rxErrorContext )
+ :m_environment( environment )
+ ,m_currentThread( environment )
+ ,m_oldContextClassLoader( environment )
+ ,m_setContextClassLoaderMethod( nullptr )
+ {
+ if ( !newClassLoader.is() )
+ return;
+
+ do // artificial loop for easier flow control
+ {
+
+ LocalRef< jclass > threadClass( m_environment );
+ threadClass.set( m_environment.FindClass( "java/lang/Thread" ) );
+ if ( !threadClass.is() )
+ break;
+
+ jmethodID currentThreadMethod( m_environment.GetStaticMethodID(
+ threadClass.get(), "currentThread", "()Ljava/lang/Thread;" ) );
+ if ( currentThreadMethod == nullptr )
+ break;
+
+ m_currentThread.set( m_environment.CallStaticObjectMethod( threadClass.get(), currentThreadMethod ) );
+ if ( !m_currentThread.is() )
+ break;
+
+ jmethodID getContextClassLoaderMethod( m_environment.GetMethodID(
+ threadClass.get(), "getContextClassLoader", "()Ljava/lang/ClassLoader;" ) );
+ if ( getContextClassLoaderMethod == nullptr )
+ break;
+ m_oldContextClassLoader.set( m_environment.CallObjectMethod( m_currentThread.get(), getContextClassLoaderMethod ) );
+ LocalRef< jthrowable > throwable( m_environment, m_environment.ExceptionOccurred() );
+ if ( throwable.is() )
+ break;
+
+ m_setContextClassLoaderMethod = m_environment.GetMethodID(
+ threadClass.get(), "setContextClassLoader", "(Ljava/lang/ClassLoader;)V" );
+ if ( m_setContextClassLoaderMethod == nullptr )
+ break;
+
+ }
+ while ( false );
+
+ if ( !isActive() )
+ {
+ java_lang_Object::ThrowLoggedSQLException( _rLoggerForErrors, &environment, _rxErrorContext );
+ return;
+ }
+
+ // set the new class loader
+ m_environment.CallObjectMethod( m_currentThread.get(), m_setContextClassLoaderMethod, newClassLoader.get() );
+ LocalRef< jthrowable > throwable( m_environment, m_environment.ExceptionOccurred() );
+ if ( throwable.is() )
+ {
+ m_currentThread.reset();
+ m_setContextClassLoaderMethod = nullptr;
+ java_lang_Object::ThrowLoggedSQLException( _rLoggerForErrors, &environment, _rxErrorContext );
+ }
+ }
+
+
+ ContextClassLoaderScope::~ContextClassLoaderScope()
+ {
+ if ( isActive() )
+ {
+ LocalRef< jobject > currentThread( m_currentThread.env(), m_currentThread.release() );
+ jmethodID setContextClassLoaderMethod( m_setContextClassLoaderMethod );
+ m_setContextClassLoaderMethod = nullptr;
+
+ m_environment.CallObjectMethod( currentThread.get(), setContextClassLoaderMethod, m_oldContextClassLoader.get() );
+ m_environment.ExceptionClear();
+ }
+ }
+
+} // namespace connectivity::jdbc
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/jdbc/DatabaseMetaData.cxx b/connectivity/source/drivers/jdbc/DatabaseMetaData.cxx
new file mode 100644
index 0000000000..2633fd09b6
--- /dev/null
+++ b/connectivity/source/drivers/jdbc/DatabaseMetaData.cxx
@@ -0,0 +1,1463 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <string_view>
+
+#include <sal/macros.h>
+#include <java/sql/DatabaseMetaData.hxx>
+#include <java/sql/Connection.hxx>
+#include <java/sql/ResultSet.hxx>
+#include <java/sql/SQLException.hxx>
+#include <java/tools.hxx>
+#include <java/lang/String.hxx>
+#include <FDatabaseMetaDataResultSet.hxx>
+#include <comphelper/types.hxx>
+#include <TPrivilegesResultSet.hxx>
+#include <strings.hxx>
+
+using namespace ::comphelper;
+
+using namespace connectivity;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+
+jclass java_sql_DatabaseMetaData::theClass = nullptr;
+
+java_sql_DatabaseMetaData::~java_sql_DatabaseMetaData()
+{
+ SDBThreadAttach::releaseRef();
+}
+
+jclass java_sql_DatabaseMetaData::getMyClass() const
+{
+ // the class must be fetched only once, therefore static
+ if( !theClass )
+ theClass = findMyClass("java/sql/DatabaseMetaData");
+ return theClass;
+}
+
+java_sql_DatabaseMetaData::java_sql_DatabaseMetaData( JNIEnv * pEnv, jobject myObj, java_sql_Connection& _rConnection )
+ :ODatabaseMetaDataBase( &_rConnection,_rConnection.getConnectionInfo() )
+ ,java_lang_Object( pEnv, myObj )
+ ,m_pConnection( &_rConnection )
+ ,m_aLogger( _rConnection.getLogger() )
+{
+ SDBThreadAttach::addRef();
+}
+
+
+Reference< XResultSet > java_sql_DatabaseMetaData::impl_getTypeInfo_throw( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callResultSetMethod( "getTypeInfo", mID );
+}
+
+Reference< XResultSet > SAL_CALL java_sql_DatabaseMetaData::getCatalogs( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callResultSetMethod( "getCatalogs", mID );
+}
+
+OUString java_sql_DatabaseMetaData::impl_getCatalogSeparator_throw( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callStringMethod( "getCatalogSeparator", mID );
+}
+
+Reference< XResultSet > SAL_CALL java_sql_DatabaseMetaData::getSchemas( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callResultSetMethod( "getSchemas", mID );
+}
+
+Reference< XResultSet > SAL_CALL java_sql_DatabaseMetaData::getColumnPrivileges(
+ const Any& catalog, const OUString& schema, const OUString& table, const OUString& columnNamePattern )
+{
+ static jmethodID mID(nullptr);
+ return impl_callResultSetMethodWithStrings( "getColumnPrivileges", mID, catalog, schema, table, &columnNamePattern );
+}
+
+Reference< XResultSet > SAL_CALL java_sql_DatabaseMetaData::getColumns(
+ const Any& catalog, const OUString& schemaPattern, const OUString& tableNamePattern, const OUString& columnNamePattern )
+{
+ static jmethodID mID(nullptr);
+ return impl_callResultSetMethodWithStrings( "getColumns", mID, catalog, schemaPattern, tableNamePattern, &columnNamePattern );
+}
+
+
+Reference< XResultSet > SAL_CALL java_sql_DatabaseMetaData::getTables(
+ const Any& catalog, const OUString& schemaPattern, const OUString& tableNamePattern, const Sequence< OUString >& _types )
+{
+ static const char * const cMethodName = "getTables";
+
+ m_aLogger.log( LogLevel::FINEST, STR_LOG_META_DATA_METHOD, cMethodName );
+
+ jobject out(nullptr);
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+
+ {
+ static const char * const cSignature = "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;)Ljava/sql/ResultSet;";
+ // execute Java-Call
+ static jmethodID mID(nullptr);
+ obtainMethodId_throwSQL(t.pEnv, cMethodName,cSignature, mID);
+ OSL_VERIFY( !isExceptionOccurred(t.pEnv) );
+ jvalue args[4];
+
+ args[3].l = nullptr;
+ sal_Int32 typeFilterCount = _types.getLength();
+ if ( typeFilterCount )
+ {
+ jobjectArray pObjArray = t.pEnv->NewObjectArray( static_cast<jsize>(typeFilterCount), java_lang_String::st_getMyClass(), nullptr );
+ OSL_VERIFY( !isExceptionOccurred( t.pEnv ) );
+ const OUString* typeFilter = _types.getConstArray();
+ bool bIncludeAllTypes = false;
+ for ( sal_Int32 i=0; i<typeFilterCount; ++i, ++typeFilter )
+ {
+ if ( *typeFilter == "%" )
+ {
+ bIncludeAllTypes = true;
+ break;
+ }
+ jstring aT = convertwchar_tToJavaString( t.pEnv, *typeFilter );
+ t.pEnv->SetObjectArrayElement( pObjArray, static_cast<jsize>(i), aT );
+ OSL_VERIFY( !isExceptionOccurred( t.pEnv ) );
+ }
+
+ if ( bIncludeAllTypes )
+ {
+ // the SDBC API allows to pass "%" as table type filter, but in JDBC, "all table types"
+ // is represented by the table type being <null/>
+ t.pEnv->DeleteLocalRef( pObjArray );
+ OSL_VERIFY( !isExceptionOccurred( t.pEnv ) );
+ }
+ else
+ {
+ args[3].l = pObjArray;
+ }
+ }
+ // if we are to display "all catalogs", then respect m_aCatalogRestriction
+ Any aCatalogFilter( catalog );
+ if ( !aCatalogFilter.hasValue() )
+ aCatalogFilter = m_pConnection->getCatalogRestriction();
+ // similar for schema
+ Any aSchemaFilter;
+ if ( schemaPattern == "%" )
+ aSchemaFilter = m_pConnection->getSchemaRestriction();
+ else
+ aSchemaFilter <<= schemaPattern;
+
+ args[0].l = aCatalogFilter.hasValue() ? convertwchar_tToJavaString( t.pEnv, ::comphelper::getString( aCatalogFilter ) ) : nullptr;
+ args[1].l = aSchemaFilter.hasValue() ? convertwchar_tToJavaString( t.pEnv, ::comphelper::getString( aSchemaFilter ) ) : nullptr;
+ args[2].l = convertwchar_tToJavaString(t.pEnv,tableNamePattern);
+ out = t.pEnv->CallObjectMethod( object, mID, args[0].l, args[1].l,args[2].l,args[3].l);
+ jthrowable jThrow = t.pEnv->ExceptionOccurred();
+ if ( jThrow )
+ t.pEnv->ExceptionClear();// we have to clear the exception here because we want to handle it below
+ if ( aCatalogFilter.hasValue() )
+ {
+ t.pEnv->DeleteLocalRef(static_cast<jstring>(args[0].l));
+ OSL_VERIFY( !isExceptionOccurred( t.pEnv ) );
+ }
+ if(args[1].l)
+ {
+ t.pEnv->DeleteLocalRef(static_cast<jstring>(args[1].l));
+ OSL_VERIFY( !isExceptionOccurred( t.pEnv ) );
+ }
+ if(!tableNamePattern.isEmpty())
+ {
+ t.pEnv->DeleteLocalRef(static_cast<jstring>(args[2].l));
+ OSL_VERIFY( !isExceptionOccurred( t.pEnv ) );
+ }
+ //for(INT16 i=0;i<len;i++)
+ if ( args[3].l )
+ {
+ t.pEnv->DeleteLocalRef( static_cast<jobjectArray>(args[3].l) );
+ OSL_VERIFY( !isExceptionOccurred( t.pEnv ) );
+ }
+
+ if ( jThrow )
+ {
+ if ( t.pEnv->IsInstanceOf( jThrow,java_sql_SQLException_BASE::st_getMyClass() ) )
+ {
+ java_sql_SQLException_BASE aException( t.pEnv, jThrow );
+ SQLException e( aException.getMessage(),
+ *this,
+ aException.getSQLState(),
+ aException.getErrorCode(),
+ Any()
+ );
+ throw e;
+ }
+ }
+ }
+
+ if ( !out )
+ return nullptr;
+
+ m_aLogger.log( LogLevel::FINEST, STR_LOG_META_DATA_SUCCESS, cMethodName );
+ return new java_sql_ResultSet( t.pEnv, out, m_aLogger,*m_pConnection);
+}
+
+Reference< XResultSet > SAL_CALL java_sql_DatabaseMetaData::getProcedureColumns(
+ const Any& catalog, const OUString& schemaPattern, const OUString& procedureNamePattern, const OUString& columnNamePattern )
+{
+ static jmethodID mID(nullptr);
+ return impl_callResultSetMethodWithStrings( "getProcedureColumns", mID, catalog, schemaPattern, procedureNamePattern, &columnNamePattern );
+}
+
+Reference< XResultSet > SAL_CALL java_sql_DatabaseMetaData::getProcedures( const Any&
+ catalog, const OUString& schemaPattern, const OUString& procedureNamePattern )
+{
+ static jmethodID mID(nullptr);
+ return impl_callResultSetMethodWithStrings( "getProcedures", mID, catalog, schemaPattern, procedureNamePattern );
+}
+
+Reference< XResultSet > SAL_CALL java_sql_DatabaseMetaData::getVersionColumns(
+ const Any& catalog, const OUString& schema, const OUString& table )
+{
+ static jmethodID mID(nullptr);
+ return impl_callResultSetMethodWithStrings( "getVersionColumns", mID, catalog, schema, table );
+}
+
+sal_Int32 SAL_CALL java_sql_DatabaseMetaData::getMaxBinaryLiteralLength( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callIntMethod_ThrowSQL("getMaxBinaryLiteralLength", mID);
+}
+
+sal_Int32 SAL_CALL java_sql_DatabaseMetaData::getMaxRowSize( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callIntMethod_ThrowSQL("getMaxRowSize", mID);
+}
+
+sal_Int32 SAL_CALL java_sql_DatabaseMetaData::getMaxCatalogNameLength( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callIntMethod_ThrowSQL("getMaxCatalogNameLength", mID);
+}
+
+sal_Int32 SAL_CALL java_sql_DatabaseMetaData::getMaxCharLiteralLength( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callIntMethod_ThrowSQL("getMaxCharLiteralLength", mID);
+}
+
+sal_Int32 SAL_CALL java_sql_DatabaseMetaData::getMaxColumnNameLength( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callIntMethod_ThrowSQL("getMaxColumnNameLength", mID);
+}
+
+sal_Int32 SAL_CALL java_sql_DatabaseMetaData::getMaxColumnsInIndex( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callIntMethod_ThrowSQL("getMaxColumnsInIndex", mID);
+}
+
+sal_Int32 SAL_CALL java_sql_DatabaseMetaData::getMaxCursorNameLength( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callIntMethod_ThrowSQL("getMaxCursorNameLength", mID);
+}
+
+sal_Int32 SAL_CALL java_sql_DatabaseMetaData::getMaxConnections( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callIntMethod_ThrowSQL("getMaxConnections", mID);
+}
+
+sal_Int32 SAL_CALL java_sql_DatabaseMetaData::getMaxColumnsInTable( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callIntMethod_ThrowSQL("getMaxColumnsInTable", mID);
+}
+
+sal_Int32 SAL_CALL java_sql_DatabaseMetaData::getMaxStatementLength( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callIntMethod_ThrowSQL("getMaxStatementLength", mID);
+}
+
+sal_Int32 SAL_CALL java_sql_DatabaseMetaData::getMaxTableNameLength( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callIntMethod_ThrowSQL("getMaxTableNameLength", mID);
+}
+
+sal_Int32 java_sql_DatabaseMetaData::impl_getMaxTablesInSelect_throw( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callIntMethod_ThrowSQL("getMaxTablesInSelect", mID);
+}
+
+Reference< XResultSet > SAL_CALL java_sql_DatabaseMetaData::getExportedKeys(
+ const Any& catalog, const OUString& schema, const OUString& table )
+{
+ static jmethodID mID(nullptr);
+ return impl_callResultSetMethodWithStrings( "getExportedKeys", mID, catalog, schema, table );
+}
+
+Reference< XResultSet > SAL_CALL java_sql_DatabaseMetaData::getImportedKeys(
+ const Any& catalog, const OUString& schema, const OUString& table )
+{
+ static jmethodID mID(nullptr);
+ return impl_callResultSetMethodWithStrings( "getImportedKeys", mID, catalog, schema, table );
+}
+
+Reference< XResultSet > SAL_CALL java_sql_DatabaseMetaData::getPrimaryKeys(
+ const Any& catalog, const OUString& schema, const OUString& table )
+{
+ static jmethodID mID(nullptr);
+ return impl_callResultSetMethodWithStrings( "getPrimaryKeys", mID, catalog, schema, table );
+}
+
+Reference< XResultSet > SAL_CALL java_sql_DatabaseMetaData::getIndexInfo(
+ const Any& catalog, const OUString& schema, const OUString& table,
+ sal_Bool unique, sal_Bool approximate )
+{
+ static const char * const cMethodName = "getIndexInfo";
+
+ m_aLogger.log( LogLevel::FINEST, STR_LOG_META_DATA_METHOD, cMethodName );
+
+ jobject out(nullptr);
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+
+ {
+ static const char * const cSignature = "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ZZ)Ljava/sql/ResultSet;";
+ // execute Java-Call
+ static jmethodID mID(nullptr);
+ obtainMethodId_throwSQL(t.pEnv, cMethodName,cSignature, mID);
+ jvalue args[5];
+ // convert Parameter
+ args[0].l = catalog.hasValue() ? convertwchar_tToJavaString(t.pEnv,comphelper::getString(catalog)) : nullptr;
+ args[1].l = schema.toChar() == '%' ? nullptr : convertwchar_tToJavaString(t.pEnv,schema);
+ args[2].l = convertwchar_tToJavaString(t.pEnv,table);
+ args[3].z = unique;
+ args[4].z = approximate;
+ out = t.pEnv->CallObjectMethod( object, mID, args[0].l,args[1].l,args[2].l,args[3].z,args[4].z );
+
+ // and clean up
+ if(catalog.hasValue())
+ t.pEnv->DeleteLocalRef(static_cast<jstring>(args[0].l));
+ if(args[1].l)
+ t.pEnv->DeleteLocalRef(static_cast<jstring>(args[1].l));
+ if(!table.isEmpty())
+ t.pEnv->DeleteLocalRef(static_cast<jstring>(args[2].l));
+ ThrowLoggedSQLException( m_aLogger, t.pEnv, *this );
+ }
+ if ( !out )
+ return nullptr;
+
+ m_aLogger.log( LogLevel::FINEST, STR_LOG_META_DATA_SUCCESS, cMethodName );
+ return new java_sql_ResultSet( t.pEnv, out, m_aLogger,*m_pConnection);
+}
+
+Reference< XResultSet > SAL_CALL java_sql_DatabaseMetaData::getBestRowIdentifier(
+ const Any& catalog, const OUString& schema, const OUString& table, sal_Int32 scope,
+ sal_Bool nullable )
+{
+ static const char * const cMethodName = "getBestRowIdentifier";
+
+ m_aLogger.log( LogLevel::FINEST, STR_LOG_META_DATA_METHOD, cMethodName );
+
+ jobject out(nullptr);
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+
+ {
+ static const char * const cSignature = "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;IZ)Ljava/sql/ResultSet;";
+ // execute Java-Call
+ static jmethodID mID(nullptr);
+ obtainMethodId_throwSQL(t.pEnv, cMethodName,cSignature, mID);
+ jvalue args[3];
+ // convert Parameter
+ args[0].l = catalog.hasValue() ? convertwchar_tToJavaString(t.pEnv,comphelper::getString(catalog)) : nullptr;
+ args[1].l = schema.toChar() == '%' ? nullptr : convertwchar_tToJavaString(t.pEnv,schema);
+ args[2].l = convertwchar_tToJavaString(t.pEnv,table);
+ out = t.pEnv->CallObjectMethod( object, mID, args[0].l,args[1].l,args[2].l,scope,nullable);
+
+ // and cleanup
+ if(catalog.hasValue())
+ t.pEnv->DeleteLocalRef(static_cast<jstring>(args[0].l));
+ if(args[1].l)
+ t.pEnv->DeleteLocalRef(static_cast<jstring>(args[1].l));
+ if(!table.isEmpty())
+ t.pEnv->DeleteLocalRef(static_cast<jstring>(args[2].l));
+ ThrowLoggedSQLException( m_aLogger, t.pEnv, *this );
+ }
+
+ if ( !out )
+ return nullptr;
+
+ m_aLogger.log( LogLevel::FINEST, STR_LOG_META_DATA_SUCCESS, cMethodName );
+ return new java_sql_ResultSet( t.pEnv, out, m_aLogger,*m_pConnection);
+}
+
+Reference< XResultSet > SAL_CALL java_sql_DatabaseMetaData::getTablePrivileges(
+ const Any& catalog, const OUString& schemaPattern, const OUString& tableNamePattern )
+{
+ if ( m_pConnection->isIgnoreDriverPrivilegesEnabled() )
+ return new OResultSetPrivileges(this,catalog,schemaPattern,tableNamePattern);
+
+ static jmethodID mID(nullptr);
+ Reference< XResultSet > xReturn( impl_callResultSetMethodWithStrings( "getTablePrivileges", mID, catalog, schemaPattern, tableNamePattern ) );
+
+ if ( xReturn.is() )
+ {
+ // we have to check the result columns for the tables privileges
+ Reference< XResultSetMetaDataSupplier > xMetaSup(xReturn,UNO_QUERY);
+ if ( xMetaSup.is() )
+ {
+ Reference< XResultSetMetaData> xMeta = xMetaSup->getMetaData();
+ if ( xMeta.is() && xMeta->getColumnCount() != 7 )
+ {
+ // here we know that the count of column doesn't match
+ std::map<sal_Int32,sal_Int32> aColumnMatching;
+ static const std::u16string_view sPrivs[] = {
+ u"TABLE_CAT",
+ u"TABLE_SCHEM",
+ u"TABLE_NAME",
+ u"GRANTOR",
+ u"GRANTEE",
+ u"PRIVILEGE",
+ u"IS_GRANTABLE"
+ };
+
+ OUString sColumnName;
+ sal_Int32 nCount = xMeta->getColumnCount();
+ for (sal_Int32 i = 1 ; i <= nCount ; ++i)
+ {
+ sColumnName = xMeta->getColumnName(i);
+ for (size_t j = 0 ; j < std::size(sPrivs); ++j)
+ {
+ if ( sPrivs[j] == sColumnName )
+ {
+ aColumnMatching.emplace(i,j+1);
+ break;
+ }
+ }
+
+ }
+ // fill our own resultset
+ rtl::Reference<ODatabaseMetaDataResultSet> pNewPrivRes = new ODatabaseMetaDataResultSet( ODatabaseMetaDataResultSet::eTablePrivileges );
+ Reference< XResultSet > xTemp = xReturn;
+ xReturn = pNewPrivRes;
+ ODatabaseMetaDataResultSet::ORows aRows;
+ Reference< XRow > xRow(xTemp,UNO_QUERY);
+ OUString sValue;
+
+ ODatabaseMetaDataResultSet::ORow aRow(8);
+ while ( xRow.is() && xTemp->next() )
+ {
+ for (const auto& [nCol, nPriv] : aColumnMatching)
+ {
+ sValue = xRow->getString(nCol);
+ if ( xRow->wasNull() )
+ aRow[nPriv] = ODatabaseMetaDataResultSet::getEmptyValue();
+ else
+ aRow[nPriv] = new ORowSetValueDecorator(sValue);
+ }
+
+ aRows.push_back(aRow);
+ }
+ pNewPrivRes->setRows(std::move(aRows));
+ }
+ }
+ }
+ return xReturn;
+}
+
+Reference< XResultSet > SAL_CALL java_sql_DatabaseMetaData::getCrossReference(
+ const Any& primaryCatalog, const OUString& primarySchema,
+ const OUString& primaryTable, const Any& foreignCatalog,
+ const OUString& foreignSchema, const OUString& foreignTable )
+{
+ static const char * const cMethodName = "getCrossReference";
+ m_aLogger.log( LogLevel::FINEST, STR_LOG_META_DATA_METHOD, cMethodName );
+
+ jobject out(nullptr);
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+ {
+ static const char * const cSignature = "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/sql/ResultSet;";
+ // execute Java-Call
+ static jmethodID mID(nullptr);
+ obtainMethodId_throwSQL(t.pEnv, cMethodName,cSignature, mID);
+ jvalue args[6];
+ // convert Parameter
+ args[0].l = primaryCatalog.hasValue() ? convertwchar_tToJavaString(t.pEnv,comphelper::getString(primaryCatalog)) : nullptr;
+ args[1].l = primarySchema.toChar() == '%' ? nullptr : convertwchar_tToJavaString(t.pEnv,primarySchema);
+ args[2].l = convertwchar_tToJavaString(t.pEnv,primaryTable);
+ args[3].l = foreignCatalog.hasValue() ? convertwchar_tToJavaString(t.pEnv,comphelper::getString(foreignCatalog)) : nullptr;
+ args[4].l = foreignSchema.toChar() == '%' ? nullptr : convertwchar_tToJavaString(t.pEnv,foreignSchema);
+ args[5].l = convertwchar_tToJavaString(t.pEnv,foreignTable);
+ out = t.pEnv->CallObjectMethod( object, mID, args[0].l,args[2].l,args[2].l,args[3].l,args[4].l,args[5].l );
+
+ // and clean up
+ if(primaryCatalog.hasValue())
+ t.pEnv->DeleteLocalRef(static_cast<jstring>(args[0].l));
+ if(args[1].l)
+ t.pEnv->DeleteLocalRef(static_cast<jstring>(args[1].l));
+ if(!primaryTable.isEmpty())
+ t.pEnv->DeleteLocalRef(static_cast<jstring>(args[2].l));
+ if(foreignCatalog.hasValue())
+ t.pEnv->DeleteLocalRef(static_cast<jstring>(args[3].l));
+ if(args[4].l)
+ t.pEnv->DeleteLocalRef(static_cast<jstring>(args[4].l));
+ if(!foreignTable.isEmpty())
+ t.pEnv->DeleteLocalRef(static_cast<jstring>(args[5].l));
+ ThrowLoggedSQLException( m_aLogger, t.pEnv, *this );
+ }
+
+ if ( !out )
+ return nullptr;
+
+ m_aLogger.log( LogLevel::FINEST, STR_LOG_META_DATA_SUCCESS, cMethodName );
+ return new java_sql_ResultSet( t.pEnv, out, m_aLogger,*m_pConnection);
+}
+
+
+bool java_sql_DatabaseMetaData::impl_callBooleanMethod( const char* _pMethodName, jmethodID& _inout_MethodID )
+{
+ m_aLogger.log( LogLevel::FINEST, STR_LOG_META_DATA_METHOD, _pMethodName );
+ bool out( java_lang_Object::callBooleanMethod(_pMethodName,_inout_MethodID) );
+ m_aLogger.log< const char*, bool>( LogLevel::FINEST, STR_LOG_META_DATA_RESULT, _pMethodName, out );
+ return out;
+}
+
+
+OUString java_sql_DatabaseMetaData::impl_callStringMethod( const char* _pMethodName, jmethodID& _inout_MethodID )
+{
+ m_aLogger.log( LogLevel::FINEST, STR_LOG_META_DATA_METHOD, _pMethodName );
+
+ const OUString sReturn( callStringMethod(_pMethodName,_inout_MethodID) );
+ if ( m_aLogger.isLoggable( LogLevel::FINEST ) )
+ {
+ OUString sLoggedResult( sReturn );
+ if ( sLoggedResult.isEmpty() )
+ sLoggedResult = "<empty string>";
+ m_aLogger.log( LogLevel::FINEST, STR_LOG_META_DATA_RESULT, _pMethodName, sLoggedResult );
+ }
+
+ return sReturn;
+}
+
+sal_Int32 java_sql_DatabaseMetaData::impl_callIntMethod_ThrowSQL(const char* _pMethodName, jmethodID& _inout_MethodID)
+{
+ m_aLogger.log( LogLevel::FINEST, STR_LOG_META_DATA_METHOD, _pMethodName );
+ sal_Int32 out( callIntMethod_ThrowSQL(_pMethodName,_inout_MethodID) );
+ m_aLogger.log( LogLevel::FINEST, STR_LOG_META_DATA_RESULT, _pMethodName, out );
+ return out;
+}
+
+sal_Int32 java_sql_DatabaseMetaData::impl_callIntMethod_ThrowRuntime(const char* _pMethodName, jmethodID& _inout_MethodID)
+{
+ m_aLogger.log( LogLevel::FINEST, STR_LOG_META_DATA_METHOD, _pMethodName );
+ sal_Int32 out( callIntMethod_ThrowRuntime(_pMethodName,_inout_MethodID) );
+ m_aLogger.log( LogLevel::FINEST, STR_LOG_META_DATA_RESULT, _pMethodName, out );
+ return out;
+}
+
+bool java_sql_DatabaseMetaData::impl_callBooleanMethodWithIntArg( const char* _pMethodName, jmethodID& _inout_MethodID, sal_Int32 _nArgument )
+{
+ m_aLogger.log( LogLevel::FINEST, STR_LOG_META_DATA_METHOD_ARG1, _pMethodName, _nArgument );
+
+ bool out( callBooleanMethodWithIntArg(_pMethodName,_inout_MethodID,_nArgument) );
+
+ m_aLogger.log< const char*, bool >( LogLevel::FINEST, STR_LOG_META_DATA_RESULT, _pMethodName, out );
+ return out;
+}
+
+
+Reference< XResultSet > java_sql_DatabaseMetaData::impl_callResultSetMethod( const char* _pMethodName, jmethodID& _inout_MethodID )
+{
+ SDBThreadAttach t;
+ m_aLogger.log( LogLevel::FINEST, STR_LOG_META_DATA_METHOD, _pMethodName );
+ jobject out(callResultSetMethod(t.env(),_pMethodName,_inout_MethodID));
+ m_aLogger.log( LogLevel::FINEST, STR_LOG_META_DATA_SUCCESS, _pMethodName );
+ return new java_sql_ResultSet( t.pEnv, out, m_aLogger,*m_pConnection);
+}
+
+
+Reference< XResultSet > java_sql_DatabaseMetaData::impl_callResultSetMethodWithStrings( const char* _pMethodName, jmethodID& _inout_MethodID,
+ const Any& _rCatalog, const OUString& _rSchemaPattern, const OUString& _rLeastPattern,
+ const OUString* _pOptionalAdditionalString )
+{
+ bool bCatalog = _rCatalog.hasValue();
+ OUString sCatalog;
+ _rCatalog >>= sCatalog;
+
+ bool bSchema = _rSchemaPattern.toChar() != '%';
+
+ // log the call
+ if ( m_aLogger.isLoggable( LogLevel::FINEST ) )
+ {
+ OUString sCatalogLog = bCatalog ? sCatalog : OUString( "null" );
+ OUString sSchemaLog = bSchema ? _rSchemaPattern : OUString( "null" );
+ if ( _pOptionalAdditionalString )
+ m_aLogger.log( LogLevel::FINEST, STR_LOG_META_DATA_METHOD_ARG4, _pMethodName, sCatalogLog, sSchemaLog, _rLeastPattern, *_pOptionalAdditionalString );
+ else
+ m_aLogger.log( LogLevel::FINEST, STR_LOG_META_DATA_METHOD_ARG3, _pMethodName, sCatalogLog, sSchemaLog, _rLeastPattern );
+ }
+
+ jobject out(nullptr);
+
+ SDBThreadAttach t;
+ OSL_ENSURE( t.pEnv, "java_sql_DatabaseMetaData::impl_callResultSetMethodWithStrings: no Java environment anymore!" );
+
+ {
+ const char* pSignature = _pOptionalAdditionalString
+ ? "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/sql/ResultSet;"
+ : "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/sql/ResultSet;";
+ // obtain method ID
+ obtainMethodId_throwSQL(t.pEnv, _pMethodName,pSignature, _inout_MethodID);
+
+ // call method
+
+ {
+ jvalue args[4];
+ // convert parameters
+ args[0].l = bCatalog ? convertwchar_tToJavaString( t.pEnv, sCatalog ) : nullptr;
+ args[1].l = bSchema ? convertwchar_tToJavaString( t.pEnv, _rSchemaPattern ) : nullptr;
+ args[2].l = convertwchar_tToJavaString( t.pEnv, _rLeastPattern );
+ args[3].l = _pOptionalAdditionalString ? convertwchar_tToJavaString( t.pEnv, *_pOptionalAdditionalString ) : nullptr;
+
+ // actually do the call
+ if ( _pOptionalAdditionalString )
+ out = t.pEnv->CallObjectMethod( object, _inout_MethodID, args[0].l, args[1].l, args[2].l, args[3].l );
+ else
+ out = t.pEnv->CallObjectMethod( object, _inout_MethodID, args[0].l, args[1].l, args[2].l );
+
+ // clean up
+ if ( args[0].l )
+ t.pEnv->DeleteLocalRef( static_cast<jstring>(args[0].l) );
+ if ( args[1].l )
+ t.pEnv->DeleteLocalRef( static_cast<jstring>(args[1].l) );
+ if ( args[2].l )
+ t.pEnv->DeleteLocalRef( static_cast<jstring>(args[2].l) );
+ if ( args[3].l )
+ t.pEnv->DeleteLocalRef( static_cast<jstring>(args[3].l) );
+
+ ThrowLoggedSQLException( m_aLogger, t.pEnv, *this );
+ }
+ }
+
+ if ( !out )
+ return nullptr;
+
+ m_aLogger.log( LogLevel::FINEST, STR_LOG_META_DATA_SUCCESS, _pMethodName );
+ return new java_sql_ResultSet( t.pEnv, out, m_aLogger,*m_pConnection);
+}
+
+
+sal_Bool SAL_CALL java_sql_DatabaseMetaData::doesMaxRowSizeIncludeBlobs( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callBooleanMethod( "doesMaxRowSizeIncludeBlobs", mID );
+}
+
+sal_Bool SAL_CALL java_sql_DatabaseMetaData::storesLowerCaseQuotedIdentifiers( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callBooleanMethod( "storesLowerCaseQuotedIdentifiers", mID );
+}
+
+sal_Bool SAL_CALL java_sql_DatabaseMetaData::storesLowerCaseIdentifiers( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callBooleanMethod( "storesLowerCaseIdentifiers", mID );
+}
+
+bool java_sql_DatabaseMetaData::impl_storesMixedCaseQuotedIdentifiers_throw( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callBooleanMethod( "storesMixedCaseQuotedIdentifiers", mID );
+}
+
+sal_Bool SAL_CALL java_sql_DatabaseMetaData::storesMixedCaseIdentifiers( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callBooleanMethod( "storesMixedCaseIdentifiers", mID );
+}
+
+sal_Bool SAL_CALL java_sql_DatabaseMetaData::storesUpperCaseQuotedIdentifiers( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callBooleanMethod( "storesUpperCaseQuotedIdentifiers", mID );
+}
+
+sal_Bool SAL_CALL java_sql_DatabaseMetaData::storesUpperCaseIdentifiers( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callBooleanMethod( "storesUpperCaseIdentifiers", mID );
+}
+
+bool java_sql_DatabaseMetaData::impl_supportsAlterTableWithAddColumn_throw( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callBooleanMethod( "supportsAlterTableWithAddColumn", mID );
+}
+
+bool java_sql_DatabaseMetaData::impl_supportsAlterTableWithDropColumn_throw( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callBooleanMethod( "supportsAlterTableWithDropColumn", mID );
+}
+
+sal_Int32 SAL_CALL java_sql_DatabaseMetaData::getMaxIndexLength( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callIntMethod_ThrowSQL("getMaxIndexLength", mID);
+}
+
+sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsNonNullableColumns( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callBooleanMethod( "supportsNonNullableColumns", mID );
+}
+
+OUString SAL_CALL java_sql_DatabaseMetaData::getCatalogTerm( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callStringMethod( "getCatalogTerm", mID );
+}
+
+OUString java_sql_DatabaseMetaData::impl_getIdentifierQuoteString_throw( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callStringMethod( "getIdentifierQuoteString", mID );
+}
+
+OUString SAL_CALL java_sql_DatabaseMetaData::getExtraNameCharacters( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callStringMethod( "getExtraNameCharacters", mID );
+}
+
+sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsDifferentTableCorrelationNames( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callBooleanMethod( "supportsDifferentTableCorrelationNames", mID );
+}
+
+bool java_sql_DatabaseMetaData::impl_isCatalogAtStart_throw( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callBooleanMethod( "isCatalogAtStart", mID );
+}
+
+sal_Bool SAL_CALL java_sql_DatabaseMetaData::dataDefinitionIgnoredInTransactions( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callBooleanMethod( "dataDefinitionIgnoredInTransactions", mID );
+}
+
+sal_Bool SAL_CALL java_sql_DatabaseMetaData::dataDefinitionCausesTransactionCommit( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callBooleanMethod( "dataDefinitionCausesTransactionCommit", mID );
+}
+
+sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsDataManipulationTransactionsOnly( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callBooleanMethod( "supportsDataManipulationTransactionsOnly", mID );
+}
+
+sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsDataDefinitionAndDataManipulationTransactions( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callBooleanMethod( "supportsDataDefinitionAndDataManipulationTransactions", mID );
+}
+
+sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsPositionedDelete( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callBooleanMethod( "supportsPositionedDelete", mID );
+}
+
+sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsPositionedUpdate( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callBooleanMethod( "supportsPositionedUpdate", mID );
+}
+
+sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsOpenStatementsAcrossRollback( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callBooleanMethod( "supportsOpenStatementsAcrossRollback", mID );
+}
+
+sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsOpenStatementsAcrossCommit( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callBooleanMethod( "supportsOpenStatementsAcrossCommit", mID );
+}
+
+sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsOpenCursorsAcrossCommit( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callBooleanMethod( "supportsOpenCursorsAcrossCommit", mID );
+}
+
+sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsOpenCursorsAcrossRollback( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callBooleanMethod( "supportsOpenCursorsAcrossRollback", mID );
+}
+
+sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsTransactionIsolationLevel( sal_Int32 level )
+{
+ static jmethodID mID(nullptr);
+ return impl_callBooleanMethodWithIntArg( "supportsTransactionIsolationLevel", mID, level );
+}
+
+bool java_sql_DatabaseMetaData::impl_supportsSchemasInDataManipulation_throw( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callBooleanMethod( "supportsSchemasInDataManipulation", mID );
+}
+
+sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsANSI92FullSQL( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callBooleanMethod( "supportsANSI92FullSQL", mID );
+}
+
+sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsANSI92EntryLevelSQL( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callBooleanMethod( "supportsANSI92EntryLevelSQL", mID );
+}
+
+sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsIntegrityEnhancementFacility( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callBooleanMethod( "supportsIntegrityEnhancementFacility", mID );
+}
+
+sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsSchemasInIndexDefinitions( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callBooleanMethod( "supportsSchemasInIndexDefinitions", mID );
+}
+
+bool java_sql_DatabaseMetaData::impl_supportsSchemasInTableDefinitions_throw( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callBooleanMethod( "supportsSchemasInTableDefinitions", mID );
+}
+
+bool java_sql_DatabaseMetaData::impl_supportsCatalogsInTableDefinitions_throw( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callBooleanMethod( "supportsCatalogsInTableDefinitions", mID );
+}
+
+sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsCatalogsInIndexDefinitions( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callBooleanMethod( "supportsCatalogsInIndexDefinitions", mID );
+}
+
+bool java_sql_DatabaseMetaData::impl_supportsCatalogsInDataManipulation_throw( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callBooleanMethod( "supportsCatalogsInDataManipulation", mID );
+}
+
+sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsOuterJoins( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callBooleanMethod( "supportsOuterJoins", mID );
+}
+
+Reference< XResultSet > SAL_CALL java_sql_DatabaseMetaData::getTableTypes( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callResultSetMethod( "getTableTypes", mID );
+}
+
+sal_Int32 java_sql_DatabaseMetaData::impl_getMaxStatements_throw( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callIntMethod_ThrowSQL("getMaxStatements", mID);
+}
+
+sal_Int32 SAL_CALL java_sql_DatabaseMetaData::getMaxProcedureNameLength( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callIntMethod_ThrowSQL("getMaxProcedureNameLength", mID);
+}
+
+sal_Int32 SAL_CALL java_sql_DatabaseMetaData::getMaxSchemaNameLength( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callIntMethod_ThrowSQL("getMaxSchemaNameLength", mID);
+}
+
+sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsTransactions( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callBooleanMethod( "supportsTransactions", mID );
+}
+
+
+sal_Bool SAL_CALL java_sql_DatabaseMetaData::allProceduresAreCallable( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callBooleanMethod( "allProceduresAreCallable", mID );
+}
+
+sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsStoredProcedures( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callBooleanMethod( "supportsStoredProcedures", mID );
+}
+
+sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsSelectForUpdate( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callBooleanMethod( "supportsSelectForUpdate", mID );
+}
+
+sal_Bool SAL_CALL java_sql_DatabaseMetaData::allTablesAreSelectable( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callBooleanMethod( "allTablesAreSelectable", mID );
+}
+
+sal_Bool SAL_CALL java_sql_DatabaseMetaData::isReadOnly( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callBooleanMethod( "isReadOnly", mID );
+}
+
+sal_Bool SAL_CALL java_sql_DatabaseMetaData::usesLocalFiles( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callBooleanMethod( "usesLocalFiles", mID );
+}
+
+sal_Bool SAL_CALL java_sql_DatabaseMetaData::usesLocalFilePerTable( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callBooleanMethod( "usesLocalFilePerTable", mID );
+}
+
+sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsTypeConversion( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callBooleanMethod( "supportsTypeConversion", mID );
+}
+
+sal_Bool SAL_CALL java_sql_DatabaseMetaData::nullPlusNonNullIsNull( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callBooleanMethod( "nullPlusNonNullIsNull", mID );
+}
+
+sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsColumnAliasing( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callBooleanMethod( "supportsColumnAliasing", mID );
+}
+
+sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsTableCorrelationNames( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callBooleanMethod( "supportsTableCorrelationNames", mID );
+}
+
+sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsConvert( sal_Int32 fromType, sal_Int32 toType )
+{
+ static const char* const pMethodName = "supportsConvert";
+ m_aLogger.log( LogLevel::FINEST, STR_LOG_META_DATA_METHOD_ARG2, pMethodName, fromType, toType );
+
+ bool out( false );
+ SDBThreadAttach t;
+
+ {
+ static jmethodID mID(nullptr);
+ obtainMethodId_throwSQL(t.pEnv, pMethodName,"(II)Z", mID);
+ out = t.pEnv->CallBooleanMethod( object, mID, fromType, toType );
+ ThrowLoggedSQLException( m_aLogger, t.pEnv, *this );
+ }
+
+ m_aLogger.log< const char*, bool >( LogLevel::FINEST, STR_LOG_META_DATA_RESULT, pMethodName, out );
+ return out;
+}
+
+sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsExpressionsInOrderBy( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callBooleanMethod( "supportsExpressionsInOrderBy", mID );
+}
+
+sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsGroupBy( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callBooleanMethod( "supportsGroupBy", mID );
+}
+
+sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsGroupByBeyondSelect( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callBooleanMethod( "supportsGroupByBeyondSelect", mID );
+}
+
+sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsGroupByUnrelated( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callBooleanMethod( "supportsGroupByUnrelated", mID );
+}
+
+sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsMultipleTransactions( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callBooleanMethod( "supportsMultipleTransactions", mID );
+}
+
+sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsMultipleResultSets( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callBooleanMethod( "supportsMultipleResultSets", mID );
+}
+
+sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsLikeEscapeClause( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callBooleanMethod( "supportsLikeEscapeClause", mID );
+}
+
+sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsOrderByUnrelated( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callBooleanMethod( "supportsOrderByUnrelated", mID );
+}
+
+sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsUnion( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callBooleanMethod( "supportsUnion", mID );
+}
+
+sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsUnionAll( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callBooleanMethod( "supportsUnionAll", mID );
+}
+
+sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsMixedCaseIdentifiers( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callBooleanMethod( "supportsMixedCaseIdentifiers", mID );
+}
+
+bool java_sql_DatabaseMetaData::impl_supportsMixedCaseQuotedIdentifiers_throw( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callBooleanMethod( "supportsMixedCaseQuotedIdentifiers", mID );
+}
+
+sal_Bool SAL_CALL java_sql_DatabaseMetaData::nullsAreSortedAtEnd( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callBooleanMethod( "nullsAreSortedAtEnd", mID );
+}
+
+sal_Bool SAL_CALL java_sql_DatabaseMetaData::nullsAreSortedAtStart( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callBooleanMethod( "nullsAreSortedAtStart", mID );
+}
+
+sal_Bool SAL_CALL java_sql_DatabaseMetaData::nullsAreSortedHigh( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callBooleanMethod( "nullsAreSortedHigh", mID );
+}
+
+sal_Bool SAL_CALL java_sql_DatabaseMetaData::nullsAreSortedLow( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callBooleanMethod( "nullsAreSortedLow", mID );
+}
+
+sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsSchemasInProcedureCalls( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callBooleanMethod( "supportsSchemasInProcedureCalls", mID );
+}
+
+sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsSchemasInPrivilegeDefinitions( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callBooleanMethod( "supportsSchemasInPrivilegeDefinitions", mID );
+}
+
+sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsCatalogsInProcedureCalls( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callBooleanMethod( "supportsCatalogsInProcedureCalls", mID );
+}
+
+sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsCatalogsInPrivilegeDefinitions( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callBooleanMethod( "supportsCatalogsInPrivilegeDefinitions", mID );
+}
+
+sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsCorrelatedSubqueries( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callBooleanMethod( "supportsCorrelatedSubqueries", mID );
+}
+
+sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsSubqueriesInComparisons( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callBooleanMethod( "supportsSubqueriesInComparisons", mID );
+}
+
+sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsSubqueriesInExists( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callBooleanMethod( "supportsSubqueriesInExists", mID );
+}
+
+sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsSubqueriesInIns( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callBooleanMethod( "supportsSubqueriesInIns", mID );
+}
+
+sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsSubqueriesInQuantifieds( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callBooleanMethod( "supportsSubqueriesInQuantifieds", mID );
+}
+
+sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsANSI92IntermediateSQL( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callBooleanMethod( "supportsANSI92IntermediateSQL", mID );
+}
+
+OUString SAL_CALL java_sql_DatabaseMetaData::getURL( )
+{
+ OUString sURL = m_pConnection->getURL();
+ if ( sURL.isEmpty() )
+ {
+ static jmethodID mID(nullptr);
+ sURL = impl_callStringMethod( "getURL", mID );
+ }
+ return sURL;
+}
+
+OUString SAL_CALL java_sql_DatabaseMetaData::getUserName( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callStringMethod( "getUserName", mID );
+}
+
+OUString SAL_CALL java_sql_DatabaseMetaData::getDriverName( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callStringMethod( "getDriverName", mID );
+}
+
+OUString SAL_CALL java_sql_DatabaseMetaData::getDriverVersion( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callStringMethod( "getDriverVersion", mID );
+}
+
+OUString SAL_CALL java_sql_DatabaseMetaData::getDatabaseProductVersion( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callStringMethod( "getDatabaseProductVersion", mID );
+}
+
+OUString SAL_CALL java_sql_DatabaseMetaData::getDatabaseProductName( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callStringMethod( "getDatabaseProductName", mID );
+}
+
+OUString SAL_CALL java_sql_DatabaseMetaData::getProcedureTerm( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callStringMethod( "getProcedureTerm", mID );
+}
+
+OUString SAL_CALL java_sql_DatabaseMetaData::getSchemaTerm( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callStringMethod( "getSchemaTerm", mID );
+}
+
+sal_Int32 SAL_CALL java_sql_DatabaseMetaData::getDriverMajorVersion( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callIntMethod_ThrowRuntime("getDriverMajorVersion", mID);
+}
+
+sal_Int32 SAL_CALL java_sql_DatabaseMetaData::getDefaultTransactionIsolation( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callIntMethod_ThrowSQL("getDefaultTransactionIsolation", mID);
+}
+
+sal_Int32 SAL_CALL java_sql_DatabaseMetaData::getDriverMinorVersion( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callIntMethod_ThrowRuntime("getDriverMinorVersion", mID);
+}
+
+OUString SAL_CALL java_sql_DatabaseMetaData::getSQLKeywords( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callStringMethod( "getSQLKeywords", mID );
+}
+
+OUString SAL_CALL java_sql_DatabaseMetaData::getSearchStringEscape( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callStringMethod( "getSearchStringEscape", mID );
+}
+
+OUString SAL_CALL java_sql_DatabaseMetaData::getStringFunctions( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callStringMethod( "getStringFunctions", mID );
+}
+
+OUString SAL_CALL java_sql_DatabaseMetaData::getTimeDateFunctions( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callStringMethod( "getTimeDateFunctions", mID );
+}
+
+OUString SAL_CALL java_sql_DatabaseMetaData::getSystemFunctions( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callStringMethod( "getSystemFunctions", mID );
+}
+
+OUString SAL_CALL java_sql_DatabaseMetaData::getNumericFunctions( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callStringMethod( "getNumericFunctions", mID );
+}
+
+sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsExtendedSQLGrammar( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callBooleanMethod( "supportsExtendedSQLGrammar", mID );
+}
+
+sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsCoreSQLGrammar( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callBooleanMethod( "supportsCoreSQLGrammar", mID );
+}
+
+sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsMinimumSQLGrammar( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callBooleanMethod( "supportsMinimumSQLGrammar", mID );
+}
+
+sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsFullOuterJoins( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callBooleanMethod( "supportsFullOuterJoins", mID );
+}
+
+sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsLimitedOuterJoins( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callBooleanMethod( "supportsLimitedOuterJoins", mID );
+}
+
+sal_Int32 SAL_CALL java_sql_DatabaseMetaData::getMaxColumnsInGroupBy( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callIntMethod_ThrowSQL("getMaxColumnsInGroupBy", mID);
+}
+
+sal_Int32 SAL_CALL java_sql_DatabaseMetaData::getMaxColumnsInOrderBy( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callIntMethod_ThrowSQL("getMaxColumnsInOrderBy", mID);
+}
+
+sal_Int32 SAL_CALL java_sql_DatabaseMetaData::getMaxColumnsInSelect( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callIntMethod_ThrowSQL("getMaxColumnsInSelect", mID);
+}
+
+sal_Int32 SAL_CALL java_sql_DatabaseMetaData::getMaxUserNameLength( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callIntMethod_ThrowSQL("getMaxUserNameLength", mID);
+}
+
+sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsResultSetType( sal_Int32 setType )
+{
+ static jmethodID mID(nullptr);
+ return impl_callBooleanMethodWithIntArg( "supportsResultSetType", mID, setType );
+}
+
+sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsResultSetConcurrency( sal_Int32 setType, sal_Int32 concurrency )
+{
+ static const char* const pMethodName = "supportsResultSetConcurrency";
+ m_aLogger.log( LogLevel::FINEST, STR_LOG_META_DATA_METHOD_ARG2, pMethodName, setType, concurrency );
+
+ bool out( false );
+ SDBThreadAttach t;
+
+ {
+ static jmethodID mID(nullptr);
+ obtainMethodId_throwSQL(t.pEnv, pMethodName,"(II)Z", mID);
+ out = t.pEnv->CallBooleanMethod( object, mID, setType, concurrency);
+ ThrowLoggedSQLException( m_aLogger, t.pEnv, *this );
+ }
+
+ m_aLogger.log< const char*, bool >( LogLevel::FINEST, STR_LOG_META_DATA_RESULT, pMethodName, out );
+ return out;
+}
+
+sal_Bool SAL_CALL java_sql_DatabaseMetaData::ownUpdatesAreVisible( sal_Int32 setType )
+{
+ static jmethodID mID(nullptr);
+ return impl_callBooleanMethodWithIntArg( "ownUpdatesAreVisible", mID, setType );
+}
+
+sal_Bool SAL_CALL java_sql_DatabaseMetaData::ownDeletesAreVisible( sal_Int32 setType )
+{
+ static jmethodID mID(nullptr);
+ return impl_callBooleanMethodWithIntArg( "ownDeletesAreVisible", mID, setType );
+}
+
+sal_Bool SAL_CALL java_sql_DatabaseMetaData::ownInsertsAreVisible( sal_Int32 setType )
+{
+ static jmethodID mID(nullptr);
+ return impl_callBooleanMethodWithIntArg( "ownInsertsAreVisible", mID, setType );
+}
+
+sal_Bool SAL_CALL java_sql_DatabaseMetaData::othersUpdatesAreVisible( sal_Int32 setType )
+{
+ static jmethodID mID(nullptr);
+ return impl_callBooleanMethodWithIntArg( "othersUpdatesAreVisible", mID, setType );
+}
+
+sal_Bool SAL_CALL java_sql_DatabaseMetaData::othersDeletesAreVisible( sal_Int32 setType )
+{
+ static jmethodID mID(nullptr);
+ return impl_callBooleanMethodWithIntArg( "othersDeletesAreVisible", mID, setType );
+}
+
+sal_Bool SAL_CALL java_sql_DatabaseMetaData::othersInsertsAreVisible( sal_Int32 setType )
+{
+ static jmethodID mID(nullptr);
+ return impl_callBooleanMethodWithIntArg( "othersInsertsAreVisible", mID, setType );
+}
+
+sal_Bool SAL_CALL java_sql_DatabaseMetaData::updatesAreDetected( sal_Int32 setType )
+{
+ static jmethodID mID(nullptr);
+ return impl_callBooleanMethodWithIntArg( "updatesAreDetected", mID, setType );
+}
+
+sal_Bool SAL_CALL java_sql_DatabaseMetaData::deletesAreDetected( sal_Int32 setType )
+{
+ static jmethodID mID(nullptr);
+ return impl_callBooleanMethodWithIntArg( "deletesAreDetected", mID, setType );
+}
+
+sal_Bool SAL_CALL java_sql_DatabaseMetaData::insertsAreDetected( sal_Int32 setType )
+{
+ static jmethodID mID(nullptr);
+ return impl_callBooleanMethodWithIntArg( "insertsAreDetected", mID, setType );
+}
+
+sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsBatchUpdates( )
+{
+ static jmethodID mID(nullptr);
+ return impl_callBooleanMethod( "supportsBatchUpdates", mID );
+}
+
+Reference< XResultSet > SAL_CALL java_sql_DatabaseMetaData::getUDTs(
+ const Any& catalog, const OUString& schemaPattern, const OUString& typeNamePattern,
+ const Sequence< sal_Int32 >& types )
+{
+ jobject out(nullptr);
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+ {
+
+
+ static const char * const cSignature = "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;[I)Ljava/sql/ResultSet;";
+ static const char * const cMethodName = "getUDTs";
+ // dismiss Java-Call
+ static jmethodID mID(nullptr);
+ obtainMethodId_throwSQL(t.pEnv, cMethodName,cSignature, mID);
+ {
+ jvalue args[4];
+ // initialize temporary Variable
+ args[0].l = catalog.hasValue() ? convertwchar_tToJavaString(t.pEnv,comphelper::getString(catalog)) : nullptr;
+ args[1].l = schemaPattern.toChar() == '%' ? nullptr : convertwchar_tToJavaString(t.pEnv,schemaPattern);
+ args[2].l = convertwchar_tToJavaString(t.pEnv,typeNamePattern);
+ jintArray pArray = t.pEnv->NewIntArray(types.getLength());
+ jint * typesData = reinterpret_cast<jint *>(
+ const_cast<sal_Int32 *>(types.getConstArray()));
+ // 4th param of Set*ArrayRegion changed from pointer to non-const to
+ // pointer to const between <http://docs.oracle.com/javase/6/docs/
+ // technotes/guides/jni/spec/functions.html#wp22933> and
+ // <http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/
+ // functions.html#wp22933>; work around that difference in a way
+ // that doesn't trigger loplugin:redundantcast
+ t.pEnv->SetIntArrayRegion(pArray,0,types.getLength(),typesData);
+ args[3].l = pArray;
+
+ out = t.pEnv->CallObjectMethod( object, mID, args[0].l, args[1].l,args[2].l,args[3].l);
+
+ if(catalog.hasValue())
+ t.pEnv->DeleteLocalRef(static_cast<jstring>(args[0].l));
+ if(!schemaPattern.isEmpty())
+ t.pEnv->DeleteLocalRef(static_cast<jstring>(args[1].l));
+ if(!typeNamePattern.isEmpty())
+ t.pEnv->DeleteLocalRef(static_cast<jstring>(args[2].l));
+ if(args[3].l)
+ t.pEnv->DeleteLocalRef(static_cast<jintArray>(args[3].l));
+ ThrowLoggedSQLException( m_aLogger, t.pEnv, *this );
+ }
+ }
+
+ return out ? new java_sql_ResultSet( t.pEnv, out, m_aLogger,*m_pConnection ) : nullptr;
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/jdbc/Date.cxx b/connectivity/source/drivers/jdbc/Date.cxx
new file mode 100644
index 0000000000..6086e81906
--- /dev/null
+++ b/connectivity/source/drivers/jdbc/Date.cxx
@@ -0,0 +1,38 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <java/util/Date.hxx>
+
+using namespace connectivity;
+
+//************ Class: java.util.Date
+
+jclass java_util_Date::theClass = nullptr;
+
+java_util_Date::~java_util_Date() {}
+
+jclass java_util_Date::getMyClass() const
+{
+ // the class must be fetched only once, therefore static
+ if (!theClass)
+ theClass = findMyClass("java/util/Date");
+ return theClass;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/jdbc/DriverPropertyInfo.cxx b/connectivity/source/drivers/jdbc/DriverPropertyInfo.cxx
new file mode 100644
index 0000000000..3fb157fb24
--- /dev/null
+++ b/connectivity/source/drivers/jdbc/DriverPropertyInfo.cxx
@@ -0,0 +1,40 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <java/sql/DriverPropertyInfo.hxx>
+
+using namespace connectivity;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+
+//************ Class: java.sql.Driver
+
+jclass java_sql_DriverPropertyInfo::theClass = nullptr;
+
+java_sql_DriverPropertyInfo::~java_sql_DriverPropertyInfo() {}
+
+jclass java_sql_DriverPropertyInfo::getMyClass() const
+{
+ // the class must be fetched only once, therefore static
+ if (!theClass)
+ theClass = findMyClass("java/sql/DriverPropertyInfo");
+ return theClass;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/jdbc/Exception.cxx b/connectivity/source/drivers/jdbc/Exception.cxx
new file mode 100644
index 0000000000..9fa2d5c18c
--- /dev/null
+++ b/connectivity/source/drivers/jdbc/Exception.cxx
@@ -0,0 +1,37 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <java/lang/Exception.hxx>
+using namespace connectivity;
+
+//************ Class: java.lang.Exception
+
+jclass java_lang_Exception::theClass = nullptr;
+
+java_lang_Exception::~java_lang_Exception() {}
+
+jclass java_lang_Exception::getMyClass() const
+{
+ // the class must be fetched only once, therefore static
+ if (!theClass)
+ theClass = findMyClass("java/lang/Exception");
+ return theClass;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/jdbc/InputStream.cxx b/connectivity/source/drivers/jdbc/InputStream.cxx
new file mode 100644
index 0000000000..c384760b3a
--- /dev/null
+++ b/connectivity/source/drivers/jdbc/InputStream.cxx
@@ -0,0 +1,113 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+#include <sal/log.hxx>
+
+#include <com/sun/star/io/BufferSizeExceededException.hpp>
+#include <java/io/InputStream.hxx>
+#include <osl/diagnose.h>
+
+#include <string.h>
+
+using namespace connectivity;
+
+#if OSL_DEBUG_LEVEL > 0
+#define THROW_WHERE SAL_WHERE
+#else
+#define THROW_WHERE ""
+#endif
+
+
+//************ Class: java.io.InputStream
+
+
+jclass java_io_InputStream::theClass = nullptr;
+java_io_InputStream::java_io_InputStream( JNIEnv * pEnv, jobject myObj )
+ : java_lang_Object( pEnv, myObj )
+{
+ SDBThreadAttach::addRef();
+}
+java_io_InputStream::~java_io_InputStream()
+{
+ SDBThreadAttach::releaseRef();
+}
+
+jclass java_io_InputStream::getMyClass() const
+{
+ // the class must be fetched only once, therefore static
+ if( !theClass )
+ theClass = findMyClass("java/io/InputStream");
+ return theClass;
+}
+
+
+sal_Int32 SAL_CALL java_io_InputStream::readSomeBytes( css::uno::Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead )
+{
+ return readBytes(aData,nMaxBytesToRead);
+}
+
+void SAL_CALL java_io_InputStream::skipBytes( sal_Int32 nBytesToSkip )
+{
+ static jmethodID mID(nullptr);
+ callIntMethodWithIntArg_ThrowRuntime("skip",mID,nBytesToSkip);
+}
+
+sal_Int32 SAL_CALL java_io_InputStream::available( )
+{
+ static jmethodID mID(nullptr);
+ return callIntMethod_ThrowRuntime("available", mID);
+}
+
+void SAL_CALL java_io_InputStream::closeInput( )
+{
+ static jmethodID mID(nullptr);
+ callVoidMethod_ThrowRuntime("close",mID);
+}
+
+sal_Int32 SAL_CALL java_io_InputStream::readBytes( css::uno::Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead )
+{
+ if (nBytesToRead < 0)
+ throw css::io::BufferSizeExceededException( THROW_WHERE, *this );
+
+ jint out(0);
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+
+ {
+ jbyteArray pByteArray = t.pEnv->NewByteArray(nBytesToRead);
+ static const char * const cSignature = "([BII)I";
+ static const char * const cMethodName = "read";
+ // execute Java-Call
+ static jmethodID mID(nullptr);
+ obtainMethodId_throwRuntime(t.pEnv, cMethodName,cSignature, mID);
+ out = t.pEnv->CallIntMethod( object, mID, pByteArray, 0, nBytesToRead );
+ if ( !out )
+ ThrowRuntimeException(t.pEnv,*this);
+ if(out > 0)
+ {
+ jboolean p = false;
+ aData.realloc ( out );
+ memcpy(aData.getArray(),t.pEnv->GetByteArrayElements(pByteArray,&p),out);
+ }
+ t.pEnv->DeleteLocalRef(pByteArray);
+ } //t.pEnv
+ return out;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/jdbc/JBigDecimal.cxx b/connectivity/source/drivers/jdbc/JBigDecimal.cxx
new file mode 100644
index 0000000000..7cbcd64860
--- /dev/null
+++ b/connectivity/source/drivers/jdbc/JBigDecimal.cxx
@@ -0,0 +1,79 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <java/math/BigDecimal.hxx>
+#include <java/tools.hxx>
+using namespace connectivity;
+
+//************ Class: java.lang.Boolean
+
+
+jclass java_math_BigDecimal::theClass = nullptr;
+
+java_math_BigDecimal::~java_math_BigDecimal()
+{}
+
+jclass java_math_BigDecimal::getMyClass() const
+{
+ // the class must be fetched only once, therefore static
+ if( !theClass )
+ theClass = findMyClass("java/math/BigDecimal");
+ return theClass;
+}
+
+java_math_BigDecimal::java_math_BigDecimal( const OUString& _par0 ): java_lang_Object( nullptr, nullptr )
+{
+ SDBThreadAttach t;
+ if( !t.pEnv )
+ return;
+ // Java-Call for the Constructor
+ // initialize temporary Variable
+ static const char * const cSignature = "(Ljava/lang/String;)V";
+ jobject tempObj;
+ static jmethodID mID(nullptr);
+ obtainMethodId_throwSQL(t.pEnv, "<init>",cSignature, mID);
+
+ jstring str = convertwchar_tToJavaString(t.pEnv,_par0.replace(',','.'));
+ tempObj = t.pEnv->NewObject( getMyClass(), mID, str );
+ t.pEnv->DeleteLocalRef(str);
+ saveRef( t.pEnv, tempObj );
+ t.pEnv->DeleteLocalRef( tempObj );
+ ThrowSQLException( t.pEnv, nullptr );
+ // and cleanup
+}
+
+java_math_BigDecimal::java_math_BigDecimal( const double& _par0 ): java_lang_Object( nullptr, nullptr )
+{
+ SDBThreadAttach t;
+ if( !t.pEnv )
+ return;
+ // Java-Call for the Constructor
+ // initialize temporary Variable
+ static const char * const cSignature = "(D)V";
+ jobject tempObj;
+ static jmethodID mID(nullptr);
+ obtainMethodId_throwSQL(t.pEnv, "<init>",cSignature, mID);
+ tempObj = t.pEnv->NewObject( getMyClass(), mID, _par0 );
+ saveRef( t.pEnv, tempObj );
+ t.pEnv->DeleteLocalRef( tempObj );
+ ThrowSQLException( t.pEnv, nullptr );
+ // and cleanup
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/jdbc/JConnection.cxx b/connectivity/source/drivers/jdbc/JConnection.cxx
new file mode 100644
index 0000000000..77d0ff3879
--- /dev/null
+++ b/connectivity/source/drivers/jdbc/JConnection.cxx
@@ -0,0 +1,800 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <java/sql/Connection.hxx>
+#include <java/lang/Class.hxx>
+#include <java/tools.hxx>
+#include <java/ContextClassLoader.hxx>
+#include <java/sql/DatabaseMetaData.hxx>
+#include <java/sql/JStatement.hxx>
+#include <java/sql/Driver.hxx>
+#include <java/sql/PreparedStatement.hxx>
+#include <java/sql/CallableStatement.hxx>
+#include <java/sql/SQLWarning.hxx>
+#include <com/sun/star/sdbc/SQLWarning.hpp>
+#include <com/sun/star/beans/NamedValue.hpp>
+#include <connectivity/dbexception.hxx>
+#include <java/util/Property.hxx>
+#include <java/LocalRef.hxx>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <jvmaccess/classpath.hxx>
+#include <comphelper/namedvaluecollection.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+#include <jni.h>
+#include <strings.hrc>
+#include <unotools/confignode.hxx>
+#include <strings.hxx>
+
+#include <utility>
+#include <vector>
+#include <memory>
+
+using namespace connectivity;
+using namespace connectivity::jdbc;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+
+namespace {
+
+struct ClassMapEntry {
+ ClassMapEntry(
+ OUString theClassPath, OUString theClassName):
+ classPath(std::move(theClassPath)), className(std::move(theClassName)), classLoader(nullptr),
+ classObject(nullptr) {}
+
+ OUString classPath;
+ OUString className;
+ jweak classLoader;
+ jweak classObject;
+};
+
+typedef std::vector< ClassMapEntry > ClassMap;
+
+struct ClassMapData {
+ osl::Mutex mutex;
+
+ ClassMap map;
+};
+
+template < typename T >
+bool getLocalFromWeakRef( jweak& _weak, LocalRef< T >& _inout_local )
+{
+ _inout_local.set( static_cast< T >( _inout_local.env().NewLocalRef( _weak ) ) );
+
+ if ( !_inout_local.is() )
+ {
+ if ( _inout_local.env().ExceptionCheck())
+ {
+ return false;
+ }
+ else if ( _weak != nullptr )
+ {
+ _inout_local.env().DeleteWeakGlobalRef( _weak );
+ _weak = nullptr;
+ }
+ }
+ return true;
+}
+
+// Load a class. A map from pairs of (classPath, name) to pairs of weak Java
+// references to (ClassLoader, Class) is maintained, so that a class is only
+// loaded once.
+//
+// It may happen that the weak reference to the ClassLoader becomes null while
+// the reference to the Class remains non-null (in case the Class was actually
+// loaded by some parent of the ClassLoader), in which case the ClassLoader is
+// resurrected (which cannot cause any classes to be loaded multiple times, as
+// the ClassLoader is no longer reachable, so no classes it has ever loaded are
+// still reachable).
+//
+// Similarly, it may happen that the weak reference to the Class becomes null
+// while the reference to the ClassLoader remains non-null, in which case the
+// Class is simply re-loaded.
+//
+// This code is close to the implementation of jvmaccess::ClassPath::loadClass
+// in jvmaccess/classpath.hxx, but not close enough to avoid the duplication.
+//
+// If false is returned, a (still pending) JNI exception occurred.
+bool loadClass(
+ Reference< XComponentContext > const & context, JNIEnv& environment,
+ OUString const & classPath, OUString const & name,
+ LocalRef< jobject > * classLoaderPtr, LocalRef< jclass > * classPtr)
+{
+ OSL_ASSERT(classLoaderPtr != nullptr);
+ // For any jweak entries still present in the map upon destruction,
+ // DeleteWeakGlobalRef is not called (which is a leak):
+ static ClassMapData classMapData;
+ osl::MutexGuard g(classMapData.mutex);
+ ClassMap::iterator i(classMapData.map.begin());
+ LocalRef< jobject > cloader(environment);
+ LocalRef< jclass > cl(environment);
+ // Prune dangling weak references from the list while searching for a match,
+ // so that the list cannot grow unbounded:
+ for (; i != classMapData.map.end();)
+ {
+ LocalRef< jobject > classLoader( environment );
+ if ( !getLocalFromWeakRef( i->classLoader, classLoader ) )
+ return false;
+
+ LocalRef< jclass > classObject( environment );
+ if ( !getLocalFromWeakRef( i->classObject, classObject ) )
+ return false;
+
+ if ( !classLoader.is() && !classObject.is() )
+ {
+ i = classMapData.map.erase(i);
+ }
+ else if ( i->classPath == classPath && i->className == name )
+ {
+ cloader.set( classLoader.release() );
+ cl.set( classObject.release() );
+ break;
+ }
+ else
+ {
+ ++i;
+ }
+ }
+ if ( !cloader.is() || !cl.is() )
+ {
+ if ( i == classMapData.map.end() )
+ {
+ // Push a new ClassMapEntry (which can potentially fail) before
+ // loading the class, so that it never happens that a class is
+ // loaded but not added to the map (which could have effects on the
+ // JVM that are not easily undone). If the pushed ClassMapEntry is
+ // not used after all (return false, etc.) it will be pruned on next
+ // call because its classLoader/classObject are null:
+ classMapData.map.push_back( ClassMapEntry( classPath, name ) );
+ i = std::prev(classMapData.map.end());
+ }
+
+ LocalRef< jclass > clClass( environment );
+ clClass.set( environment.FindClass( "java/net/URLClassLoader" ) );
+ if ( !clClass.is() )
+ return false;
+
+ jweak wcloader = nullptr;
+ if (!cloader.is())
+ {
+ jmethodID ctorLoader( environment.GetMethodID( clClass.get(), "<init>", "([Ljava/net/URL;)V" ) );
+ if (ctorLoader == nullptr)
+ return false;
+
+ LocalRef< jobjectArray > arr( environment );
+ arr.set( jvmaccess::ClassPath::translateToUrls( context, &environment, classPath ) );
+ if ( !arr.is() )
+ return false;
+
+ jvalue arg;
+ arg.l = arr.get();
+ cloader.set( environment.NewObjectA( clClass.get(), ctorLoader, &arg ) );
+ if ( !cloader.is() )
+ return false;
+
+ wcloader = environment.NewWeakGlobalRef( cloader.get() );
+ if ( wcloader == nullptr )
+ return false;
+ }
+
+ jweak wcl = nullptr;
+ if ( !cl.is() )
+ {
+ jmethodID methLoadClass( environment.GetMethodID( clClass.get(), "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;" ) );
+ if ( methLoadClass == nullptr )
+ return false;
+
+ LocalRef< jstring > str( environment );
+ str.set( convertwchar_tToJavaString( &environment, name ) );
+ if ( !str.is() )
+ return false;
+
+ jvalue arg;
+ arg.l = str.get();
+ cl.set( static_cast< jclass >( environment.CallObjectMethodA( cloader.get(), methLoadClass, &arg ) ) );
+ if ( !cl.is() )
+ return false;
+
+ wcl = environment.NewWeakGlobalRef( cl.get() );
+ if ( wcl == nullptr )
+ return false;
+ }
+
+ if ( wcloader != nullptr)
+ {
+ i->classLoader = wcloader;
+ }
+ if ( wcl != nullptr )
+ {
+ i->classObject = wcl;
+ }
+ }
+
+ classLoaderPtr->set( cloader.release() );
+ classPtr->set( cl.release() );
+ return true;
+}
+
+}
+
+
+IMPLEMENT_SERVICE_INFO(java_sql_Connection,"com.sun.star.sdbcx.JConnection","com.sun.star.sdbc.Connection");
+
+
+//************ Class: java.sql.Connection
+
+jclass java_sql_Connection::theClass = nullptr;
+
+java_sql_Connection::java_sql_Connection( const java_sql_Driver& _rDriver )
+ :m_xContext( _rDriver.getContext() )
+ ,m_pDriver( &_rDriver )
+ ,m_pDriverobject(nullptr)
+ ,m_Driver_theClass(nullptr)
+ ,m_aLogger( _rDriver.getLogger() )
+ ,m_bIgnoreDriverPrivileges(true)
+ ,m_bIgnoreCurrency(false)
+{
+}
+
+java_sql_Connection::~java_sql_Connection()
+{
+ ::rtl::Reference< jvmaccess::VirtualMachine > xTest = java_lang_Object::getVM();
+ if ( !xTest.is() )
+ return;
+
+ SDBThreadAttach t;
+ clearObject(*t.pEnv);
+
+ {
+ if ( m_pDriverobject )
+ t.pEnv->DeleteGlobalRef( m_pDriverobject );
+ m_pDriverobject = nullptr;
+ if ( m_Driver_theClass )
+ t.pEnv->DeleteGlobalRef( m_Driver_theClass );
+ m_Driver_theClass = nullptr;
+ }
+ SDBThreadAttach::releaseRef();
+}
+
+void java_sql_Connection::disposing()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+
+ m_aLogger.log( LogLevel::INFO, STR_LOG_SHUTDOWN_CONNECTION );
+
+ java_sql_Connection_BASE::disposing();
+
+ if ( object )
+ {
+ static jmethodID mID(nullptr);
+ callVoidMethod_ThrowSQL("close", mID);
+ }
+}
+
+jclass java_sql_Connection::getMyClass() const
+{
+ // the class must be fetched only once, therefore static
+ if( !theClass )
+ theClass = findMyClass("java/sql/Connection");
+ return theClass;
+}
+
+
+OUString SAL_CALL java_sql_Connection::getCatalog( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed);
+
+ static jmethodID mID(nullptr);
+ return callStringMethod("getCatalog",mID);
+}
+
+Reference< XDatabaseMetaData > SAL_CALL java_sql_Connection::getMetaData( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed);
+
+
+ Reference< XDatabaseMetaData > xMetaData = m_xMetaData;
+ if(!xMetaData.is())
+ {
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+ static jmethodID mID(nullptr);
+ jobject out = callObjectMethod(t.pEnv,"getMetaData","()Ljava/sql/DatabaseMetaData;", mID);
+ if(out)
+ {
+ xMetaData = new java_sql_DatabaseMetaData( t.pEnv, out, *this );
+ m_xMetaData = xMetaData;
+ }
+ }
+
+ return xMetaData;
+}
+
+void SAL_CALL java_sql_Connection::close( )
+{
+ dispose();
+}
+
+void SAL_CALL java_sql_Connection::commit( )
+{
+ static jmethodID mID(nullptr);
+ callVoidMethod_ThrowSQL("commit", mID);
+}
+
+sal_Bool SAL_CALL java_sql_Connection::isClosed( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ static jmethodID mID(nullptr);
+ return callBooleanMethod( "isClosed", mID ) && java_sql_Connection_BASE::rBHelper.bDisposed;
+}
+
+sal_Bool SAL_CALL java_sql_Connection::isReadOnly( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed);
+ static jmethodID mID(nullptr);
+ return callBooleanMethod( "isReadOnly", mID );
+}
+
+void SAL_CALL java_sql_Connection::setCatalog( const OUString& catalog )
+{
+ static jmethodID mID(nullptr);
+ callVoidMethodWithStringArg("setCatalog",mID,catalog);
+}
+
+void SAL_CALL java_sql_Connection::rollback( )
+{
+ static jmethodID mID(nullptr);
+ callVoidMethod_ThrowSQL("rollback", mID);
+}
+
+sal_Bool SAL_CALL java_sql_Connection::getAutoCommit( )
+{
+ static jmethodID mID(nullptr);
+ return callBooleanMethod( "getAutoCommit", mID );
+}
+
+void SAL_CALL java_sql_Connection::setReadOnly( sal_Bool readOnly )
+{
+ static jmethodID mID(nullptr);
+ callVoidMethodWithBoolArg_ThrowSQL("setReadOnly", mID, readOnly);
+}
+
+void SAL_CALL java_sql_Connection::setAutoCommit( sal_Bool autoCommit )
+{
+ static jmethodID mID(nullptr);
+ callVoidMethodWithBoolArg_ThrowSQL("setAutoCommit", mID, autoCommit);
+}
+
+Reference< css::container::XNameAccess > SAL_CALL java_sql_Connection::getTypeMap( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed);
+
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+ static jmethodID mID(nullptr);
+ callObjectMethod(t.pEnv,"getTypeMap","()Ljava/util/Map;", mID);
+ // WARNING: the caller becomes the owner of the returned pointer
+ return nullptr;
+}
+
+void SAL_CALL java_sql_Connection::setTypeMap( const Reference< css::container::XNameAccess >& /*typeMap*/ )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed);
+
+ ::dbtools::throwFeatureNotImplementedSQLException( "XConnection::setTypeMap", *this );
+}
+
+
+sal_Int32 SAL_CALL java_sql_Connection::getTransactionIsolation( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed);
+
+ static jmethodID mID(nullptr);
+ return callIntMethod_ThrowSQL("getTransactionIsolation", mID);
+}
+
+void SAL_CALL java_sql_Connection::setTransactionIsolation( sal_Int32 level )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed);
+
+ static jmethodID mID(nullptr);
+ callVoidMethodWithIntArg_ThrowSQL("setTransactionIsolation", mID, level);
+}
+
+Reference< XStatement > SAL_CALL java_sql_Connection::createStatement( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed);
+ m_aLogger.log( LogLevel::FINE, STR_LOG_CREATE_STATEMENT );
+
+ SDBThreadAttach t;
+ rtl::Reference<java_sql_Statement> pStatement = new java_sql_Statement( t.pEnv, *this );
+ Reference< XStatement > xStmt = pStatement;
+ m_aStatements.push_back( WeakReferenceHelper( xStmt ) );
+
+ m_aLogger.log( LogLevel::FINE, STR_LOG_CREATED_STATEMENT_ID, pStatement->getStatementObjectID() );
+ return xStmt;
+}
+
+Reference< XPreparedStatement > SAL_CALL java_sql_Connection::prepareStatement( const OUString& sql )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed);
+ m_aLogger.log( LogLevel::FINE, STR_LOG_PREPARE_STATEMENT, sql );
+
+ SDBThreadAttach t;
+
+ rtl::Reference<java_sql_PreparedStatement> pStatement = new java_sql_PreparedStatement( t.pEnv, *this, sql );
+ Reference< XPreparedStatement > xReturn( pStatement );
+ m_aStatements.push_back(WeakReferenceHelper(xReturn));
+
+ m_aLogger.log( LogLevel::FINE, STR_LOG_PREPARED_STATEMENT_ID, pStatement->getStatementObjectID() );
+ return xReturn;
+}
+
+Reference< XPreparedStatement > SAL_CALL java_sql_Connection::prepareCall( const OUString& sql )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed);
+ m_aLogger.log( LogLevel::FINE, STR_LOG_PREPARE_CALL, sql );
+
+ SDBThreadAttach t;
+
+ rtl::Reference<java_sql_CallableStatement> pStatement = new java_sql_CallableStatement( t.pEnv, *this, sql );
+ Reference< XPreparedStatement > xStmt( pStatement );
+ m_aStatements.push_back(WeakReferenceHelper(xStmt));
+
+ m_aLogger.log( LogLevel::FINE, STR_LOG_PREPARED_CALL_ID, pStatement->getStatementObjectID() );
+ return xStmt;
+}
+
+OUString SAL_CALL java_sql_Connection::nativeSQL( const OUString& sql )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed);
+
+ OUString aStr;
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+ {
+
+ // initialize temporary Variable
+ static const char * const cSignature = "(Ljava/lang/String;)Ljava/lang/String;";
+ static const char * const cMethodName = "nativeSQL";
+ // Java-Call
+ static jmethodID mID(nullptr);
+ obtainMethodId_throwSQL(t.pEnv, cMethodName,cSignature, mID);
+ // Convert Parameter
+ jdbc::LocalRef< jstring > str( t.env(),convertwchar_tToJavaString(t.pEnv,sql));
+
+ jobject out = t.pEnv->CallObjectMethod( object, mID, str.get() );
+ aStr = JavaString2String(t.pEnv, static_cast<jstring>(out) );
+ ThrowLoggedSQLException( m_aLogger, t.pEnv, *this );
+ } //t.pEnv
+
+ m_aLogger.log( LogLevel::FINER, STR_LOG_NATIVE_SQL, sql, aStr );
+
+ return aStr;
+}
+
+void SAL_CALL java_sql_Connection::clearWarnings( )
+{
+ static jmethodID mID(nullptr);
+ callVoidMethod_ThrowSQL("clearWarnings", mID);
+}
+
+Any SAL_CALL java_sql_Connection::getWarnings( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed);
+
+ SDBThreadAttach t;
+ static jmethodID mID(nullptr);
+ jobject out = callObjectMethod(t.pEnv,"getWarnings","()Ljava/sql/SQLWarning;", mID);
+ // WARNING: the caller becomes the owner of the returned pointer
+ if( out )
+ {
+ java_sql_SQLWarning_BASE warn_base(t.pEnv, out);
+ SQLException aAsException( java_sql_SQLWarning( warn_base, *this ) );
+
+ // translate to warning
+ SQLWarning aWarning(aAsException.Message, aAsException.Context, aAsException.SQLState,
+ aAsException.ErrorCode, aAsException.NextException);
+
+ return Any( aWarning );
+ }
+
+ return Any();
+}
+
+
+namespace
+{
+ OUString lcl_getDriverLoadErrorMessage( const ::connectivity::SharedResources& _aResource,const OUString& _rDriverClass, const OUString& _rDriverClassPath )
+ {
+ OUString sError1( _aResource.getResourceStringWithSubstitution(
+ STR_NO_CLASSNAME,
+ "$classname$", _rDriverClass
+ ) );
+ if ( !_rDriverClassPath.isEmpty() )
+ {
+ const OUString sError2( _aResource.getResourceStringWithSubstitution(
+ STR_NO_CLASSNAME_PATH,
+ "$classpath$", _rDriverClassPath
+ ) );
+ sError1 += sError2;
+ } // if ( _rDriverClassPath.getLength() )
+ return sError1;
+ }
+}
+
+
+namespace
+{
+ bool lcl_setSystemProperties_nothrow( const java::sql::ConnectionLog& _rLogger,
+ JNIEnv& _rEnv, const Sequence< NamedValue >& _rSystemProperties )
+ {
+ if ( !_rSystemProperties.hasElements() )
+ // nothing to do
+ return true;
+
+ LocalRef< jclass > systemClass( _rEnv );
+ jmethodID nSetPropertyMethodID = nullptr;
+ // retrieve the java.lang.System class
+ systemClass.set( _rEnv.FindClass( "java/lang/System" ) );
+ if ( systemClass.is() )
+ {
+ nSetPropertyMethodID = _rEnv.GetStaticMethodID(
+ systemClass.get(), "setProperty", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;" );
+ }
+
+ if ( nSetPropertyMethodID == nullptr )
+ return false;
+
+ for ( auto const & systemProp : _rSystemProperties )
+ {
+ OUString sValue;
+ OSL_VERIFY( systemProp.Value >>= sValue );
+
+ _rLogger.log( LogLevel::FINER, STR_LOG_SETTING_SYSTEM_PROPERTY, systemProp.Name, sValue );
+
+ LocalRef< jstring > jName( _rEnv, convertwchar_tToJavaString( &_rEnv, systemProp.Name ) );
+ LocalRef< jstring > jValue( _rEnv, convertwchar_tToJavaString( &_rEnv, sValue ) );
+
+ _rEnv.CallStaticObjectMethod( systemClass.get(), nSetPropertyMethodID, jName.get(), jValue.get() );
+ LocalRef< jthrowable > throwable( _rEnv, _rEnv.ExceptionOccurred() );
+ if ( throwable.is() )
+ return false;
+ }
+
+ return true;
+ }
+}
+
+
+void java_sql_Connection::loadDriverFromProperties( const OUString& _sDriverClass, const OUString& _sDriverClassPath,
+ const Sequence< NamedValue >& _rSystemProperties )
+{
+ // first try if the jdbc driver is already registered at the driver manager
+ SDBThreadAttach t;
+ try
+ {
+ if ( !object )
+ {
+ if ( !lcl_setSystemProperties_nothrow( getLogger(), *t.pEnv, _rSystemProperties ) )
+ ThrowLoggedSQLException( getLogger(), t.pEnv, *this );
+
+ m_pDriverClassLoader.reset();
+
+ // here I try to find the class for jdbc driver
+ java_sql_SQLException_BASE::st_getMyClass();
+ java_lang_Throwable::st_getMyClass();
+
+ if ( _sDriverClass.isEmpty() )
+ {
+ m_aLogger.log( LogLevel::SEVERE, STR_LOG_NO_DRIVER_CLASS );
+ ::dbtools::throwGenericSQLException(
+ lcl_getDriverLoadErrorMessage( getResources(),_sDriverClass, _sDriverClassPath ),
+ *this
+ );
+ }
+ else
+ {
+ m_aLogger.log( LogLevel::INFO, STR_LOG_LOADING_DRIVER, _sDriverClass );
+ // the driver manager holds the class of the driver for later use
+ std::unique_ptr< java_lang_Class > pDrvClass;
+ if ( _sDriverClassPath.isEmpty() )
+ {
+ // if forName didn't find the class it will throw an exception
+ pDrvClass.reset(java_lang_Class::forName(_sDriverClass));
+ }
+ else
+ {
+ LocalRef< jclass > driverClass(t.env());
+ LocalRef< jobject > driverClassLoader(t.env());
+
+ loadClass(
+ m_pDriver->getContext(),
+ t.env(), _sDriverClassPath, _sDriverClass, &driverClassLoader, &driverClass );
+
+ m_pDriverClassLoader.set( driverClassLoader );
+ pDrvClass.reset( new java_lang_Class( t.pEnv, driverClass.release() ) );
+
+ ThrowLoggedSQLException( m_aLogger, t.pEnv, *this );
+ }
+ if (pDrvClass)
+ {
+ LocalRef< jobject > driverObject( t.env() );
+ driverObject.set( pDrvClass->newInstanceObject() );
+ ThrowLoggedSQLException( m_aLogger, t.pEnv, *this );
+ m_pDriverobject = driverObject.release();
+
+ if( m_pDriverobject )
+ m_pDriverobject = t.pEnv->NewGlobalRef( m_pDriverobject );
+
+ {
+ jclass tempClass = t.pEnv->GetObjectClass(m_pDriverobject);
+ if ( m_pDriverobject )
+ {
+ m_Driver_theClass = static_cast<jclass>(t.pEnv->NewGlobalRef( tempClass ));
+ t.pEnv->DeleteLocalRef( tempClass );
+ }
+ }
+ }
+ m_aLogger.log( LogLevel::INFO, STR_LOG_CONN_SUCCESS );
+ }
+ }
+ }
+ catch( const SQLException& )
+ {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ throw SQLException(
+ lcl_getDriverLoadErrorMessage( getResources(),_sDriverClass, _sDriverClassPath ),
+ *this,
+ OUString(),
+ 1000,
+ anyEx);
+ }
+ catch( Exception& )
+ {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ ::dbtools::throwGenericSQLException(
+ lcl_getDriverLoadErrorMessage( getResources(),_sDriverClass, _sDriverClassPath ),
+ *this,
+ anyEx
+ );
+ }
+}
+
+OUString java_sql_Connection::impl_getJavaDriverClassPath_nothrow(const OUString& _sDriverClass)
+{
+ static constexpr OUStringLiteral s_sNodeName
+ = u"org.openoffice.Office.DataAccess/JDBC/DriverClassPaths";
+ ::utl::OConfigurationTreeRoot aNamesRoot = ::utl::OConfigurationTreeRoot::createWithComponentContext(
+ m_pDriver->getContext(), s_sNodeName, -1, ::utl::OConfigurationTreeRoot::CM_READONLY);
+ OUString sURL;
+ if ( aNamesRoot.isValid() && aNamesRoot.hasByName( _sDriverClass ) )
+ {
+ ::utl::OConfigurationNode aRegisterObj = aNamesRoot.openNode( _sDriverClass );
+ OSL_VERIFY( aRegisterObj.getNodeValue( "Path" ) >>= sURL );
+ }
+ return sURL;
+}
+
+bool java_sql_Connection::construct(const OUString& url,
+ const Sequence< PropertyValue >& info)
+{
+ { // initialize the java vm
+ ::rtl::Reference< jvmaccess::VirtualMachine > xTest = java_lang_Object::getVM(m_xContext);
+ if ( !xTest.is() )
+ throwGenericSQLException(STR_NO_JAVA,*this);
+ }
+ SDBThreadAttach t;
+ SDBThreadAttach::addRef(); // will be released in dtor
+ if ( !t.pEnv )
+ throwGenericSQLException(STR_NO_JAVA,*this);
+
+ OUString sGeneratedValueStatement; // contains the statement which should be used when query for automatically generated values
+ bool bAutoRetrievingEnabled = false; // set to <TRUE/> when we should allow to query for generated values
+ OUString sDriverClassPath,sDriverClass;
+ Sequence< NamedValue > aSystemProperties;
+
+ ::comphelper::NamedValueCollection aSettings( info );
+ sDriverClass = aSettings.getOrDefault( "JavaDriverClass", sDriverClass );
+ sDriverClassPath = aSettings.getOrDefault( "JavaDriverClassPath", sDriverClassPath);
+ if ( sDriverClassPath.isEmpty() )
+ sDriverClassPath = impl_getJavaDriverClassPath_nothrow(sDriverClass);
+ bAutoRetrievingEnabled = aSettings.getOrDefault( "IsAutoRetrievingEnabled", bAutoRetrievingEnabled );
+ sGeneratedValueStatement = aSettings.getOrDefault( "AutoRetrievingStatement", sGeneratedValueStatement );
+ m_bIgnoreDriverPrivileges = aSettings.getOrDefault( "IgnoreDriverPrivileges", m_bIgnoreDriverPrivileges );
+ m_bIgnoreCurrency = aSettings.getOrDefault( "IgnoreCurrency", m_bIgnoreCurrency );
+ aSystemProperties = aSettings.getOrDefault( "SystemProperties", aSystemProperties );
+ m_aCatalogRestriction = aSettings.getOrDefault( "ImplicitCatalogRestriction", Any() );
+ m_aSchemaRestriction = aSettings.getOrDefault( "ImplicitSchemaRestriction", Any() );
+
+ loadDriverFromProperties( sDriverClass, sDriverClassPath, aSystemProperties );
+
+ enableAutoRetrievingEnabled(bAutoRetrievingEnabled);
+ setAutoRetrievingStatement(sGeneratedValueStatement);
+
+ if ( t.pEnv && m_Driver_theClass && m_pDriverobject )
+ {
+ // Java-Call
+ static const char * const cSignature = "(Ljava/lang/String;Ljava/util/Properties;)Ljava/sql/Connection;";
+ static const char * const cMethodName = "connect";
+ jmethodID mID = t.pEnv->GetMethodID( m_Driver_theClass, cMethodName, cSignature );
+
+ if ( mID )
+ {
+ jvalue args[2];
+ // convert Parameter
+ args[0].l = convertwchar_tToJavaString(t.pEnv,url);
+ std::unique_ptr<java_util_Properties> pProps = createStringPropertyArray(info);
+ args[1].l = pProps->getJavaObject();
+
+ LocalRef< jobject > ensureDelete( t.env(), args[0].l );
+
+ jobject out = nullptr;
+ // In some cases (e.g.,
+ // connectivity/source/drivers/hsqldb/HDriver.cxx:1.24
+ // l. 249) the JavaDriverClassPath contains multiple jars,
+ // as creating the JavaDriverClass instance requires
+ // (reflective) access to those other jars. Now, if the
+ // JavaDriverClass is actually loaded by some parent class
+ // loader (e.g., because its jar is also on the global
+ // class path), it would still not have access to the
+ // additional jars on the JavaDriverClassPath. Hence, the
+ // JavaDriverClassPath class loader is pushed as context
+ // class loader around the JavaDriverClass instance
+ // creation:
+ // #i82222# / 2007-10-15
+ {
+ ContextClassLoaderScope ccl( t.env(), getDriverClassLoader(), getLogger(), *this );
+ out = t.pEnv->CallObjectMethod( m_pDriverobject, mID, args[0].l,args[1].l );
+ pProps.reset();
+ ThrowLoggedSQLException( m_aLogger, t.pEnv, *this );
+ }
+
+ if ( !out )
+ m_aLogger.log( LogLevel::SEVERE, STR_LOG_NO_SYSTEM_CONNECTION );
+
+ if ( out )
+ object = t.pEnv->NewGlobalRef( out );
+
+ if ( object )
+ m_aLogger.log( LogLevel::INFO, STR_LOG_GOT_JDBC_CONNECTION, url );
+
+ m_aConnectionInfo = info;
+ } //mID
+ } //t.pEnv
+ return object != nullptr;
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/jdbc/JDriver.cxx b/connectivity/source/drivers/jdbc/JDriver.cxx
new file mode 100644
index 0000000000..f294d30b49
--- /dev/null
+++ b/connectivity/source/drivers/jdbc/JDriver.cxx
@@ -0,0 +1,231 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <java/sql/Driver.hxx>
+#include <java/sql/Connection.hxx>
+#include <sal/log.hxx>
+#include <connectivity/dbexception.hxx>
+#include <jvmfwk/framework.hxx>
+#include <strings.hrc>
+#include <resource/sharedresources.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <strings.hxx>
+
+using namespace connectivity;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+
+
+java_sql_Driver::java_sql_Driver(const Reference< css::uno::XComponentContext >& _rxContext)
+ :m_aContext( _rxContext )
+ ,m_aLogger( _rxContext, "org.openoffice.sdbc.jdbcBridge" )
+{
+}
+
+java_sql_Driver::~java_sql_Driver()
+{
+}
+
+OUString SAL_CALL java_sql_Driver::getImplementationName( )
+{
+ return "com.sun.star.comp.sdbc.JDBCDriver";
+ // this name is referenced in the configuration and in the jdbc.xml
+ // Please take care when changing it.
+}
+
+sal_Bool SAL_CALL java_sql_Driver::supportsService( const OUString& _rServiceName )
+{
+ return cppu::supportsService(this, _rServiceName);
+}
+
+
+Sequence< OUString > SAL_CALL java_sql_Driver::getSupportedServiceNames( )
+{
+ return { "com.sun.star.sdbc.Driver" };
+}
+
+Reference< XConnection > SAL_CALL java_sql_Driver::connect( const OUString& url, const
+ Sequence< PropertyValue >& info )
+{
+ m_aLogger.log( LogLevel::INFO, STR_LOG_DRIVER_CONNECTING_URL, url );
+
+ Reference< XConnection > xOut;
+ if ( acceptsURL(url ) )
+ {
+ rtl::Reference<java_sql_Connection> pConnection = new java_sql_Connection( *this );
+ xOut = pConnection;
+ if ( !pConnection->construct(url,info) )
+ xOut.clear(); // an error occurred and the java driver didn't throw an exception
+ else
+ m_aLogger.log( LogLevel::INFO, STR_LOG_DRIVER_SUCCESS );
+ }
+ return xOut;
+}
+
+sal_Bool SAL_CALL java_sql_Driver::acceptsURL( const OUString& url )
+{
+ // don't ask the real driver for the url
+ // I feel responsible for all jdbc url's
+ bool bEnabled = false;
+ javaFrameworkError e = jfw_getEnabled(&bEnabled);
+ switch (e) {
+ case JFW_E_NONE:
+ break;
+ case JFW_E_DIRECT_MODE:
+ SAL_INFO(
+ "connectivity.jdbc",
+ "jfw_getEnabled: JFW_E_DIRECT_MODE, assuming true");
+ bEnabled = true;
+ break;
+ default:
+ SAL_WARN("connectivity.jdbc", "jfw_getEnabled: error code " << +e);
+ break;
+ }
+ return bEnabled && url.startsWith("jdbc:");
+}
+
+Sequence< DriverPropertyInfo > SAL_CALL java_sql_Driver::getPropertyInfo( const OUString& url,
+ const Sequence< PropertyValue >& /*info*/ )
+{
+ if ( acceptsURL(url) )
+ {
+ Sequence< OUString > aBooleanValues{ "false", "true" };
+
+ return
+ {
+ {
+ "JavaDriverClass"
+ ,"The JDBC driver class name."
+ ,true
+ ,OUString()
+ ,Sequence< OUString >()
+ },
+ {
+ "JavaDriverClassPath"
+ ,"The class path where to look for the JDBC driver."
+ ,true
+ , ""
+ ,Sequence< OUString >()
+ },
+ {
+ "SystemProperties"
+ ,"Additional properties to set at java.lang.System before loading the driver."
+ ,true
+ , ""
+ ,Sequence< OUString >()
+ },
+ {
+ "ParameterNameSubstitution"
+ ,"Change named parameters with '?'."
+ ,false
+ ,"false"
+ ,aBooleanValues
+ },
+ {
+ "IgnoreDriverPrivileges"
+ ,"Ignore the privileges from the database driver."
+ ,false
+ , "false"
+ ,aBooleanValues
+ },
+ {
+ "IsAutoRetrievingEnabled"
+ ,"Retrieve generated values."
+ ,false
+ ,"false"
+ ,aBooleanValues
+ },
+ {
+ "AutoRetrievingStatement"
+ ,"Auto-increment statement."
+ ,false
+ ,OUString()
+ ,Sequence< OUString >()
+ },
+ {
+ "GenerateASBeforeCorrelationName"
+ ,"Generate AS before table correlation names."
+ ,false
+ ,"false"
+ ,aBooleanValues
+ },
+ {
+ "IgnoreCurrency"
+ ,"Ignore the currency field from the ResultsetMetaData."
+ ,false
+ ,"false"
+ ,aBooleanValues
+ },
+ {
+ "EscapeDateTime"
+ ,"Escape date time format."
+ ,false
+ ,"true"
+ ,aBooleanValues
+ },
+ {
+ "TypeInfoSettings"
+ ,"Defines how the type info of the database metadata should be manipulated."
+ ,false
+ ,OUString()
+ ,Sequence< OUString > ()
+ },
+ {
+ "ImplicitCatalogRestriction"
+ ,"The catalog which should be used in getTables calls, when the caller passed NULL."
+ ,false
+ ,OUString( )
+ ,Sequence< OUString > ()
+ },
+ {
+ "ImplicitSchemaRestriction"
+ ,"The schema which should be used in getTables calls, when the caller passed NULL."
+ ,false
+ ,OUString( )
+ ,Sequence< OUString > ()
+ }
+ };
+ }
+ ::connectivity::SharedResources aResources;
+ const OUString sMessage = aResources.getResourceString(STR_URI_SYNTAX_ERROR);
+ ::dbtools::throwGenericSQLException(sMessage ,*this);
+ return Sequence< DriverPropertyInfo >();
+}
+
+sal_Int32 SAL_CALL java_sql_Driver::getMajorVersion( )
+{
+ return 1;
+}
+
+sal_Int32 SAL_CALL java_sql_Driver::getMinorVersion( )
+{
+ return 0;
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+connectivity_java_sql_Driver_get_implementation(
+ css::uno::XComponentContext* context , css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new java_sql_Driver(context));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/jdbc/JStatement.cxx b/connectivity/source/drivers/jdbc/JStatement.cxx
new file mode 100644
index 0000000000..1d5326ca63
--- /dev/null
+++ b/connectivity/source/drivers/jdbc/JStatement.cxx
@@ -0,0 +1,864 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <java/sql/JStatement.hxx>
+#include <java/sql/ResultSet.hxx>
+#include <java/sql/Connection.hxx>
+#include <java/sql/SQLWarning.hxx>
+#include <java/tools.hxx>
+#include <java/ContextClassLoader.hxx>
+#include <comphelper/property.hxx>
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <cppuhelper/typeprovider.hxx>
+#include <cppuhelper/queryinterface.hxx>
+#include <comphelper/sequence.hxx>
+#include <TConnection.hxx>
+#include <comphelper/types.hxx>
+#include <comphelper/diagnose_ex.hxx>
+#include <com/sun/star/sdbc/ResultSetConcurrency.hpp>
+#include <com/sun/star/sdbc/ResultSetType.hpp>
+
+#include <strings.hxx>
+
+#include <algorithm>
+#include <string.h>
+
+using namespace ::comphelper;
+using namespace connectivity;
+using namespace ::cppu;
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+
+
+//************ Class: java.sql.Statement
+
+
+jclass java_sql_Statement_Base::theClass = nullptr;
+
+
+java_sql_Statement_Base::java_sql_Statement_Base( JNIEnv * pEnv, java_sql_Connection& _rCon )
+ :java_sql_Statement_BASE(m_aMutex)
+ ,java_lang_Object( pEnv, nullptr )
+ ,OPropertySetHelper(java_sql_Statement_BASE::rBHelper)
+ ,m_pConnection( &_rCon )
+ ,m_aLogger( _rCon.getLogger(), java::sql::ConnectionLog::STATEMENT )
+ ,m_nResultSetConcurrency(ResultSetConcurrency::READ_ONLY)
+ ,m_nResultSetType(ResultSetType::FORWARD_ONLY)
+ ,m_bEscapeProcessing(true)
+{
+}
+
+
+java_sql_Statement_Base::~java_sql_Statement_Base()
+{
+}
+
+
+void SAL_CALL OStatement_BASE2::disposing()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+
+ if ( object )
+ {
+ static jmethodID mID(nullptr);
+ callVoidMethod_ThrowSQL("close", mID);
+ }
+
+ ::comphelper::disposeComponent(m_xGeneratedStatement);
+ m_pConnection.clear();
+
+ java_sql_Statement_Base::disposing();
+}
+
+jclass java_sql_Statement_Base::getMyClass() const
+{
+ // the class must be fetched only once, therefore static
+ if( !theClass )
+ theClass = findMyClass("java/sql/Statement");
+ return theClass;
+}
+
+void SAL_CALL java_sql_Statement_Base::disposing()
+{
+ m_aLogger.log( LogLevel::FINE, STR_LOG_CLOSING_STATEMENT );
+ java_sql_Statement_BASE::disposing();
+ clearObject();
+}
+
+
+Any SAL_CALL java_sql_Statement_Base::queryInterface( const Type & rType )
+{
+ if ( m_pConnection.is() && !m_pConnection->isAutoRetrievingEnabled() && rType == cppu::UnoType<XGeneratedResultSet>::get())
+ return Any();
+ Any aRet( java_sql_Statement_BASE::queryInterface(rType) );
+ return aRet.hasValue() ? aRet : OPropertySetHelper::queryInterface(rType);
+}
+
+Sequence< Type > SAL_CALL java_sql_Statement_Base::getTypes( )
+{
+ ::cppu::OTypeCollection aTypes( cppu::UnoType<css::beans::XMultiPropertySet>::get(),
+ cppu::UnoType<css::beans::XFastPropertySet>::get(),
+ cppu::UnoType<css::beans::XPropertySet>::get());
+
+ Sequence< Type > aOldTypes = java_sql_Statement_BASE::getTypes();
+ if ( m_pConnection.is() && !m_pConnection->isAutoRetrievingEnabled() )
+ {
+ auto [begin, end] = asNonConstRange(aOldTypes);
+ auto newEnd = std::remove(begin, end,
+ cppu::UnoType<XGeneratedResultSet>::get());
+ aOldTypes.realloc(std::distance(begin, newEnd));
+ }
+
+ return ::comphelper::concatSequences(aTypes.getTypes(),aOldTypes);
+}
+
+Reference< XResultSet > SAL_CALL java_sql_Statement_Base::getGeneratedValues( )
+{
+ m_aLogger.log( LogLevel::FINE, STR_LOG_GENERATED_VALUES );
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(java_sql_Statement_BASE::rBHelper.bDisposed);
+
+ jobject out(nullptr);
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+ createStatement(t.pEnv);
+ // initialize temporary Variable
+ try
+ {
+ static jmethodID mID(nullptr);
+ out = callResultSetMethod(t.env(),"getGeneratedKeys",mID);
+ }
+ catch(const SQLException&)
+ {
+ // ignore
+ }
+
+ Reference< XResultSet > xRes;
+ if ( !out )
+ {
+ OSL_ENSURE( m_pConnection.is() && m_pConnection->isAutoRetrievingEnabled(),"Illegal call here. isAutoRetrievingEnabled is false!");
+ if ( m_pConnection.is() )
+ {
+ OUString sStmt = m_pConnection->getTransformedGeneratedStatement(m_sSqlStatement);
+ if ( !sStmt.isEmpty() )
+ {
+ m_aLogger.log( LogLevel::FINER, STR_LOG_GENERATED_VALUES_FALLBACK, sStmt );
+ ::comphelper::disposeComponent(m_xGeneratedStatement);
+ m_xGeneratedStatement = m_pConnection->createStatement();
+ xRes = m_xGeneratedStatement->executeQuery(sStmt);
+ }
+ }
+ }
+ else
+ xRes = new java_sql_ResultSet( t.pEnv, out, m_aLogger,*m_pConnection, this );
+ return xRes;
+}
+
+
+void SAL_CALL java_sql_Statement_Base::cancel( )
+{
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+ createStatement(t.pEnv);
+ static jmethodID mID(nullptr);
+ callVoidMethod_ThrowRuntime("cancel",mID);
+}
+
+
+void SAL_CALL java_sql_Statement_Base::close( )
+{
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if (java_sql_Statement_BASE::rBHelper.bDisposed)
+ throw DisposedException();
+ }
+ dispose();
+}
+
+
+void SAL_CALL java_sql_Statement::clearBatch( )
+{
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+ {
+
+ createStatement(t.pEnv);
+ static jmethodID mID(nullptr);
+ callVoidMethod_ThrowSQL("clearBatch", mID);
+ } //t.pEnv
+}
+
+
+sal_Bool SAL_CALL java_sql_Statement_Base::execute( const OUString& sql )
+{
+ m_aLogger.log( LogLevel::FINE, STR_LOG_EXECUTE_STATEMENT, sql );
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(java_sql_Statement_BASE::rBHelper.bDisposed);
+
+ bool out(false);
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+ {
+ createStatement(t.pEnv);
+ m_sSqlStatement = sql;
+ // initialize temporary Variable
+ static const char * const cSignature = "(Ljava/lang/String;)Z";
+ static const char * const cMethodName = "execute";
+ // Java-Call
+ static jmethodID mID(nullptr);
+ obtainMethodId_throwSQL(t.pEnv, cMethodName,cSignature, mID);
+ // convert Parameter
+ jdbc::LocalRef< jstring > str( t.env(), convertwchar_tToJavaString( t.pEnv, sql ) );
+ {
+ jdbc::ContextClassLoaderScope ccl( t.env(),
+ m_pConnection.is() ? m_pConnection->getDriverClassLoader() : jdbc::GlobalRef< jobject >(),
+ m_aLogger,
+ *this
+ );
+
+ out = t.pEnv->CallBooleanMethod( object, mID, str.get() );
+ ThrowLoggedSQLException( m_aLogger, t.pEnv, *this );
+ }
+ } //t.pEnv
+ return out;
+}
+
+
+Reference< XResultSet > SAL_CALL java_sql_Statement_Base::executeQuery( const OUString& sql )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(java_sql_Statement_BASE::rBHelper.bDisposed);
+ m_aLogger.log( LogLevel::FINE, STR_LOG_EXECUTE_QUERY, sql );
+
+ jobject out(nullptr);
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+
+ {
+ createStatement(t.pEnv);
+ m_sSqlStatement = sql;
+ // initialize temporary variable
+ static const char * const cSignature = "(Ljava/lang/String;)Ljava/sql/ResultSet;";
+ static const char * const cMethodName = "executeQuery";
+ // Java-Call
+ static jmethodID mID(nullptr);
+ obtainMethodId_throwSQL(t.pEnv, cMethodName,cSignature, mID);
+ // convert Parameter
+ jdbc::LocalRef< jstring > str( t.env(), convertwchar_tToJavaString( t.pEnv, sql ) );
+ {
+ jdbc::ContextClassLoaderScope ccl( t.env(),
+ m_pConnection.is() ? m_pConnection->getDriverClassLoader() : jdbc::GlobalRef< jobject >(),
+ m_aLogger,
+ *this
+ );
+
+ out = t.pEnv->CallObjectMethod( object, mID, str.get() );
+ ThrowLoggedSQLException( m_aLogger, t.pEnv, *this );
+ }
+ } //t.pEnv
+ // WARNING: the caller becomes the owner of the returned pointer
+ return out==nullptr ? nullptr : new java_sql_ResultSet( t.pEnv, out, m_aLogger, *m_pConnection,this );
+}
+
+Reference< XConnection > SAL_CALL java_sql_Statement_Base::getConnection( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(java_sql_Statement_BASE::rBHelper.bDisposed);
+ return m_pConnection;
+}
+
+
+Any SAL_CALL java_sql_Statement::queryInterface( const Type & rType )
+{
+ Any aRet = ::cppu::queryInterface(rType,static_cast< XBatchExecution*> (this));
+ return aRet.hasValue() ? aRet : java_sql_Statement_Base::queryInterface(rType);
+}
+
+
+void SAL_CALL java_sql_Statement::addBatch( const OUString& sql )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(java_sql_Statement_BASE::rBHelper.bDisposed);
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+ {
+ createStatement(t.pEnv);
+ static jmethodID mID(nullptr);
+ callVoidMethodWithStringArg("addBatch",mID,sql);
+ } //t.pEnv
+}
+
+
+Sequence< sal_Int32 > SAL_CALL java_sql_Statement::executeBatch( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(java_sql_Statement_BASE::rBHelper.bDisposed);
+ Sequence< sal_Int32 > aSeq;
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+ createStatement(t.pEnv);
+ static jmethodID mID(nullptr);
+ jintArray out = static_cast<jintArray>(callObjectMethod(t.pEnv,"executeBatch","()[I", mID));
+ if (out)
+ {
+ jboolean p = false;
+ aSeq.realloc(t.pEnv->GetArrayLength(out));
+ memcpy(aSeq.getArray(),t.pEnv->GetIntArrayElements(out,&p),aSeq.getLength());
+ t.pEnv->DeleteLocalRef(out);
+ }
+ return aSeq;
+}
+
+
+sal_Int32 SAL_CALL java_sql_Statement_Base::executeUpdate( const OUString& sql )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(java_sql_Statement_BASE::rBHelper.bDisposed);
+ m_aLogger.log( LogLevel::FINE, STR_LOG_EXECUTE_UPDATE, sql );
+
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+ createStatement(t.pEnv);
+ m_sSqlStatement = sql;
+ static jmethodID mID(nullptr);
+ return callIntMethodWithStringArg("executeUpdate",mID,sql);
+}
+
+
+Reference< css::sdbc::XResultSet > SAL_CALL java_sql_Statement_Base::getResultSet( )
+{
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+ createStatement(t.pEnv);
+ static jmethodID mID(nullptr);
+ jobject out = callResultSetMethod(t.env(),"getResultSet",mID);
+
+ // WARNING: the caller becomes the owner of the returned pointer
+ return out==nullptr ? nullptr : new java_sql_ResultSet( t.pEnv, out, m_aLogger, *m_pConnection,this );
+}
+
+
+sal_Int32 SAL_CALL java_sql_Statement_Base::getUpdateCount( )
+{
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+ createStatement(t.pEnv);
+ static jmethodID mID(nullptr);
+ sal_Int32 out = callIntMethod_ThrowSQL("getUpdateCount", mID);
+ m_aLogger.log( LogLevel::FINER, STR_LOG_UPDATE_COUNT, out );
+ return out;
+}
+
+
+sal_Bool SAL_CALL java_sql_Statement_Base::getMoreResults( )
+{
+ static jmethodID mID(nullptr);
+ return callBooleanMethod( "getMoreResults", mID );
+}
+
+
+Any SAL_CALL java_sql_Statement_Base::getWarnings( )
+{
+ SDBThreadAttach t;
+ createStatement(t.pEnv);
+ static jmethodID mID(nullptr);
+ jobject out = callObjectMethod(t.pEnv,"getWarnings","()Ljava/sql/SQLWarning;", mID);
+ // WARNING: the caller becomes the owner of the returned pointer
+ if( out )
+ {
+ java_sql_SQLWarning_BASE warn_base( t.pEnv, out );
+ return Any(
+ static_cast< css::sdbc::SQLException >(
+ java_sql_SQLWarning(warn_base,getXWeak())));
+ }
+
+ return Any();
+}
+
+void SAL_CALL java_sql_Statement_Base::clearWarnings( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(java_sql_Statement_BASE::rBHelper.bDisposed);
+ SDBThreadAttach t;
+
+ {
+ createStatement(t.pEnv);
+ static jmethodID mID(nullptr);
+ callVoidMethod_ThrowSQL("clearWarnings", mID);
+ }
+}
+
+sal_Int32 java_sql_Statement_Base::getQueryTimeOut()
+{
+ static jmethodID mID(nullptr);
+ return impl_getProperty("getQueryTimeOut",mID);
+}
+
+sal_Int32 java_sql_Statement_Base::getMaxRows()
+{
+ static jmethodID mID(nullptr);
+ return impl_getProperty("getMaxRows",mID);
+}
+
+sal_Int32 java_sql_Statement_Base::getResultSetConcurrency()
+{
+ static jmethodID mID(nullptr);
+ return impl_getProperty("getResultSetConcurrency",mID,m_nResultSetConcurrency);
+}
+
+
+sal_Int32 java_sql_Statement_Base::getResultSetType()
+{
+ static jmethodID mID(nullptr);
+ return impl_getProperty("getResultSetType",mID,m_nResultSetType);
+}
+
+sal_Int32 java_sql_Statement_Base::impl_getProperty(const char* _pMethodName, jmethodID& _inout_MethodID,sal_Int32 _nDefault)
+{
+ sal_Int32 out = _nDefault;
+ if ( object )
+ out = callIntMethod_ThrowRuntime(_pMethodName, _inout_MethodID);
+ return out;
+}
+
+sal_Int32 java_sql_Statement_Base::impl_getProperty(const char* _pMethodName, jmethodID& _inout_MethodID)
+{
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+ createStatement(t.pEnv);
+ return callIntMethod_ThrowRuntime(_pMethodName, _inout_MethodID);
+}
+
+sal_Int32 java_sql_Statement_Base::getFetchDirection()
+{
+ static jmethodID mID(nullptr);
+ return impl_getProperty("getFetchDirection",mID);
+}
+
+sal_Int32 java_sql_Statement_Base::getFetchSize()
+{
+ static jmethodID mID(nullptr);
+ return impl_getProperty("getFetchSize",mID);
+}
+
+sal_Int32 java_sql_Statement_Base::getMaxFieldSize()
+{
+ static jmethodID mID(nullptr);
+ return impl_getProperty("getMaxFieldSize",mID);
+}
+
+OUString java_sql_Statement_Base::getCursorName()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(java_sql_Statement_BASE::rBHelper.bDisposed);
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+ createStatement(t.pEnv);
+ static jmethodID mID(nullptr);
+ try
+ {
+ return callStringMethod("getCursorName",mID);
+ }
+ catch(const SQLException&)
+ {
+ }
+ return OUString();
+}
+
+void java_sql_Statement_Base::setQueryTimeOut(sal_Int32 _par0)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(java_sql_Statement_BASE::rBHelper.bDisposed);
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+ createStatement(t.pEnv);
+ static jmethodID mID(nullptr);
+ callVoidMethodWithIntArg_ThrowRuntime("setQueryTimeOut", mID, _par0);
+}
+
+
+void java_sql_Statement_Base::setEscapeProcessing(bool _par0)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(java_sql_Statement_BASE::rBHelper.bDisposed);
+ m_aLogger.log( LogLevel::FINE, STR_LOG_SET_ESCAPE_PROCESSING, _par0 );
+
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+ m_bEscapeProcessing = _par0;
+ createStatement( t.pEnv );
+ static jmethodID mID(nullptr);
+ callVoidMethodWithBoolArg_ThrowRuntime("setEscapeProcessing", mID, _par0);
+}
+
+void java_sql_Statement_Base::setMaxRows(sal_Int32 _par0)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(java_sql_Statement_BASE::rBHelper.bDisposed);
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+ createStatement(t.pEnv);
+ static jmethodID mID(nullptr);
+ callVoidMethodWithIntArg_ThrowRuntime("setMaxRows", mID, _par0);
+}
+
+void java_sql_Statement_Base::setResultSetConcurrency(sal_Int32 _par0)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(java_sql_Statement_BASE::rBHelper.bDisposed);
+ m_aLogger.log( LogLevel::FINE, STR_LOG_RESULT_SET_CONCURRENCY, _par0 );
+ m_nResultSetConcurrency = _par0;
+
+ clearObject();
+}
+
+void java_sql_Statement_Base::setResultSetType(sal_Int32 _par0)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(java_sql_Statement_BASE::rBHelper.bDisposed);
+ m_aLogger.log( LogLevel::FINE, STR_LOG_RESULT_SET_TYPE, _par0 );
+ m_nResultSetType = _par0;
+
+ clearObject();
+}
+
+void java_sql_Statement_Base::setFetchDirection(sal_Int32 _par0)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(java_sql_Statement_BASE::rBHelper.bDisposed);
+ m_aLogger.log( LogLevel::FINER, STR_LOG_FETCH_DIRECTION, _par0 );
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+ createStatement(t.pEnv);
+ static jmethodID mID(nullptr);
+ callVoidMethodWithIntArg_ThrowRuntime("setFetchDirection", mID, _par0);
+}
+
+void java_sql_Statement_Base::setFetchSize(sal_Int32 _par0)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(java_sql_Statement_BASE::rBHelper.bDisposed);
+ m_aLogger.log( LogLevel::FINER, STR_LOG_FETCH_SIZE, _par0 );
+
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+ createStatement(t.pEnv);
+ static jmethodID mID(nullptr);
+ callVoidMethodWithIntArg_ThrowRuntime("setFetchSize", mID, _par0);
+}
+
+void java_sql_Statement_Base::setMaxFieldSize(sal_Int32 _par0)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(java_sql_Statement_BASE::rBHelper.bDisposed);
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+ createStatement(t.pEnv);
+ static jmethodID mID(nullptr);
+ callVoidMethodWithIntArg_ThrowRuntime("setMaxFieldSize", mID, _par0);
+}
+
+void java_sql_Statement_Base::setCursorName(const OUString &_par0)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(java_sql_Statement_BASE::rBHelper.bDisposed);
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+ {
+ createStatement(t.pEnv);
+ static jmethodID mID(nullptr);
+ callVoidMethodWithStringArg("setCursorName",mID,_par0);
+ } //t.pEnv
+}
+
+
+::cppu::IPropertyArrayHelper* java_sql_Statement_Base::createArrayHelper( ) const
+{
+ return new ::cppu::OPropertyArrayHelper
+ {
+ {
+ {
+ ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_CURSORNAME),
+ PROPERTY_ID_CURSORNAME,
+ cppu::UnoType<OUString>::get(),
+ 0
+ },
+ {
+ ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ESCAPEPROCESSING),
+ PROPERTY_ID_ESCAPEPROCESSING,
+ cppu::UnoType<bool>::get(),
+ 0
+ },
+ {
+ ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHDIRECTION),
+ PROPERTY_ID_FETCHDIRECTION,
+ cppu::UnoType<sal_Int32>::get(),
+ 0
+ },
+ {
+ ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHSIZE),
+ PROPERTY_ID_FETCHSIZE,
+ cppu::UnoType<sal_Int32>::get(),
+ 0
+ },
+ {
+ ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_MAXFIELDSIZE),
+ PROPERTY_ID_MAXFIELDSIZE,
+ cppu::UnoType<sal_Int32>::get(),
+ 0
+ },
+ {
+ ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_MAXROWS),
+ PROPERTY_ID_MAXROWS,
+ cppu::UnoType<sal_Int32>::get(),
+ 0
+ },
+ {
+ ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_QUERYTIMEOUT),
+ PROPERTY_ID_QUERYTIMEOUT,
+ cppu::UnoType<sal_Int32>::get(),
+ 0
+ },
+ {
+ ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETCONCURRENCY),
+ PROPERTY_ID_RESULTSETCONCURRENCY,
+ cppu::UnoType<sal_Int32>::get(),
+ 0
+ },
+ {
+ ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETTYPE),
+ PROPERTY_ID_RESULTSETTYPE,
+ cppu::UnoType<sal_Int32>::get(),
+ 0
+ },
+ {
+ ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_USEBOOKMARKS),
+ PROPERTY_ID_USEBOOKMARKS,
+ cppu::UnoType<bool>::get(),
+ 0
+ }
+ }
+ };
+}
+
+
+::cppu::IPropertyArrayHelper & java_sql_Statement_Base::getInfoHelper()
+
+{
+ return *getArrayHelper();
+}
+
+sal_Bool java_sql_Statement_Base::convertFastPropertyValue(
+ Any & rConvertedValue,
+ Any & rOldValue,
+ sal_Int32 nHandle,
+ const Any& rValue )
+{
+ try
+ {
+ switch(nHandle)
+ {
+ case PROPERTY_ID_QUERYTIMEOUT:
+ return ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, getQueryTimeOut());
+ case PROPERTY_ID_MAXFIELDSIZE:
+ return ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, getMaxFieldSize());
+ case PROPERTY_ID_MAXROWS:
+ return ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, getMaxRows());
+ case PROPERTY_ID_CURSORNAME:
+ return ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, getCursorName());
+ case PROPERTY_ID_RESULTSETCONCURRENCY:
+ return ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, getResultSetConcurrency());
+ case PROPERTY_ID_RESULTSETTYPE:
+ return ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, getResultSetType());
+ case PROPERTY_ID_FETCHDIRECTION:
+ return ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, getFetchDirection());
+ case PROPERTY_ID_FETCHSIZE:
+ return ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, getFetchSize());
+ case PROPERTY_ID_ESCAPEPROCESSING:
+ return ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, m_bEscapeProcessing );
+ case PROPERTY_ID_USEBOOKMARKS:
+ // return ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, m_bAsLink);
+ default:
+ ;
+ }
+ }
+ catch(const css::lang::IllegalArgumentException&)
+ {
+ throw;
+ }
+ catch(const css::uno::Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("connectivity.jdbc");
+ }
+ return false;
+}
+
+void java_sql_Statement_Base::setFastPropertyValue_NoBroadcast(
+ sal_Int32 nHandle,
+ const Any& rValue
+ )
+{
+ switch(nHandle)
+ {
+ case PROPERTY_ID_QUERYTIMEOUT:
+ setQueryTimeOut(comphelper::getINT32(rValue));
+ break;
+ case PROPERTY_ID_MAXFIELDSIZE:
+ setMaxFieldSize(comphelper::getINT32(rValue));
+ break;
+ case PROPERTY_ID_MAXROWS:
+ setMaxRows(comphelper::getINT32(rValue));
+ break;
+ case PROPERTY_ID_CURSORNAME:
+ setCursorName(comphelper::getString(rValue));
+ break;
+ case PROPERTY_ID_RESULTSETCONCURRENCY:
+ setResultSetConcurrency(comphelper::getINT32(rValue));
+ break;
+ case PROPERTY_ID_RESULTSETTYPE:
+ setResultSetType(comphelper::getINT32(rValue));
+ break;
+ case PROPERTY_ID_FETCHDIRECTION:
+ setFetchDirection(comphelper::getINT32(rValue));
+ break;
+ case PROPERTY_ID_FETCHSIZE:
+ setFetchSize(comphelper::getINT32(rValue));
+ break;
+ case PROPERTY_ID_ESCAPEPROCESSING:
+ setEscapeProcessing( ::comphelper::getBOOL( rValue ) );
+ break;
+ case PROPERTY_ID_USEBOOKMARKS:
+ // return ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, m_bAsLink);
+ default:
+ ;
+ }
+}
+
+void java_sql_Statement_Base::getFastPropertyValue(
+ Any& rValue,
+ sal_Int32 nHandle
+ ) const
+{
+ java_sql_Statement_Base* THIS = const_cast<java_sql_Statement_Base*>(this);
+ try
+ {
+ switch(nHandle)
+ {
+ case PROPERTY_ID_QUERYTIMEOUT:
+ rValue <<= THIS->getQueryTimeOut();
+ break;
+ case PROPERTY_ID_MAXFIELDSIZE:
+ rValue <<= THIS->getMaxFieldSize();
+ break;
+ case PROPERTY_ID_MAXROWS:
+ rValue <<= THIS->getMaxRows();
+ break;
+ case PROPERTY_ID_CURSORNAME:
+ rValue <<= THIS->getCursorName();
+ break;
+ case PROPERTY_ID_RESULTSETCONCURRENCY:
+ rValue <<= THIS->getResultSetConcurrency();
+ break;
+ case PROPERTY_ID_RESULTSETTYPE:
+ rValue <<= THIS->getResultSetType();
+ break;
+ case PROPERTY_ID_FETCHDIRECTION:
+ rValue <<= THIS->getFetchDirection();
+ break;
+ case PROPERTY_ID_FETCHSIZE:
+ rValue <<= THIS->getFetchSize();
+ break;
+ case PROPERTY_ID_ESCAPEPROCESSING:
+ rValue <<= m_bEscapeProcessing;
+ break;
+ case PROPERTY_ID_USEBOOKMARKS:
+ default:
+ ;
+ }
+ }
+ catch(const Exception&)
+ {
+ }
+}
+
+jclass java_sql_Statement::theClass = nullptr;
+
+java_sql_Statement::~java_sql_Statement()
+{}
+
+jclass java_sql_Statement::getMyClass() const
+{
+ // the class must be fetched only once, therefore static
+ if( !theClass )
+ theClass = findMyClass("java/sql/Statement");
+ return theClass;
+}
+
+
+void java_sql_Statement::createStatement(JNIEnv* _pEnv)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(java_sql_Statement_BASE::rBHelper.bDisposed);
+
+ if( !_pEnv || object )
+ return;
+
+ // initialize temporary variable
+ static const char * const cMethodName = "createStatement";
+ // Java-Call
+ jobject out = nullptr;
+ static jmethodID mID(nullptr);
+ if ( !mID )
+ {
+ static const char * const cSignature = "(II)Ljava/sql/Statement;";
+ mID = _pEnv->GetMethodID( m_pConnection->getMyClass(), cMethodName, cSignature );
+ }
+ if( mID ){
+ out = _pEnv->CallObjectMethod( m_pConnection->getJavaObject(), mID,m_nResultSetType,m_nResultSetConcurrency );
+ } //mID
+ else
+ {
+ static const char * const cSignature2 = "()Ljava/sql/Statement;";
+ static jmethodID mID2 = _pEnv->GetMethodID( m_pConnection->getMyClass(), cMethodName, cSignature2 );OSL_ENSURE(mID2,"Unknown method id!");
+ if( mID2 ){
+ out = _pEnv->CallObjectMethod( m_pConnection->getJavaObject(), mID2);
+ } //mID
+ }
+ ThrowLoggedSQLException( m_aLogger, _pEnv, *this );
+
+ if ( out )
+ object = _pEnv->NewGlobalRef( out );
+}
+
+
+IMPLEMENT_SERVICE_INFO(java_sql_Statement,"com.sun.star.sdbcx.JStatement","com.sun.star.sdbc.Statement");
+
+void SAL_CALL java_sql_Statement_Base::acquire() noexcept
+{
+ java_sql_Statement_BASE::acquire();
+}
+
+void SAL_CALL java_sql_Statement_Base::release() noexcept
+{
+ java_sql_Statement_BASE::release();
+}
+
+void SAL_CALL java_sql_Statement::acquire() noexcept
+{
+ OStatement_BASE2::acquire();
+}
+
+void SAL_CALL java_sql_Statement::release() noexcept
+{
+ OStatement_BASE2::release();
+}
+
+css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL java_sql_Statement_Base::getPropertySetInfo( )
+{
+ return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper());
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/jdbc/Object.cxx b/connectivity/source/drivers/jdbc/Object.cxx
new file mode 100644
index 0000000000..f05eced9df
--- /dev/null
+++ b/connectivity/source/drivers/jdbc/Object.cxx
@@ -0,0 +1,481 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <connectivity/CommonTools.hxx>
+#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
+#include <com/sun/star/logging/LogLevel.hpp>
+#include <java/tools.hxx>
+#include <java/sql/SQLException.hxx>
+#include <osl/diagnose.h>
+#include <java/LocalRef.hxx>
+#include <strings.hxx>
+
+#include <comphelper/logging.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+
+using namespace connectivity;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+
+
+static ::rtl::Reference< jvmaccess::VirtualMachine > const & getJavaVM2(const ::rtl::Reference< jvmaccess::VirtualMachine >& _rVM = ::rtl::Reference< jvmaccess::VirtualMachine >(),
+ bool _bSet = false)
+{
+ static ::rtl::Reference< jvmaccess::VirtualMachine > s_VM;
+ if ( _rVM.is() || _bSet )
+ s_VM = _rVM;
+ return s_VM;
+}
+
+::rtl::Reference< jvmaccess::VirtualMachine > java_lang_Object::getVM(const Reference<XComponentContext >& _rxContext)
+{
+ ::rtl::Reference< jvmaccess::VirtualMachine > xVM = getJavaVM2();
+ if ( !xVM.is() && _rxContext.is() )
+ xVM = getJavaVM2(::connectivity::getJavaVM(_rxContext));
+
+ return xVM;
+}
+
+SDBThreadAttach::SDBThreadAttach()
+ : m_aGuard(java_lang_Object::getVM())
+ , pEnv(nullptr)
+{
+ pEnv = m_aGuard.getEnvironment();
+ OSL_ENSURE(pEnv,"Environment is nULL!");
+}
+
+SDBThreadAttach::~SDBThreadAttach()
+{
+}
+
+static oslInterlockedCount& getJavaVMRefCount()
+{
+ static oslInterlockedCount s_nRefCount = 0;
+ return s_nRefCount;
+}
+
+void SDBThreadAttach::addRef()
+{
+ osl_atomic_increment(&getJavaVMRefCount());
+}
+
+void SDBThreadAttach::releaseRef()
+{
+ osl_atomic_decrement(&getJavaVMRefCount());
+ if ( getJavaVMRefCount() == 0 )
+ {
+ getJavaVM2(::rtl::Reference< jvmaccess::VirtualMachine >(),true);
+ }
+}
+
+// static variables of the class
+jclass java_lang_Object::theClass = nullptr;
+
+jclass java_lang_Object::getMyClass() const
+{
+ if( !theClass )
+ theClass = findMyClass("java/lang/Object");
+ return theClass;
+}
+// the actual constructor
+java_lang_Object::java_lang_Object()
+ : object( nullptr )
+{
+ SDBThreadAttach::addRef();
+}
+
+// the protected-constructor for the derived classes
+java_lang_Object::java_lang_Object( JNIEnv * pXEnv, jobject myObj )
+ : object( nullptr )
+{
+ SDBThreadAttach::addRef();
+ if( pXEnv && myObj )
+ object = pXEnv->NewGlobalRef( myObj );
+}
+
+java_lang_Object::~java_lang_Object() COVERITY_NOEXCEPT_FALSE
+{
+ if( object )
+ {
+ SDBThreadAttach t;
+ clearObject(*t.pEnv);
+ }
+ SDBThreadAttach::releaseRef();
+}
+void java_lang_Object::clearObject(JNIEnv& rEnv)
+{
+ if( object )
+ {
+ rEnv.DeleteGlobalRef( object );
+ object = nullptr;
+ }
+}
+
+void java_lang_Object::clearObject()
+{
+ if( object )
+ {
+ SDBThreadAttach t;
+ clearObject(*t.pEnv);
+ }
+}
+// the protected-constructor for the derived classes
+void java_lang_Object::saveRef( JNIEnv * pXEnv, jobject myObj )
+{
+ OSL_ENSURE( myObj, "object in c++ -> Java Wrapper" );
+ if( myObj )
+ object = pXEnv->NewGlobalRef( myObj );
+}
+
+
+OUString java_lang_Object::toString() const
+{
+ static jmethodID mID(nullptr);
+ return callStringMethod("toString",mID);
+}
+
+
+namespace
+{
+ bool lcl_translateJNIExceptionToUNOException(
+ JNIEnv* _pEnvironment, const Reference< XInterface >& _rxContext, SQLException& _out_rException )
+ {
+ jthrowable jThrow = _pEnvironment ? _pEnvironment->ExceptionOccurred() : nullptr;
+ if ( !jThrow )
+ return false;
+
+ _pEnvironment->ExceptionClear();
+ // we have to clear the exception here because we want to handle it itself
+
+ if ( _pEnvironment->IsInstanceOf( jThrow, java_sql_SQLException_BASE::st_getMyClass() ) )
+ {
+ java_sql_SQLException_BASE aException( _pEnvironment, jThrow );
+ _out_rException = SQLException( aException.getMessage(), _rxContext,
+ aException.getSQLState(), aException.getErrorCode(), Any() );
+ return true;
+ }
+ else if ( _pEnvironment->IsInstanceOf( jThrow, java_lang_Throwable::st_getMyClass() ) )
+ {
+ java_lang_Throwable aThrow( _pEnvironment, jThrow );
+#if OSL_DEBUG_LEVEL > 0
+ aThrow.printStackTrace();
+#endif
+ OUString sMessage = aThrow.getMessage();
+ if ( sMessage.isEmpty() )
+ sMessage = aThrow.getLocalizedMessage();
+ if( sMessage.isEmpty() )
+ sMessage = aThrow.toString();
+ _out_rException = SQLException( sMessage, _rxContext, OUString(), -1, Any() );
+ return true;
+ }
+ else
+ _pEnvironment->DeleteLocalRef( jThrow );
+ return false;
+ }
+}
+
+
+void java_lang_Object::ThrowLoggedSQLException( const ::comphelper::EventLogger& _rLogger, JNIEnv* _pEnvironment,
+ const Reference< XInterface >& _rxContext )
+{
+ SQLException aException;
+ if ( lcl_translateJNIExceptionToUNOException( _pEnvironment, _rxContext, aException ) )
+ {
+ _rLogger.log( css::logging::LogLevel::SEVERE, STR_LOG_THROWING_EXCEPTION, aException.Message, aException.SQLState, aException.ErrorCode );
+ throw aException;
+ }
+}
+
+void java_lang_Object::ThrowSQLException( JNIEnv* _pEnvironment, const Reference< XInterface>& _rxContext )
+{
+ SQLException aException;
+ if ( lcl_translateJNIExceptionToUNOException( _pEnvironment, _rxContext, aException ) )
+ throw aException;
+}
+
+void java_lang_Object::ThrowRuntimeException( JNIEnv* _pEnvironment, const Reference< XInterface>& _rxContext )
+{
+ try
+ {
+ ThrowSQLException(_pEnvironment, _rxContext);
+ }
+ catch (const SQLException& e)
+ {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ throw css::lang::WrappedTargetRuntimeException( e.Message,
+ e.Context, anyEx );
+ }
+}
+
+void java_lang_Object::obtainMethodId_throwSQL(JNIEnv* _pEnv,const char* _pMethodName, const char* _pSignature,jmethodID& _inout_MethodID) const
+{
+ if ( !_inout_MethodID )
+ {
+ _inout_MethodID = _pEnv->GetMethodID( getMyClass(), _pMethodName, _pSignature );
+ OSL_ENSURE( _inout_MethodID, _pSignature );
+ if ( !_inout_MethodID )
+ throw SQLException();
+ } // if ( !_inout_MethodID )
+}
+
+void java_lang_Object::obtainMethodId_throwRuntime(JNIEnv* _pEnv,const char* _pMethodName, const char* _pSignature,jmethodID& _inout_MethodID) const
+{
+ if ( !_inout_MethodID )
+ {
+ _inout_MethodID = _pEnv->GetMethodID( getMyClass(), _pMethodName, _pSignature );
+ OSL_ENSURE( _inout_MethodID, _pSignature );
+ if ( !_inout_MethodID )
+ throw RuntimeException();
+ } // if ( !_inout_MethodID )
+}
+
+
+bool java_lang_Object::callBooleanMethod( const char* _pMethodName, jmethodID& _inout_MethodID ) const
+{
+ bool out( false );
+
+ SDBThreadAttach t;
+ OSL_ENSURE( t.pEnv, "java_lang_Object::callBooleanMethod: no Java environment anymore!" );
+ obtainMethodId_throwSQL(t.pEnv, _pMethodName,"()Z", _inout_MethodID);
+ // call method
+ out = t.pEnv->CallBooleanMethod( object, _inout_MethodID );
+ ThrowSQLException( t.pEnv, nullptr );
+
+ return out;
+}
+
+bool java_lang_Object::callBooleanMethodWithIntArg( const char* _pMethodName, jmethodID& _inout_MethodID, sal_Int32 _nArgument ) const
+{
+ bool out( false );
+ SDBThreadAttach t;
+ OSL_ENSURE( t.pEnv, "java_lang_Object::callBooleanMethodWithIntArg: no Java environment anymore!" );
+ obtainMethodId_throwSQL(t.pEnv, _pMethodName,"(I)Z", _inout_MethodID);
+ // call method
+ out = t.pEnv->CallBooleanMethod( object, _inout_MethodID, _nArgument );
+ ThrowSQLException( t.pEnv, nullptr );
+
+ return out;
+}
+
+jobject java_lang_Object::callResultSetMethod( JNIEnv& _rEnv,const char* _pMethodName, jmethodID& _inout_MethodID ) const
+{
+ // call method
+ jobject out = callObjectMethod(&_rEnv,_pMethodName,"()Ljava/sql/ResultSet;", _inout_MethodID);
+ return out;
+}
+
+sal_Int32 java_lang_Object::callIntMethod_ThrowSQL(const char* _pMethodName, jmethodID& _inout_MethodID) const
+{
+ SDBThreadAttach t;
+ OSL_ENSURE( t.pEnv, "java_lang_Object::callIntMethod: no Java environment anymore!" );
+ obtainMethodId_throwSQL(t.pEnv, _pMethodName,"()I", _inout_MethodID);
+ // call method
+ jint out( t.pEnv->CallIntMethod( object, _inout_MethodID ) );
+ ThrowSQLException( t.pEnv, nullptr );
+ return static_cast<sal_Int32>(out);
+}
+
+sal_Int32 java_lang_Object::callIntMethod_ThrowRuntime(const char* _pMethodName, jmethodID& _inout_MethodID) const
+{
+ SDBThreadAttach t;
+ OSL_ENSURE( t.pEnv, "java_lang_Object::callIntMethod: no Java environment anymore!" );
+ obtainMethodId_throwRuntime(t.pEnv, _pMethodName,"()I", _inout_MethodID);
+ // call method
+ jint out( t.pEnv->CallIntMethod( object, _inout_MethodID ) );
+ ThrowRuntimeException(t.pEnv, nullptr);
+ return static_cast<sal_Int32>(out);
+}
+
+sal_Int32 java_lang_Object::callIntMethodWithIntArg_ThrowSQL( const char* _pMethodName, jmethodID& _inout_MethodID,sal_Int32 _nArgument ) const
+{
+ SDBThreadAttach t;
+ OSL_ENSURE( t.pEnv, "java_lang_Object::callIntMethod: no Java environment anymore!" );
+ obtainMethodId_throwSQL(t.pEnv, _pMethodName,"(I)I", _inout_MethodID);
+ // call method
+ jint out( t.pEnv->CallIntMethod( object, _inout_MethodID , _nArgument) );
+ ThrowSQLException( t.pEnv, nullptr );
+ return static_cast<sal_Int32>(out);
+}
+
+sal_Int32 java_lang_Object::callIntMethodWithIntArg_ThrowRuntime( const char* _pMethodName, jmethodID& _inout_MethodID,sal_Int32 _nArgument ) const
+{
+ SDBThreadAttach t;
+ OSL_ENSURE( t.pEnv, "java_lang_Object::callIntMethod: no Java environment anymore!" );
+ obtainMethodId_throwRuntime(t.pEnv, _pMethodName,"(I)I", _inout_MethodID);
+ // call method
+ jint out( t.pEnv->CallIntMethod( object, _inout_MethodID , _nArgument) );
+ ThrowRuntimeException(t.pEnv, nullptr);
+ return static_cast<sal_Int32>(out);
+}
+
+void java_lang_Object::callVoidMethod_ThrowSQL( const char* _pMethodName, jmethodID& _inout_MethodID) const
+{
+ SDBThreadAttach t;
+ OSL_ENSURE( t.pEnv, "java_lang_Object::callIntMethod: no Java environment anymore!" );
+ obtainMethodId_throwSQL(t.pEnv, _pMethodName,"()V", _inout_MethodID);
+
+ // call method
+ t.pEnv->CallVoidMethod( object, _inout_MethodID );
+ ThrowSQLException( t.pEnv, nullptr );
+}
+
+void java_lang_Object::callVoidMethod_ThrowRuntime( const char* _pMethodName, jmethodID& _inout_MethodID) const
+{
+ SDBThreadAttach t;
+ OSL_ENSURE( t.pEnv, "java_lang_Object::callIntMethod: no Java environment anymore!" );
+ obtainMethodId_throwRuntime(t.pEnv, _pMethodName,"()V", _inout_MethodID);
+
+ // call method
+ t.pEnv->CallVoidMethod( object, _inout_MethodID );
+ ThrowRuntimeException(t.pEnv, nullptr);
+}
+
+void java_lang_Object::callVoidMethodWithIntArg_ThrowSQL( const char* _pMethodName, jmethodID& _inout_MethodID, sal_Int32 _nArgument ) const
+{
+ SDBThreadAttach t;
+ OSL_ENSURE( t.pEnv, "java_lang_Object::callIntMethod: no Java environment anymore!" );
+ obtainMethodId_throwSQL(t.pEnv, _pMethodName,"(I)V", _inout_MethodID);
+
+ // call method
+ t.pEnv->CallVoidMethod( object, _inout_MethodID,_nArgument );
+ ThrowSQLException( t.pEnv, nullptr );
+}
+
+void java_lang_Object::callVoidMethodWithIntArg_ThrowRuntime( const char* _pMethodName, jmethodID& _inout_MethodID, sal_Int32 _nArgument ) const
+{
+ SDBThreadAttach t;
+ OSL_ENSURE( t.pEnv, "java_lang_Object::callIntMethod: no Java environment anymore!" );
+ obtainMethodId_throwRuntime(t.pEnv, _pMethodName,"(I)V", _inout_MethodID);
+
+ // call method
+ t.pEnv->CallVoidMethod( object, _inout_MethodID,_nArgument );
+ ThrowRuntimeException(t.pEnv, nullptr);
+}
+
+void java_lang_Object::callVoidMethodWithBoolArg_ThrowSQL( const char* _pMethodName, jmethodID& _inout_MethodID, bool _nArgument ) const
+{
+ SDBThreadAttach t;
+ OSL_ENSURE( t.pEnv, "java_lang_Object::callIntMethod: no Java environment anymore!" );
+ obtainMethodId_throwSQL(t.pEnv, _pMethodName,"(Z)V", _inout_MethodID);
+ // call method
+ t.pEnv->CallVoidMethod( object, _inout_MethodID,int(_nArgument) );
+ ThrowSQLException( t.pEnv, nullptr );
+}
+
+void java_lang_Object::callVoidMethodWithBoolArg_ThrowRuntime( const char* _pMethodName, jmethodID& _inout_MethodID, bool _nArgument ) const
+{
+ SDBThreadAttach t;
+ OSL_ENSURE( t.pEnv, "java_lang_Object::callIntMethod: no Java environment anymore!" );
+ obtainMethodId_throwRuntime(t.pEnv, _pMethodName,"(Z)V", _inout_MethodID);
+ // call method
+ t.pEnv->CallVoidMethod( object, _inout_MethodID,int(_nArgument) );
+ ThrowRuntimeException(t.pEnv, nullptr);
+}
+
+OUString java_lang_Object::callStringMethod( const char* _pMethodName, jmethodID& _inout_MethodID ) const
+{
+ SDBThreadAttach t;
+ OSL_ENSURE( t.pEnv, "java_lang_Object::callStringMethod: no Java environment anymore!" );
+
+ // call method
+ jstring out = static_cast<jstring>(callObjectMethod(t.pEnv,_pMethodName,"()Ljava/lang/String;", _inout_MethodID));
+ return JavaString2String( t.pEnv, out );
+}
+
+jobject java_lang_Object::callObjectMethod( JNIEnv * _pEnv,const char* _pMethodName,const char* _pSignature, jmethodID& _inout_MethodID ) const
+{
+ // obtain method ID
+ obtainMethodId_throwSQL(_pEnv, _pMethodName,_pSignature, _inout_MethodID);
+ // call method
+ jobject out = _pEnv->CallObjectMethod( object, _inout_MethodID);
+ ThrowSQLException( _pEnv, nullptr );
+ return out;
+}
+
+
+jobject java_lang_Object::callObjectMethodWithIntArg( JNIEnv * _pEnv,const char* _pMethodName,const char* _pSignature, jmethodID& _inout_MethodID , sal_Int32 _nArgument) const
+{
+ obtainMethodId_throwSQL(_pEnv, _pMethodName,_pSignature, _inout_MethodID);
+ // call method
+ jobject out = _pEnv->CallObjectMethod( object, _inout_MethodID,_nArgument );
+ ThrowSQLException( _pEnv, nullptr );
+ return out;
+}
+
+OUString java_lang_Object::callStringMethodWithIntArg( const char* _pMethodName, jmethodID& _inout_MethodID , sal_Int32 _nArgument) const
+{
+ SDBThreadAttach t;
+ OSL_ENSURE( t.pEnv, "java_lang_Object::callStringMethod: no Java environment anymore!" );
+ jstring out = static_cast<jstring>(callObjectMethodWithIntArg(t.pEnv,_pMethodName,"(I)Ljava/lang/String;",_inout_MethodID,_nArgument));
+ return JavaString2String( t.pEnv, out );
+}
+
+void java_lang_Object::callVoidMethodWithStringArg( const char* _pMethodName, jmethodID& _inout_MethodID,const OUString& _nArgument ) const
+{
+ SDBThreadAttach t;
+ OSL_ENSURE( t.pEnv, "java_lang_Object::callIntMethod: no Java environment anymore!" );
+ obtainMethodId_throwSQL(t.pEnv, _pMethodName,"(Ljava/lang/String;)V", _inout_MethodID);
+
+ jdbc::LocalRef< jstring > str( t.env(),convertwchar_tToJavaString(t.pEnv,_nArgument));
+ // call method
+ t.pEnv->CallVoidMethod( object, _inout_MethodID , str.get());
+ ThrowSQLException( t.pEnv, nullptr );
+}
+
+sal_Int32 java_lang_Object::callIntMethodWithStringArg( const char* _pMethodName, jmethodID& _inout_MethodID,const OUString& _nArgument ) const
+{
+ SDBThreadAttach t;
+ OSL_ENSURE( t.pEnv, "java_lang_Object::callIntMethodWithStringArg: no Java environment anymore!" );
+ obtainMethodId_throwSQL(t.pEnv, _pMethodName,"(Ljava/lang/String;)I", _inout_MethodID);
+
+ //TODO: Check if the code below is needed
+ //jdbc::LocalRef< jstring > str( t.env(), convertwchar_tToJavaString( t.pEnv, sql ) );
+ //{
+ // jdbc::ContextClassLoaderScope ccl( t.env(),
+ // m_pConnection ? m_pConnection->getDriverClassLoader() : jdbc::GlobalRef< jobject >(),
+ // m_aLogger,
+ // *this
+ // );
+
+ jdbc::LocalRef< jstring > str( t.env(),convertwchar_tToJavaString(t.pEnv,_nArgument));
+ // call method
+ jint out = t.pEnv->CallIntMethod( object, _inout_MethodID , str.get());
+ ThrowSQLException( t.pEnv, nullptr );
+ return static_cast<sal_Int32>(out);
+}
+
+jclass java_lang_Object::findMyClass(const char* _pClassName)
+{
+ // the class must be fetched only once, therefore static
+ SDBThreadAttach t;
+ jclass tempClass = t.pEnv->FindClass(_pClassName); OSL_ENSURE(tempClass,"Java : FindClass not successful!");
+ if(!tempClass)
+ {
+ t.pEnv->ExceptionDescribe();
+ t.pEnv->ExceptionClear();
+ }
+ jclass globClass = static_cast<jclass>(t.pEnv->NewGlobalRef( tempClass ));
+ t.pEnv->DeleteLocalRef( tempClass );
+ return globClass;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/jdbc/PreparedStatement.cxx b/connectivity/source/drivers/jdbc/PreparedStatement.cxx
new file mode 100644
index 0000000000..33aadcbca8
--- /dev/null
+++ b/connectivity/source/drivers/jdbc/PreparedStatement.cxx
@@ -0,0 +1,697 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <java/sql/PreparedStatement.hxx>
+#include <java/sql/ResultSet.hxx>
+#include <java/sql/ResultSetMetaData.hxx>
+#include <java/sql/Connection.hxx>
+#include <java/sql/Timestamp.hxx>
+#include <java/math/BigDecimal.hxx>
+#include <java/tools.hxx>
+#include <cppuhelper/typeprovider.hxx>
+#include <cppuhelper/queryinterface.hxx>
+#include <comphelper/sequence.hxx>
+#include <comphelper/types.hxx>
+#include <connectivity/dbtools.hxx>
+#include <connectivity/FValue.hxx>
+#include <connectivity/dbexception.hxx>
+#include <strings.hrc>
+#include <resource/sharedresources.hxx>
+#include <java/LocalRef.hxx>
+#include <strings.hxx>
+#include <string.h>
+#include <memory>
+
+using namespace connectivity;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+
+
+//************ Class: java.sql.PreparedStatement
+
+IMPLEMENT_SERVICE_INFO(java_sql_PreparedStatement,"com.sun.star.sdbcx.JPreparedStatement","com.sun.star.sdbc.PreparedStatement");
+
+java_sql_PreparedStatement::java_sql_PreparedStatement( JNIEnv * pEnv, java_sql_Connection& _rCon, const OUString& sql )
+ : OStatement_BASE2( pEnv, _rCon )
+{
+ m_sSqlStatement = sql;
+}
+
+jclass java_sql_PreparedStatement::theClass = nullptr;
+
+java_sql_PreparedStatement::~java_sql_PreparedStatement()
+{
+}
+
+
+jclass java_sql_PreparedStatement::getMyClass() const
+{
+ // the class must be fetched only once, therefore static
+ if( !theClass )
+ theClass = findMyClass("java/sql/PreparedStatement");
+ return theClass;
+}
+
+
+css::uno::Any SAL_CALL java_sql_PreparedStatement::queryInterface( const css::uno::Type & rType )
+{
+ css::uno::Any aRet = OStatement_BASE2::queryInterface(rType);
+ return aRet.hasValue() ? aRet : ::cppu::queryInterface( rType,
+ static_cast< XPreparedStatement*>(this),
+ static_cast< XParameters*>(this),
+ static_cast< XResultSetMetaDataSupplier*>(this),
+ static_cast< XPreparedBatchExecution*>(this));
+}
+
+css::uno::Sequence< css::uno::Type > SAL_CALL java_sql_PreparedStatement::getTypes( )
+{
+ ::cppu::OTypeCollection aTypes( cppu::UnoType<XPreparedStatement>::get(),
+ cppu::UnoType<XParameters>::get(),
+ cppu::UnoType<XResultSetMetaDataSupplier>::get(),
+ cppu::UnoType<XPreparedBatchExecution>::get());
+
+ return ::comphelper::concatSequences(aTypes.getTypes(),OStatement_BASE2::getTypes());
+}
+
+
+sal_Bool SAL_CALL java_sql_PreparedStatement::execute( )
+{
+ m_aLogger.log( LogLevel::FINE, STR_LOG_EXECUTING_PREPARED );
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(java_sql_Statement_BASE::rBHelper.bDisposed);
+
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+ createStatement(t.pEnv);
+ static jmethodID mID(nullptr);
+ return callBooleanMethod( "execute", mID );
+}
+
+
+sal_Int32 SAL_CALL java_sql_PreparedStatement::executeUpdate( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(java_sql_Statement_BASE::rBHelper.bDisposed);
+ m_aLogger.log( LogLevel::FINE, STR_LOG_EXECUTING_PREPARED_UPDATE );
+
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+ createStatement(t.pEnv);
+ static jmethodID mID(nullptr);
+ return callIntMethod_ThrowSQL("executeUpdate", mID);
+}
+
+
+void SAL_CALL java_sql_PreparedStatement::setString( sal_Int32 parameterIndex, const OUString& x )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(java_sql_Statement_BASE::rBHelper.bDisposed);
+ m_aLogger.log( LogLevel::FINER, STR_LOG_STRING_PARAMETER, parameterIndex, x );
+
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+ { // initialize temporary Variable
+ createStatement(t.pEnv);
+ static const char * const cSignature = "(ILjava/lang/String;)V";
+ static const char * const cMethodName = "setString";
+ // Java-Call
+ static jmethodID mID(nullptr);
+ obtainMethodId_throwSQL(t.pEnv, cMethodName,cSignature, mID);
+ jdbc::LocalRef< jstring > str( t.env(),convertwchar_tToJavaString(t.pEnv,x));
+ t.pEnv->CallVoidMethod( object, mID, parameterIndex,str.get());
+ // and clean up
+ ThrowLoggedSQLException( m_aLogger, t.pEnv, *this );
+ } //t.pEnv
+}
+
+
+css::uno::Reference< css::sdbc::XConnection > SAL_CALL java_sql_PreparedStatement::getConnection( )
+{
+ return m_pConnection;
+}
+
+
+css::uno::Reference< css::sdbc::XResultSet > SAL_CALL java_sql_PreparedStatement::executeQuery( )
+{
+ m_aLogger.log( LogLevel::FINE, STR_LOG_EXECUTING_PREPARED_QUERY );
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(java_sql_Statement_BASE::rBHelper.bDisposed);
+
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+ createStatement(t.pEnv);
+ static jmethodID mID(nullptr);
+ jobject out = callResultSetMethod(t.env(),"executeQuery",mID);
+
+ return out==nullptr ? nullptr : new java_sql_ResultSet( t.pEnv, out, m_aLogger, *m_pConnection,this);
+}
+
+
+void SAL_CALL java_sql_PreparedStatement::setBoolean( sal_Int32 parameterIndex, sal_Bool x )
+{
+ m_aLogger.log( LogLevel::FINER, STR_LOG_BOOLEAN_PARAMETER, parameterIndex, bool(x) );
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(java_sql_Statement_BASE::rBHelper.bDisposed);
+
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+ createStatement(t.pEnv);
+ static jmethodID mID(nullptr);
+ callVoidMethod_ThrowSQL("setBoolean", "(IZ)V", mID, parameterIndex, x);
+}
+
+
+void SAL_CALL java_sql_PreparedStatement::setByte( sal_Int32 parameterIndex, sal_Int8 x )
+{
+ m_aLogger.log( LogLevel::FINER, STR_LOG_BYTE_PARAMETER, parameterIndex, static_cast<sal_Int32>(x) );
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(java_sql_Statement_BASE::rBHelper.bDisposed);
+
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+ createStatement(t.pEnv);
+ static jmethodID mID(nullptr);
+ callVoidMethod_ThrowSQL("setByte", "(IB)V", mID, parameterIndex, x);
+}
+
+
+void SAL_CALL java_sql_PreparedStatement::setDate( sal_Int32 parameterIndex, const css::util::Date& x )
+{
+ m_aLogger.log( LogLevel::FINER, STR_LOG_DATE_PARAMETER, parameterIndex, x );
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(java_sql_Statement_BASE::rBHelper.bDisposed);
+
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+ createStatement(t.pEnv);
+ java_sql_Date aT(x);
+ static jmethodID mID(nullptr);
+ callVoidMethod_ThrowSQL("setDate", "(ILjava/sql/Date;)V", mID, parameterIndex, aT.getJavaObject());
+}
+
+
+void SAL_CALL java_sql_PreparedStatement::setTime( sal_Int32 parameterIndex, const css::util::Time& x )
+{
+ m_aLogger.log( LogLevel::FINER, STR_LOG_TIME_PARAMETER, parameterIndex, x );
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(java_sql_Statement_BASE::rBHelper.bDisposed);
+
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+ createStatement(t.pEnv);
+ java_sql_Time aT(x);
+ static jmethodID mID(nullptr);
+ callVoidMethod_ThrowSQL("setTime", "(ILjava/sql/Time;)V", mID, parameterIndex, aT.getJavaObject());
+}
+
+
+void SAL_CALL java_sql_PreparedStatement::setTimestamp( sal_Int32 parameterIndex, const css::util::DateTime& x )
+{
+ m_aLogger.log( LogLevel::FINER, STR_LOG_TIMESTAMP_PARAMETER, parameterIndex, x );
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(java_sql_Statement_BASE::rBHelper.bDisposed);
+
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+ createStatement(t.pEnv);
+ static jmethodID mID(nullptr);
+ java_sql_Timestamp aD(x);
+ callVoidMethod_ThrowSQL("setTimestamp", "(ILjava/sql/Timestamp;)V", mID, parameterIndex, aD.getJavaObject());
+}
+
+void SAL_CALL java_sql_PreparedStatement::setDouble( sal_Int32 parameterIndex, double x )
+{
+ m_aLogger.log( LogLevel::FINER, STR_LOG_DOUBLE_PARAMETER, parameterIndex, x );
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(java_sql_Statement_BASE::rBHelper.bDisposed);
+
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+ createStatement(t.pEnv);
+ static jmethodID mID(nullptr);
+ callVoidMethod_ThrowSQL("setDouble", "(ID)V", mID, parameterIndex, x);
+}
+
+
+void SAL_CALL java_sql_PreparedStatement::setFloat( sal_Int32 parameterIndex, float x )
+{
+ m_aLogger.log( LogLevel::FINER, STR_LOG_FLOAT_PARAMETER, parameterIndex, x );
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(java_sql_Statement_BASE::rBHelper.bDisposed);
+
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+ createStatement(t.pEnv);
+ static jmethodID mID(nullptr);
+ callVoidMethod_ThrowSQL("setFloat", "(IF)V", mID, parameterIndex, x);
+}
+
+
+void SAL_CALL java_sql_PreparedStatement::setInt( sal_Int32 parameterIndex, sal_Int32 x )
+{
+ m_aLogger.log( LogLevel::FINER, STR_LOG_INT_PARAMETER, parameterIndex, x );
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(java_sql_Statement_BASE::rBHelper.bDisposed);
+
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+ createStatement(t.pEnv);
+ static jmethodID mID(nullptr);
+ callVoidMethod_ThrowSQL("setInt", "(II)V", mID, parameterIndex, x);
+}
+
+
+void SAL_CALL java_sql_PreparedStatement::setLong( sal_Int32 parameterIndex, sal_Int64 x )
+{
+ m_aLogger.log( LogLevel::FINER, STR_LOG_LONG_PARAMETER, parameterIndex, x );
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(java_sql_Statement_BASE::rBHelper.bDisposed);
+
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+ createStatement(t.pEnv);
+ static jmethodID mID(nullptr);
+ callVoidMethod_ThrowSQL("setLong", "(IJ)V", mID, parameterIndex, x);
+}
+
+
+void SAL_CALL java_sql_PreparedStatement::setNull( sal_Int32 parameterIndex, sal_Int32 sqlType )
+{
+ m_aLogger.log( LogLevel::FINER, STR_LOG_NULL_PARAMETER, parameterIndex, sqlType );
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(java_sql_Statement_BASE::rBHelper.bDisposed);
+
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+ createStatement(t.pEnv);
+ static jmethodID mID(nullptr);
+ callVoidMethod_ThrowSQL("setNull", "(II)V", mID, parameterIndex, sqlType);
+}
+
+
+void SAL_CALL java_sql_PreparedStatement::setClob( sal_Int32 /*parameterIndex*/, const css::uno::Reference< css::sdbc::XClob >& /*x*/ )
+{
+ ::dbtools::throwFeatureNotImplementedSQLException( "XParameters::setClob", *this );
+}
+
+
+void SAL_CALL java_sql_PreparedStatement::setBlob( sal_Int32 /*parameterIndex*/, const css::uno::Reference< css::sdbc::XBlob >& /*x*/ )
+{
+ ::dbtools::throwFeatureNotImplementedSQLException( "XParameters::setBlob", *this );
+}
+
+
+void SAL_CALL java_sql_PreparedStatement::setArray( sal_Int32 /*parameterIndex*/, const css::uno::Reference< css::sdbc::XArray >& /*x*/ )
+{
+ ::dbtools::throwFeatureNotImplementedSQLException( "XParameters::setArray", *this );
+}
+
+
+void SAL_CALL java_sql_PreparedStatement::setRef( sal_Int32 /*parameterIndex*/, const css::uno::Reference< css::sdbc::XRef >& /*x*/ )
+{
+ ::dbtools::throwFeatureNotImplementedSQLException( "XParameters::setRef", *this );
+}
+
+
+void SAL_CALL java_sql_PreparedStatement::setObjectWithInfo( sal_Int32 parameterIndex, const css::uno::Any& x, sal_Int32 targetSqlType, sal_Int32 scale )
+{
+ m_aLogger.log( LogLevel::FINER, STR_LOG_OBJECT_NULL_PARAMETER, parameterIndex );
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(java_sql_Statement_BASE::rBHelper.bDisposed);
+
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+ {
+ createStatement(t.pEnv);
+
+ // initialize temporary Variable
+ static const char * const cSignature = "(ILjava/lang/Object;II)V";
+ static const char * const cMethodName = "setObject";
+ // Java-Call
+ static jmethodID mID(nullptr);
+ obtainMethodId_throwSQL(t.pEnv, cMethodName,cSignature, mID);
+ {
+ jobject obj = nullptr;
+ switch(targetSqlType)
+ {
+ case DataType::DECIMAL:
+ case DataType::NUMERIC:
+ {
+ double nTemp = 0.0;
+
+ std::unique_ptr<java_math_BigDecimal> pBigDecimal;
+ if ( x >>= nTemp)
+ {
+ pBigDecimal.reset(new java_math_BigDecimal(nTemp));
+ //setDouble(parameterIndex,nTemp);
+ //return;
+ }
+ else
+ {
+ ORowSetValue aValue;
+ aValue.fill(x);
+ const OUString sValue = aValue.getString();
+ if ( !sValue.isEmpty() )
+ pBigDecimal.reset(new java_math_BigDecimal(sValue));
+ else
+ pBigDecimal.reset(new java_math_BigDecimal(0.0));
+ }
+ //obj = convertwchar_tToJavaString(t.pEnv,::comphelper::getString(x));
+ t.pEnv->CallVoidMethod( object, mID, parameterIndex,pBigDecimal->getJavaObject(),targetSqlType,scale);
+ ThrowLoggedSQLException( m_aLogger, t.pEnv, *this );
+ return;
+ }
+ default:
+ obj = convertwchar_tToJavaString(t.pEnv,::comphelper::getString(x));
+ break;
+ }
+ t.pEnv->CallVoidMethod( object, mID, parameterIndex,obj,targetSqlType,scale);
+ t.pEnv->DeleteLocalRef(obj);
+ ThrowLoggedSQLException( m_aLogger, t.pEnv, *this );
+ // and clean up
+ } //mID
+ } //t.pEnv
+}
+
+
+void SAL_CALL java_sql_PreparedStatement::setObjectNull( sal_Int32 parameterIndex, sal_Int32 /*sqlType*/, const OUString& /*typeName*/ )
+{
+ m_aLogger.log( LogLevel::FINER, STR_LOG_OBJECT_NULL_PARAMETER, parameterIndex );
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(java_sql_Statement_BASE::rBHelper.bDisposed);
+
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+ createStatement(t.pEnv);
+ static jmethodID mID(nullptr);
+ callVoidMethod_ThrowSQL<jobject>("setObject", "(ILjava/lang/Object;)V", mID, parameterIndex, nullptr);
+}
+
+
+void SAL_CALL java_sql_PreparedStatement::setObject( sal_Int32 parameterIndex, const css::uno::Any& x )
+{
+ if(!::dbtools::implSetObject(this,parameterIndex,x))
+ {
+ const OUString sError( m_pConnection->getResources().getResourceStringWithSubstitution(
+ STR_UNKNOWN_PARA_TYPE,
+ "$position$", OUString::number(parameterIndex)
+ ) );
+ ::dbtools::throwGenericSQLException(sError,*this);
+ }
+}
+
+
+void SAL_CALL java_sql_PreparedStatement::setShort( sal_Int32 parameterIndex, sal_Int16 x )
+{
+ m_aLogger.log( LogLevel::FINER, STR_LOG_SHORT_PARAMETER, parameterIndex, x );
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(java_sql_Statement_BASE::rBHelper.bDisposed);
+
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+ createStatement(t.pEnv);
+ static jmethodID mID(nullptr);
+ callVoidMethod_ThrowSQL("setShort", "(IS)V", mID, parameterIndex, x);
+}
+
+
+void SAL_CALL java_sql_PreparedStatement::setBytes( sal_Int32 parameterIndex, const css::uno::Sequence< sal_Int8 >& x )
+{
+ m_aLogger.log( LogLevel::FINER, STR_LOG_BYTES_PARAMETER, parameterIndex );
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(java_sql_Statement_BASE::rBHelper.bDisposed);
+
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+ {
+ createStatement(t.pEnv);
+
+ // initialize temporary Variable
+ static const char * const cSignature = "(I[B)V";
+ static const char * const cMethodName = "setBytes";
+ // Java-Call
+ static jmethodID mID(nullptr);
+ obtainMethodId_throwSQL(t.pEnv, cMethodName,cSignature, mID);
+ jbyteArray pByteArray = t.pEnv->NewByteArray(x.getLength());
+ jbyte * pData = reinterpret_cast<jbyte *>(
+ const_cast<sal_Int8 *>(x.getConstArray()));
+ // 4th param of Set*ArrayRegion changed from pointer to non-const to
+ // pointer to const between <http://docs.oracle.com/javase/6/docs/
+ // technotes/guides/jni/spec/functions.html#wp22933> and
+ // <http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/
+ // functions.html#wp22933>; work around that difference in a way
+ // that doesn't trigger loplugin:redundantcast
+ t.pEnv->SetByteArrayRegion(pByteArray,0,x.getLength(),pData);
+ t.pEnv->CallVoidMethod( object, mID, parameterIndex,pByteArray);
+ t.pEnv->DeleteLocalRef(pByteArray);
+ ThrowLoggedSQLException( m_aLogger, t.pEnv, *this );
+ } //t.pEnv
+}
+
+
+void SAL_CALL java_sql_PreparedStatement::setCharacterStream( sal_Int32 parameterIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length )
+{
+ m_aLogger.log( LogLevel::FINER, STR_LOG_CHARSTREAM_PARAMETER, parameterIndex );
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(java_sql_Statement_BASE::rBHelper.bDisposed);
+
+ SDBThreadAttach t;
+ assert(t.pEnv && "Java environment has been deleted!");
+ {
+ createStatement(t.pEnv);
+
+ // initialize temporary variable
+ static const char * const cSignature = "(ILjava/io/InputStream;I)V";
+ static const char * const cMethodName = "setCharacterStream";
+ // Java-Call
+ static jmethodID mID(nullptr);
+ obtainMethodId_throwSQL(t.pEnv, cMethodName,cSignature, mID);
+ Sequence< sal_Int8 > aSeq;
+ if ( x.is() )
+ x->readBytes( aSeq, length );
+ sal_Int32 actualLength = aSeq.getLength();
+
+ jvalue args2[3];
+ jbyteArray pByteArray = t.pEnv->NewByteArray( actualLength );
+ jbyte * aSeqData = reinterpret_cast<jbyte *>(
+ const_cast<sal_Int8 *>(aSeq.getConstArray()));
+ // 4th param of Set*ArrayRegion changed from pointer to non-const to
+ // pointer to const between <http://docs.oracle.com/javase/6/docs/
+ // technotes/guides/jni/spec/functions.html#wp22933> and
+ // <http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/
+ // functions.html#wp22933>; work around that difference in a way
+ // that doesn't trigger loplugin:redundantcast
+ t.pEnv->SetByteArrayRegion(pByteArray,0,actualLength,aSeqData);
+ args2[0].l = pByteArray;
+ args2[1].i = 0;
+ args2[2].i = actualLength;
+ // Java-Call
+ jclass aClass = t.pEnv->FindClass("java/io/CharArrayInputStream");
+ static jmethodID mID2 = nullptr;
+ if ( !mID2 )
+ {
+ // initialize temporary variable
+ const char * const cSignatureStream = "([BII)V";
+ mID2 = t.pEnv->GetMethodID( aClass, "<init>", cSignatureStream );
+ }
+ jobject tempObj = nullptr;
+ if(mID2)
+ tempObj = t.pEnv->NewObjectA( aClass, mID2, args2 );
+
+ t.pEnv->CallVoidMethod( object, mID, parameterIndex,tempObj,actualLength);
+ // and clean up
+ t.pEnv->DeleteLocalRef(pByteArray);
+ t.pEnv->DeleteLocalRef(tempObj);
+ t.pEnv->DeleteLocalRef(aClass);
+ ThrowLoggedSQLException( m_aLogger, t.pEnv, *this );
+ } //t.pEnv
+}
+
+
+void SAL_CALL java_sql_PreparedStatement::setBinaryStream( sal_Int32 parameterIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length )
+{
+ m_aLogger.log( LogLevel::FINER, STR_LOG_BINARYSTREAM_PARAMETER, parameterIndex );
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(java_sql_Statement_BASE::rBHelper.bDisposed);
+
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+ {
+ createStatement(t.pEnv);
+ // initialize temporary variable
+ static const char * const cSignature = "(ILjava/io/InputStream;I)V";
+ static const char * const cMethodName = "setBinaryStream";
+ // Java-Call
+ static jmethodID mID(nullptr);
+ obtainMethodId_throwSQL(t.pEnv, cMethodName,cSignature, mID);
+ {
+ Sequence< sal_Int8 > aSeq;
+ if ( x.is() )
+ x->readBytes( aSeq, length );
+ sal_Int32 actualLength = aSeq.getLength();
+
+ jvalue args2[3];
+ jbyteArray pByteArray = t.pEnv->NewByteArray(actualLength);
+ jbyte * aSeqData = reinterpret_cast<jbyte *>(
+ const_cast<sal_Int8 *>(aSeq.getConstArray()));
+ // 4th param of Set*ArrayRegion changed from pointer to non-const to
+ // pointer to const between <http://docs.oracle.com/javase/6/docs/
+ // technotes/guides/jni/spec/functions.html#wp22933> and
+ // <http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/
+ // functions.html#wp22933>; work around that difference in a way
+ // that doesn't trigger loplugin:redundantcast
+ t.pEnv->SetByteArrayRegion(pByteArray,0,actualLength,aSeqData);
+ args2[0].l = pByteArray;
+ args2[1].i = 0;
+ args2[2].i = actualLength;
+
+ // Java-Call
+ jclass aClass = t.pEnv->FindClass("java/io/ByteArrayInputStream");
+ static jmethodID mID2 = nullptr;
+ if ( !mID2 )
+ {
+ // initialize temporary variable
+ const char * const cSignatureStream = "([BII)V";
+ mID2 = t.pEnv->GetMethodID( aClass, "<init>", cSignatureStream );
+ }
+ jobject tempObj = nullptr;
+ if(mID2)
+ tempObj = t.pEnv->NewObjectA( aClass, mID2, args2 );
+ t.pEnv->CallVoidMethod( object, mID, parameterIndex,tempObj,actualLength);
+ // and clean up
+ t.pEnv->DeleteLocalRef(pByteArray);
+ t.pEnv->DeleteLocalRef(tempObj);
+ t.pEnv->DeleteLocalRef(aClass);
+ ThrowLoggedSQLException( m_aLogger, t.pEnv, *this );
+ }
+ } //t.pEnv
+}
+
+
+void SAL_CALL java_sql_PreparedStatement::clearParameters( )
+{
+ m_aLogger.log( LogLevel::FINER, STR_LOG_CLEAR_PARAMETERS );
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(java_sql_Statement_BASE::rBHelper.bDisposed);
+
+ SDBThreadAttach t;
+ {
+ createStatement(t.pEnv);
+
+ static jmethodID mID(nullptr);
+ callVoidMethod_ThrowSQL("clearParameters",mID);
+ } //t.pEnv
+}
+
+void SAL_CALL java_sql_PreparedStatement::clearBatch( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(java_sql_Statement_BASE::rBHelper.bDisposed);
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+ {
+ createStatement(t.pEnv);
+ static jmethodID mID(nullptr);
+ callVoidMethod_ThrowSQL("clearBatch",mID);
+ } //t.pEnv
+}
+
+
+void SAL_CALL java_sql_PreparedStatement::addBatch( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(java_sql_Statement_BASE::rBHelper.bDisposed);
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+ {
+ createStatement(t.pEnv);
+ static jmethodID mID(nullptr);
+ callVoidMethod_ThrowSQL("addBatch", mID);
+ } //t.pEnv
+}
+
+
+css::uno::Sequence< sal_Int32 > SAL_CALL java_sql_PreparedStatement::executeBatch( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(java_sql_Statement_BASE::rBHelper.bDisposed);
+ css::uno::Sequence< sal_Int32 > aSeq;
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+ createStatement(t.pEnv);
+ static jmethodID mID(nullptr);
+ jintArray out = static_cast<jintArray>(callObjectMethod(t.pEnv,"executeBatch","()[I", mID));
+ if(out)
+ {
+ jboolean p = false;
+ aSeq.realloc(t.pEnv->GetArrayLength(out));
+ memcpy(aSeq.getArray(),t.pEnv->GetIntArrayElements(out,&p),aSeq.getLength());
+ t.pEnv->DeleteLocalRef(out);
+ }
+ return aSeq;
+}
+
+css::uno::Reference< css::sdbc::XResultSetMetaData > SAL_CALL java_sql_PreparedStatement::getMetaData( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(java_sql_Statement_BASE::rBHelper.bDisposed);
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+ createStatement(t.pEnv);
+ static jmethodID mID(nullptr);
+ jobject out = callObjectMethod(t.pEnv,"getMetaData","()Ljava/sql/ResultSetMetaData;", mID);
+
+ return out==nullptr ? nullptr : new java_sql_ResultSetMetaData( t.pEnv, out, *m_pConnection );
+}
+
+void SAL_CALL java_sql_PreparedStatement::acquire() noexcept
+{
+ OStatement_BASE2::acquire();
+}
+
+void SAL_CALL java_sql_PreparedStatement::release() noexcept
+{
+ OStatement_BASE2::release();
+}
+
+void java_sql_PreparedStatement::createStatement(JNIEnv* _pEnv)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(java_sql_Statement_BASE::rBHelper.bDisposed);
+
+ if( object || !_pEnv )
+ return;
+
+ // initialize temporary variable
+ static const char * const cMethodName = "prepareStatement";
+
+ jvalue args[1];
+ // convert Parameter
+ args[0].l = convertwchar_tToJavaString(_pEnv,m_sSqlStatement);
+ // Java-Call
+ jobject out = nullptr;
+ static jmethodID mID(nullptr);
+ if ( !mID )
+ {
+ static const char * const cSignature = "(Ljava/lang/String;II)Ljava/sql/PreparedStatement;";
+ mID = _pEnv->GetMethodID( m_pConnection->getMyClass(), cMethodName, cSignature );
+ }
+ if( mID )
+ {
+ out = _pEnv->CallObjectMethod( m_pConnection->getJavaObject(), mID, args[0].l ,m_nResultSetType,m_nResultSetConcurrency);
+ }
+ else
+ {
+ static jmethodID mID2 = nullptr;
+ if ( !mID2 )
+ {
+ static const char * const cSignature2 = "(Ljava/lang/String;)Ljava/sql/PreparedStatement;";
+ mID2 = _pEnv->GetMethodID( m_pConnection->getMyClass(), cMethodName, cSignature2 );
+ }
+ if ( mID2 )
+ out = _pEnv->CallObjectMethod( m_pConnection->getJavaObject(), mID2, args[0].l );
+ }
+ _pEnv->DeleteLocalRef(static_cast<jstring>(args[0].l));
+ ThrowLoggedSQLException( m_aLogger, _pEnv, *this );
+ if ( out )
+ object = _pEnv->NewGlobalRef( out );
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/jdbc/Reader.cxx b/connectivity/source/drivers/jdbc/Reader.cxx
new file mode 100644
index 0000000000..85d02e87a3
--- /dev/null
+++ b/connectivity/source/drivers/jdbc/Reader.cxx
@@ -0,0 +1,178 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <java/io/Reader.hxx>
+#include <string.h>
+#include <osl/diagnose.h>
+using namespace connectivity;
+using ::com::sun::star::uno::Sequence;
+
+
+//************ Class: java.io.Reader
+
+
+jclass java_io_Reader::theClass = nullptr;
+java_io_Reader::java_io_Reader( JNIEnv * pEnv, jobject myObj )
+ : java_lang_Object( pEnv, myObj )
+{
+ SDBThreadAttach::addRef();
+}
+java_io_Reader::~java_io_Reader()
+{
+ SDBThreadAttach::releaseRef();
+}
+
+jclass java_io_Reader::getMyClass() const
+{
+ // the class must be fetched only once, therefore static
+ if( !theClass )
+ theClass = findMyClass("java/io/Reader");
+ return theClass;
+}
+
+sal_Int32 SAL_CALL java_io_Reader::readSomeBytes( css::uno::Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead )
+{
+ return readBytes(aData,nMaxBytesToRead);
+}
+
+void SAL_CALL java_io_Reader::skipBytes( sal_Int32 nBytesToSkip )
+{
+ static jmethodID mID(nullptr);
+ if(nBytesToSkip <= 0)
+ return;
+
+ if(m_buf)
+ {
+ m_buf.reset();
+ --nBytesToSkip;
+ }
+
+ static_assert(sizeof(jchar) == 2, "I thought Java characters were UTF16 code units?");
+ sal_Int32 nCharsToSkip = nBytesToSkip / sizeof(jchar);
+ callIntMethodWithIntArg_ThrowRuntime("skip",mID,nCharsToSkip);
+ if(nBytesToSkip % sizeof(jchar) != 0)
+ {
+ assert(nBytesToSkip % sizeof(jchar) == 1);
+ Sequence< sal_Int8 > aData(1);
+ assert(m_buf);
+ readBytes(aData, 1);
+ }
+}
+
+sal_Int32 SAL_CALL java_io_Reader::available( )
+{
+ if(m_buf)
+ return 1;
+ bool out;
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+
+ {
+ static const char * const cSignature = "()Z";
+ static const char * const cMethodName = "ready";
+ // Java-Call
+ static jmethodID mID(nullptr);
+ obtainMethodId_throwRuntime(t.pEnv, cMethodName,cSignature, mID);
+ out = t.pEnv->CallBooleanMethod( object, mID);
+ ThrowRuntimeException(t.pEnv,*this);
+ } //t.pEnv
+ return (m_buf ? 1 : 0) + (out ? 1 : 0); // no way to tell *how much* is ready
+}
+
+void SAL_CALL java_io_Reader::closeInput( )
+{
+ static jmethodID mID(nullptr);
+ callVoidMethod_ThrowRuntime("close", mID);
+}
+
+sal_Int32 SAL_CALL java_io_Reader::readBytes( css::uno::Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead )
+{
+ OSL_ENSURE(aData.getLength() >= nBytesToRead," Sequence is smaller than BytesToRead");
+
+ if(nBytesToRead == 0)
+ return 0;
+
+ sal_Int8 *dst(aData.getArray());
+ sal_Int32 nBytesWritten(0);
+
+ if (m_buf)
+ {
+ if(!aData.hasElements())
+ {
+ aData.realloc(1);
+ dst = aData.getArray();
+ }
+ *dst = *m_buf;
+ m_buf.reset();
+ ++nBytesWritten;
+ ++dst;
+ --nBytesToRead;
+ }
+
+ if(nBytesToRead == 0)
+ return nBytesWritten;
+
+ sal_Int32 nCharsToRead = (nBytesToRead + 1)/2;
+
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+
+ {
+ jcharArray pCharArray = t.pEnv->NewCharArray(nCharsToRead);
+ static const char * const cSignature = "([CII)I";
+ static const char * const cMethodName = "read";
+ // Java-Call
+ static jmethodID mID(nullptr);
+ obtainMethodId_throwRuntime(t.pEnv, cMethodName,cSignature, mID);
+ jint outChars = t.pEnv->CallIntMethod( object, mID, pCharArray, 0, nCharsToRead );
+ if ( !outChars )
+ {
+ if(nBytesWritten==0)
+ ThrowRuntimeException(t.pEnv,*this);
+ else
+ return 1;
+ }
+ if(outChars > 0)
+ {
+ static_assert(sizeof(jchar) == 2, "I thought Java characters were UTF16 code units?");
+ const sal_Int32 jcs = sizeof(jchar);
+ const sal_Int32 outBytes = std::min(nBytesToRead, outChars*jcs);
+ assert(outBytes == outChars*jcs || outBytes == outChars*jcs - 1);
+
+ jboolean p = JNI_FALSE;
+ if(aData.getLength() < nBytesWritten + outBytes)
+ {
+ aData.realloc(nBytesWritten + outBytes);
+ dst = aData.getArray() + nBytesWritten;
+ }
+ jchar *outBuf(t.pEnv->GetCharArrayElements(pCharArray,&p));
+
+ memcpy(dst, outBuf, outBytes);
+ nBytesWritten += outBytes;
+ if(outBytes < outChars*jcs)
+ {
+ assert(outChars*jcs - outBytes == 1);
+ assert(!m_buf);
+ m_buf = reinterpret_cast<char*>(outBuf)[outBytes];
+ }
+ }
+ t.pEnv->DeleteLocalRef(pCharArray);
+ } //t.pEnv
+ return nBytesWritten;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/jdbc/Ref.cxx b/connectivity/source/drivers/jdbc/Ref.cxx
new file mode 100644
index 0000000000..12ce9fda8a
--- /dev/null
+++ b/connectivity/source/drivers/jdbc/Ref.cxx
@@ -0,0 +1,48 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <java/sql/Ref.hxx>
+
+using namespace connectivity;
+
+//************ Class: java.sql.Ref
+
+jclass java_sql_Ref::theClass = nullptr;
+java_sql_Ref::java_sql_Ref(JNIEnv* pEnv, jobject myObj)
+ : java_lang_Object(pEnv, myObj)
+{
+ SDBThreadAttach::addRef();
+}
+java_sql_Ref::~java_sql_Ref() { SDBThreadAttach::releaseRef(); }
+
+jclass java_sql_Ref::getMyClass() const
+{
+ // the class must be fetched only once, therefore static
+ if (!theClass)
+ theClass = findMyClass("java/sql/Ref");
+ return theClass;
+}
+
+OUString SAL_CALL java_sql_Ref::getBaseTypeName()
+{
+ static jmethodID mID(nullptr);
+ return callStringMethod("getBaseTypeName", mID);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/jdbc/ResultSet.cxx b/connectivity/source/drivers/jdbc/ResultSet.cxx
new file mode 100644
index 0000000000..c274c521c3
--- /dev/null
+++ b/connectivity/source/drivers/jdbc/ResultSet.cxx
@@ -0,0 +1,1013 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <java/lang/String.hxx>
+#include <java/lang/Boolean.hxx>
+#include <java/sql/ResultSet.hxx>
+#include <java/math/BigDecimal.hxx>
+#include <java/sql/JStatement.hxx>
+#include <java/sql/SQLWarning.hxx>
+#include <java/sql/Timestamp.hxx>
+#include <java/sql/Array.hxx>
+#include <java/sql/Ref.hxx>
+#include <java/sql/Clob.hxx>
+#include <java/sql/Blob.hxx>
+#include <java/sql/ResultSetMetaData.hxx>
+#include <java/io/InputStream.hxx>
+#include <java/io/Reader.hxx>
+#include <java/tools.hxx>
+#include <comphelper/property.hxx>
+#include <connectivity/CommonTools.hxx>
+#include <cppuhelper/typeprovider.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+#include <comphelper/sequence.hxx>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <TConnection.hxx>
+#include <comphelper/types.hxx>
+#include <connectivity/dbtools.hxx>
+#include <connectivity/dbexception.hxx>
+#include <strings.hrc>
+#include <resource/sharedresources.hxx>
+#include <java/LocalRef.hxx>
+
+#include <string.h>
+#include <memory>
+
+using namespace ::comphelper;
+
+using namespace connectivity;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+
+IMPLEMENT_SERVICE_INFO(java_sql_ResultSet,"com.sun.star.sdbcx.JResultSet","com.sun.star.sdbc.ResultSet");
+
+//************ Class: java.sql.ResultSet
+
+
+jclass java_sql_ResultSet::theClass = nullptr;
+java_sql_ResultSet::java_sql_ResultSet( JNIEnv * pEnv, jobject myObj, const java::sql::ConnectionLog& _rParentLogger,java_sql_Connection& _rConnection, java_sql_Statement_Base* pStmt)
+ :java_sql_ResultSet_BASE(m_aMutex)
+ ,java_lang_Object( pEnv, myObj )
+ ,OPropertySetHelper(java_sql_ResultSet_BASE::rBHelper)
+ ,m_aLogger( _rParentLogger, java::sql::ConnectionLog::RESULTSET )
+ ,m_pConnection(&_rConnection)
+{
+ SDBThreadAttach::addRef();
+ osl_atomic_increment(&m_refCount);
+ if ( pStmt )
+ m_xStatement = *pStmt;
+
+ osl_atomic_decrement(&m_refCount);
+}
+
+java_sql_ResultSet::~java_sql_ResultSet()
+{
+ if ( !java_sql_ResultSet_BASE::rBHelper.bDisposed && !java_sql_ResultSet_BASE::rBHelper.bInDispose )
+ {
+ // increment ref count to prevent double call of Dtor
+ osl_atomic_increment( &m_refCount );
+ dispose();
+ }
+}
+
+jclass java_sql_ResultSet::getMyClass() const
+{
+ // the class must be fetched only once, therefore static
+ if( !theClass )
+ theClass = findMyClass("java/sql/ResultSet");
+ return theClass;
+}
+
+void java_sql_ResultSet::disposing()
+{
+ OPropertySetHelper::disposing();
+
+ ::osl::MutexGuard aGuard(m_aMutex);
+ if( object )
+ {
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+ static jmethodID mID(nullptr);
+ callVoidMethod_ThrowSQL("close", mID);
+ clearObject(*t.pEnv);
+ }
+
+ SDBThreadAttach::releaseRef();
+}
+
+css::uno::Any SAL_CALL java_sql_ResultSet::queryInterface( const css::uno::Type & rType )
+{
+ css::uno::Any aRet = OPropertySetHelper::queryInterface(rType);
+ return aRet.hasValue() ? aRet : java_sql_ResultSet_BASE::queryInterface(rType);
+}
+
+css::uno::Sequence< css::uno::Type > SAL_CALL java_sql_ResultSet::getTypes( )
+{
+ ::cppu::OTypeCollection aTypes( cppu::UnoType<css::beans::XMultiPropertySet>::get(),
+ cppu::UnoType<css::beans::XFastPropertySet>::get(),
+ cppu::UnoType<css::beans::XPropertySet>::get());
+
+ return ::comphelper::concatSequences(aTypes.getTypes(),java_sql_ResultSet_BASE::getTypes());
+}
+
+
+sal_Int32 SAL_CALL java_sql_ResultSet::findColumn( const OUString& columnName )
+{
+ static jmethodID mID(nullptr);
+ return callIntMethodWithStringArg("findColumn",mID,columnName);
+}
+
+Reference< css::io::XInputStream > SAL_CALL java_sql_ResultSet::getBinaryStream( sal_Int32 columnIndex )
+{
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+ static jmethodID mID(nullptr);
+ jobject out = callObjectMethodWithIntArg(t.pEnv,"getBinaryStream","(I)Ljava/io/InputStream;", mID, columnIndex);
+
+ // WARNING: the caller becomes the owner of the returned pointer
+ return out==nullptr ? nullptr : new java_io_InputStream( t.pEnv, out );
+}
+
+Reference< css::io::XInputStream > SAL_CALL java_sql_ResultSet::getCharacterStream( sal_Int32 columnIndex )
+{
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+ static jmethodID mID(nullptr);
+ jobject out = callObjectMethodWithIntArg(t.pEnv,"getCharacterStream","(I)Ljava/io/Reader;", mID, columnIndex);
+
+ // WARNING: the caller becomes the owner of the returned pointer
+ return out==nullptr ? nullptr : new java_io_Reader( t.pEnv, out );
+}
+
+
+sal_Bool SAL_CALL java_sql_ResultSet::getBoolean( sal_Int32 columnIndex )
+{
+ static jmethodID mID(nullptr);
+ return callBooleanMethodWithIntArg( "getBoolean", mID,columnIndex );
+}
+
+
+sal_Int8 SAL_CALL java_sql_ResultSet::getByte( sal_Int32 columnIndex )
+{
+ static jmethodID mID(nullptr);
+ jbyte (JNIEnv::* const pCallMethod)( jobject obj, jmethodID methodID, ... ) = &JNIEnv::CallByteMethod;
+ return callMethodWithIntArg<jbyte>(pCallMethod,"getByte","(I)B",mID,columnIndex);
+}
+
+
+Sequence< sal_Int8 > SAL_CALL java_sql_ResultSet::getBytes( sal_Int32 columnIndex )
+{
+ Sequence< sal_Int8 > aSeq;
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+ static jmethodID mID(nullptr);
+ jbyteArray out = static_cast<jbyteArray>(callObjectMethodWithIntArg(t.pEnv,"getBytes","(I)[B", mID, columnIndex));
+ if (out)
+ {
+ jboolean p = false;
+ aSeq.realloc(t.pEnv->GetArrayLength(out));
+ memcpy(aSeq.getArray(),t.pEnv->GetByteArrayElements(out,&p),aSeq.getLength());
+ t.pEnv->DeleteLocalRef(out);
+ }
+ return aSeq;
+}
+
+
+css::util::Date SAL_CALL java_sql_ResultSet::getDate( sal_Int32 columnIndex )
+{
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+ static jmethodID mID(nullptr);
+ jobject out = callObjectMethodWithIntArg(t.pEnv,"getDate","(I)Ljava/sql/Date;", mID, columnIndex);
+ // WARNING: the caller becomes the owner of the returned pointer
+ return out ? static_cast <css::util::Date> (java_sql_Date( t.pEnv, out )) : css::util::Date();
+}
+
+
+double SAL_CALL java_sql_ResultSet::getDouble( sal_Int32 columnIndex )
+{
+ static jmethodID mID(nullptr);
+ jdouble (JNIEnv::* const pCallMethod)( jobject obj, jmethodID methodID, ... ) = &JNIEnv::CallDoubleMethod;
+ return callMethodWithIntArg<double>(pCallMethod,"getDouble","(I)D",mID,columnIndex);
+}
+
+
+float SAL_CALL java_sql_ResultSet::getFloat( sal_Int32 columnIndex )
+{
+ static jmethodID mID(nullptr);
+ jfloat (JNIEnv::* const pCallMethod)( jobject obj, jmethodID methodID, ... ) = &JNIEnv::CallFloatMethod;
+ return callMethodWithIntArg<jfloat>(pCallMethod,"getFloat","(I)F",mID,columnIndex);
+}
+
+
+sal_Int32 SAL_CALL java_sql_ResultSet::getInt( sal_Int32 columnIndex )
+{
+ static jmethodID mID(nullptr);
+ return callIntMethodWithIntArg_ThrowSQL("getInt",mID,columnIndex);
+}
+
+
+sal_Int32 SAL_CALL java_sql_ResultSet::getRow( )
+{
+ static jmethodID mID(nullptr);
+ return callIntMethod_ThrowSQL("getRow", mID);
+}
+
+
+sal_Int64 SAL_CALL java_sql_ResultSet::getLong( sal_Int32 columnIndex )
+{
+ static jmethodID mID(nullptr);
+ jlong (JNIEnv::* const pCallMethod)( jobject obj, jmethodID methodID, ... ) = &JNIEnv::CallLongMethod;
+ return callMethodWithIntArg<jlong>(pCallMethod,"getLong","(I)J",mID,columnIndex);
+}
+
+
+css::uno::Reference< css::sdbc::XResultSetMetaData > SAL_CALL java_sql_ResultSet::getMetaData( )
+{
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+ static jmethodID mID(nullptr);
+ jobject out = callObjectMethod(t.pEnv,"getMetaData","()Ljava/sql/ResultSetMetaData;", mID);
+
+ return out==nullptr ? nullptr : new java_sql_ResultSetMetaData( t.pEnv, out, *m_pConnection );
+}
+
+Reference< XArray > SAL_CALL java_sql_ResultSet::getArray( sal_Int32 columnIndex )
+{
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+ static jmethodID mID(nullptr);
+ jobject out = callObjectMethodWithIntArg(t.pEnv,"getArray","(I)Ljava/sql/Array;", mID, columnIndex);
+
+ // WARNING: the caller becomes the owner of the returned pointer
+ return out==nullptr ? nullptr : new java_sql_Array( t.pEnv, out );
+}
+
+
+Reference< XClob > SAL_CALL java_sql_ResultSet::getClob( sal_Int32 columnIndex )
+{
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+ static jmethodID mID(nullptr);
+ jobject out = callObjectMethodWithIntArg(t.pEnv,"getClob","(I)Ljava/sql/Clob;", mID, columnIndex);
+ // WARNING: the caller becomes the owner of the returned pointer
+ return out==nullptr ? nullptr : new java_sql_Clob( t.pEnv, out );
+}
+
+Reference< XBlob > SAL_CALL java_sql_ResultSet::getBlob( sal_Int32 columnIndex )
+{
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+ static jmethodID mID(nullptr);
+ jobject out = callObjectMethodWithIntArg(t.pEnv,"getBlob","(I)Ljava/sql/Blob;", mID, columnIndex);
+ // WARNING: the caller becomes the owner of the returned pointer
+ return out==nullptr ? nullptr : new java_sql_Blob( t.pEnv, out );
+}
+
+
+Reference< XRef > SAL_CALL java_sql_ResultSet::getRef( sal_Int32 columnIndex )
+{
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+ static jmethodID mID(nullptr);
+ jobject out = callObjectMethodWithIntArg(t.pEnv,"getRef","(I)Ljava/sql/Ref;", mID, columnIndex);
+
+ // WARNING: the caller becomes the owner of the returned pointer
+ return out==nullptr ? nullptr : new java_sql_Ref( t.pEnv, out );
+}
+
+
+Any SAL_CALL java_sql_ResultSet::getObject( sal_Int32 columnIndex, const Reference< css::container::XNameAccess >& typeMap )
+{
+ Any aRet;
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+ {
+ jvalue args[2];
+ // convert parameter
+ args[0].i = columnIndex;
+ args[1].l = convertTypeMapToJavaMap(typeMap);
+ // initialize temporary Variable
+ // Java-Call
+ static jmethodID mID(nullptr);
+ if ( !mID )
+ {
+ static const char * const cSignature = "(I)Ljava/lang/Object;";
+ static const char * const cMethodName = "getObject";
+
+ obtainMethodId_throwSQL(t.pEnv, cMethodName,cSignature, mID);
+ }
+
+ jobject out = t.pEnv->CallObjectMethodA( object, mID, args);
+ t.pEnv->DeleteLocalRef(static_cast<jstring>(args[1].l));
+ ThrowLoggedSQLException( m_aLogger, t.pEnv, *this );
+ // and clean up
+ if ( out )
+ {
+ if ( t.pEnv->IsInstanceOf(out,java_lang_String::st_getMyClass()) )
+ {
+ java_lang_String aVal(t.pEnv,out);
+ aRet <<= OUString(aVal);
+ }
+ else if ( t.pEnv->IsInstanceOf(out,java_lang_Boolean::st_getMyClass()) )
+ {
+ java_lang_Boolean aVal(t.pEnv,out);
+ static jmethodID methodID = nullptr;
+ aRet <<= aVal.callBooleanMethod("booleanValue",methodID);
+ }
+ else if ( t.pEnv->IsInstanceOf(out,java_sql_Date::st_getMyClass()) )
+ {
+ java_sql_Date aVal(t.pEnv,out);
+ aRet <<= css::util::Date(aVal);
+ }
+ else if ( t.pEnv->IsInstanceOf(out,java_sql_Time::st_getMyClass()) )
+ {
+ java_sql_Time aVal(t.pEnv,out);
+ aRet <<= css::util::Time(aVal);
+ }
+ else if ( t.pEnv->IsInstanceOf(out,java_sql_Timestamp::st_getMyClass()) )
+ {
+ java_sql_Timestamp aVal(t.pEnv,out);
+ aRet <<= css::util::DateTime(aVal);
+ }
+ else
+ t.pEnv->DeleteLocalRef(out);
+ }
+ } //t.pEnv
+ return aRet;
+}
+
+
+sal_Int16 SAL_CALL java_sql_ResultSet::getShort( sal_Int32 columnIndex )
+{
+ static jmethodID mID(nullptr);
+ jshort (JNIEnv::* const pCallMethod)( jobject obj, jmethodID methodID, ... ) = &JNIEnv::CallShortMethod;
+ return callMethodWithIntArg<jshort>(pCallMethod,"getShort","(I)S",mID,columnIndex);
+}
+
+
+OUString SAL_CALL java_sql_ResultSet::getString( sal_Int32 columnIndex )
+{
+ static jmethodID mID(nullptr);
+ return callStringMethodWithIntArg("getString",mID,columnIndex);
+}
+
+
+css::util::Time SAL_CALL java_sql_ResultSet::getTime( sal_Int32 columnIndex )
+{
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+ static jmethodID mID(nullptr);
+ jobject out = callObjectMethodWithIntArg(t.pEnv,"getTime","(I)Ljava/sql/Time;", mID, columnIndex);
+ // WARNING: the caller becomes the owner of the returned pointer
+ return out ? static_cast <css::util::Time> (java_sql_Time( t.pEnv, out )) : css::util::Time();
+}
+
+
+css::util::DateTime SAL_CALL java_sql_ResultSet::getTimestamp( sal_Int32 columnIndex )
+{
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+ static jmethodID mID(nullptr);
+ jobject out = callObjectMethodWithIntArg(t.pEnv,"getTimestamp","(I)Ljava/sql/Timestamp;", mID, columnIndex);
+ // WARNING: the caller becomes the owner of the returned pointer
+ return out ? static_cast <css::util::DateTime> (java_sql_Timestamp( t.pEnv, out )) : css::util::DateTime();
+}
+
+
+sal_Bool SAL_CALL java_sql_ResultSet::isAfterLast( )
+{
+ static jmethodID mID(nullptr);
+ return callBooleanMethod( "isAfterLast", mID );
+}
+
+sal_Bool SAL_CALL java_sql_ResultSet::isFirst( )
+{
+ static jmethodID mID(nullptr);
+ return callBooleanMethod( "isFirst", mID );
+}
+
+sal_Bool SAL_CALL java_sql_ResultSet::isLast( )
+{
+ static jmethodID mID(nullptr);
+ return callBooleanMethod( "isLast", mID );
+}
+
+void SAL_CALL java_sql_ResultSet::beforeFirst( )
+{
+ static jmethodID mID(nullptr);
+ callVoidMethod_ThrowSQL("beforeFirst", mID);
+}
+
+void SAL_CALL java_sql_ResultSet::afterLast( )
+{
+ static jmethodID mID(nullptr);
+ callVoidMethod_ThrowSQL("afterLast", mID);
+}
+
+
+void SAL_CALL java_sql_ResultSet::close( )
+{
+ dispose();
+}
+
+
+sal_Bool SAL_CALL java_sql_ResultSet::first( )
+{
+ static jmethodID mID(nullptr);
+ return callBooleanMethod( "first", mID );
+}
+
+
+sal_Bool SAL_CALL java_sql_ResultSet::last( )
+{
+ static jmethodID mID(nullptr);
+ return callBooleanMethod( "last", mID );
+}
+
+sal_Bool SAL_CALL java_sql_ResultSet::absolute( sal_Int32 row )
+{
+ static jmethodID mID(nullptr);
+ return callBooleanMethodWithIntArg( "absolute", mID,row );
+}
+
+sal_Bool SAL_CALL java_sql_ResultSet::relative( sal_Int32 row )
+{
+ static jmethodID mID(nullptr);
+ return callBooleanMethodWithIntArg( "relative", mID,row );
+}
+
+sal_Bool SAL_CALL java_sql_ResultSet::previous( )
+{
+ static jmethodID mID(nullptr);
+ return callBooleanMethod( "previous", mID );
+}
+
+Reference< XInterface > SAL_CALL java_sql_ResultSet::getStatement( )
+{
+ return m_xStatement;
+}
+
+
+sal_Bool SAL_CALL java_sql_ResultSet::rowDeleted( )
+{
+ static jmethodID mID(nullptr);
+ return callBooleanMethod( "rowDeleted", mID );
+}
+
+sal_Bool SAL_CALL java_sql_ResultSet::rowInserted( )
+{
+ static jmethodID mID(nullptr);
+ return callBooleanMethod( "rowInserted", mID );
+}
+
+sal_Bool SAL_CALL java_sql_ResultSet::rowUpdated( )
+{
+ static jmethodID mID(nullptr);
+ return callBooleanMethod( "rowUpdated", mID );
+}
+
+
+sal_Bool SAL_CALL java_sql_ResultSet::isBeforeFirst( )
+{
+ static jmethodID mID(nullptr);
+ return callBooleanMethod( "isBeforeFirst", mID );
+}
+
+
+sal_Bool SAL_CALL java_sql_ResultSet::next( )
+{
+ static jmethodID mID(nullptr);
+ return callBooleanMethod( "next", mID );
+}
+
+sal_Bool SAL_CALL java_sql_ResultSet::wasNull( )
+{
+ static jmethodID mID(nullptr);
+ return callBooleanMethod( "wasNull", mID );
+}
+
+void SAL_CALL java_sql_ResultSet::cancel( )
+{
+ static jmethodID mID(nullptr);
+ callVoidMethod_ThrowRuntime("cancel", mID);
+}
+
+void SAL_CALL java_sql_ResultSet::clearWarnings( )
+{
+ static jmethodID mID(nullptr);
+ callVoidMethod_ThrowSQL("clearWarnings", mID);
+}
+
+css::uno::Any SAL_CALL java_sql_ResultSet::getWarnings( )
+{
+ SDBThreadAttach t;
+ static jmethodID mID(nullptr);
+ jobject out = callObjectMethod(t.pEnv,"getWarnings","()Ljava/sql/SQLWarning;", mID);
+ // WARNING: the caller becomes the owner of the returned pointer
+ if( out )
+ {
+ java_sql_SQLWarning_BASE warn_base( t.pEnv, out );
+ return Any(
+ static_cast< css::sdbc::SQLException >(
+ java_sql_SQLWarning(warn_base,*this)));
+ }
+
+ return css::uno::Any();
+}
+
+
+void SAL_CALL java_sql_ResultSet::insertRow( )
+{
+ static jmethodID mID(nullptr);
+ callVoidMethod_ThrowSQL("insertRow", mID);
+}
+
+void SAL_CALL java_sql_ResultSet::updateRow( )
+{
+ static jmethodID mID(nullptr);
+ callVoidMethod_ThrowSQL("updateRow", mID);
+}
+
+void SAL_CALL java_sql_ResultSet::deleteRow( )
+{
+ static jmethodID mID(nullptr);
+ callVoidMethod_ThrowSQL("deleteRow", mID);
+}
+
+
+void SAL_CALL java_sql_ResultSet::cancelRowUpdates( )
+{
+ static jmethodID mID(nullptr);
+ callVoidMethod_ThrowSQL("cancelRowUpdates", mID);
+}
+
+
+void SAL_CALL java_sql_ResultSet::moveToInsertRow( )
+{
+ static jmethodID mID(nullptr);
+ callVoidMethod_ThrowSQL("moveToInsertRow", mID);
+}
+
+
+void SAL_CALL java_sql_ResultSet::moveToCurrentRow( )
+{
+ static jmethodID mID(nullptr);
+ callVoidMethod_ThrowSQL("moveToCurrentRow", mID);
+}
+
+
+void SAL_CALL java_sql_ResultSet::updateNull( sal_Int32 columnIndex )
+{
+ static jmethodID mID(nullptr);
+ callVoidMethodWithIntArg_ThrowSQL("updateNull", mID, columnIndex);
+}
+
+
+void SAL_CALL java_sql_ResultSet::updateBoolean( sal_Int32 columnIndex, sal_Bool x )
+{
+ static jmethodID mID(nullptr);
+ callVoidMethod_ThrowSQL("updateBoolean", "(IZ)V", mID, columnIndex, x);
+}
+
+void SAL_CALL java_sql_ResultSet::updateByte( sal_Int32 columnIndex, sal_Int8 x )
+{
+ static jmethodID mID(nullptr);
+ callVoidMethod_ThrowSQL("updateByte", "(IB)V", mID, columnIndex, x);
+}
+
+
+void SAL_CALL java_sql_ResultSet::updateShort( sal_Int32 columnIndex, sal_Int16 x )
+{
+ static jmethodID mID(nullptr);
+ callVoidMethod_ThrowSQL("updateShort", "(IS)V", mID, columnIndex, x);
+}
+
+void SAL_CALL java_sql_ResultSet::updateInt( sal_Int32 columnIndex, sal_Int32 x )
+{
+ static jmethodID mID(nullptr);
+ callVoidMethod_ThrowSQL("updateInt", "(II)V", mID, columnIndex, x);
+}
+
+void SAL_CALL java_sql_ResultSet::updateLong( sal_Int32 columnIndex, sal_Int64 x )
+{
+ static jmethodID mID(nullptr);
+ callVoidMethod_ThrowSQL("updateLong", "(IJ)V", mID, columnIndex, x);
+}
+
+
+void SAL_CALL java_sql_ResultSet::updateFloat( sal_Int32 columnIndex, float x )
+{
+ static jmethodID mID(nullptr);
+ callVoidMethod_ThrowSQL("updateFloat", "(IF)V", mID, columnIndex, x);
+}
+
+
+void SAL_CALL java_sql_ResultSet::updateDouble( sal_Int32 columnIndex, double x )
+{
+ static jmethodID mID(nullptr);
+ callVoidMethod_ThrowSQL("updateDouble", "(ID)V", mID, columnIndex, x);
+}
+
+
+void SAL_CALL java_sql_ResultSet::updateString( sal_Int32 columnIndex, const OUString& x )
+{
+ SDBThreadAttach t;
+
+ {
+ // initialize temporary variable
+ // Java-Call
+ static jmethodID mID(nullptr);
+ if ( !mID )
+ {
+ static const char * const cSignature = "(ILjava/lang/String;)V";
+ static const char * const cMethodName = "updateString";
+
+ obtainMethodId_throwSQL(t.pEnv, cMethodName,cSignature, mID);
+ }
+
+ {
+ // convert parameter
+ jdbc::LocalRef< jstring > str( t.env(),convertwchar_tToJavaString(t.pEnv,x));
+ t.pEnv->CallVoidMethod( object, mID,columnIndex,str.get());
+ ThrowLoggedSQLException( m_aLogger, t.pEnv, *this );
+ }
+ }
+}
+
+
+void SAL_CALL java_sql_ResultSet::updateBytes( sal_Int32 columnIndex, const css::uno::Sequence< sal_Int8 >& x )
+{
+ SDBThreadAttach t;
+
+ {
+ // initialize temporary variable
+ // Java-Call
+ static jmethodID mID(nullptr);
+ if ( !mID )
+ {
+ static const char * const cSignature = "(I[B)V";
+ static const char * const cMethodName = "updateBytes";
+
+ obtainMethodId_throwSQL(t.pEnv, cMethodName,cSignature, mID);
+ }
+
+ {
+ jbyteArray aArray = t.pEnv->NewByteArray(x.getLength());
+ jbyte * pData = reinterpret_cast<jbyte *>(
+ const_cast<sal_Int8 *>(x.getConstArray()));
+ // 4th param of Set*ArrayRegion changed from pointer to non-const to
+ // pointer to const between <http://docs.oracle.com/javase/6/docs/
+ // technotes/guides/jni/spec/functions.html#wp22933> and
+ // <http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/
+ // functions.html#wp22933>; work around that difference in a way
+ // that doesn't trigger loplugin:redundantcast
+ t.pEnv->SetByteArrayRegion(aArray,0,x.getLength(),pData);
+ // convert parameter
+ t.pEnv->CallVoidMethod( object, mID,columnIndex,aArray);
+ t.pEnv->DeleteLocalRef(aArray);
+ ThrowLoggedSQLException( m_aLogger, t.pEnv, *this );
+ }
+ }
+}
+
+
+void SAL_CALL java_sql_ResultSet::updateDate( sal_Int32 columnIndex, const css::util::Date& x )
+{
+ java_sql_Date aD(x);
+ static jmethodID mID(nullptr);
+ callVoidMethod_ThrowSQL("updateDate", "(ILjava/sql/Date;)V", mID, columnIndex, aD.getJavaObject());
+}
+
+
+void SAL_CALL java_sql_ResultSet::updateTime( sal_Int32 columnIndex, const css::util::Time& x )
+{
+ java_sql_Time aD(x);
+ static jmethodID mID(nullptr);
+ callVoidMethod_ThrowSQL("updateTime", "(ILjava/sql/Time;)V", mID, columnIndex, aD.getJavaObject());
+}
+
+
+void SAL_CALL java_sql_ResultSet::updateTimestamp( sal_Int32 columnIndex, const css::util::DateTime& x )
+{
+ java_sql_Timestamp aD(x);
+ static jmethodID mID(nullptr);
+ callVoidMethod_ThrowSQL("updateTimestamp", "(ILjava/sql/Timestamp;)V", mID, columnIndex, aD.getJavaObject());
+}
+
+
+void SAL_CALL java_sql_ResultSet::updateBinaryStream( sal_Int32 columnIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length )
+{
+ try
+ {
+ SDBThreadAttach t;
+ {
+
+ // initialize temporary variable
+ // Java-Call
+ static jmethodID mID(nullptr);
+ if ( !mID )
+ {
+ static const char * const cSignature = "(ILjava/io/InputStream;I)V";
+ static const char * const cMethodName = "updateBinaryStream";
+ obtainMethodId_throwSQL(t.pEnv, cMethodName,cSignature, mID);
+ }
+
+ {
+ // convert Parameter
+ jobject obj = createByteInputStream(x,length);
+ t.pEnv->CallVoidMethod( object, mID, columnIndex,obj,length);
+ ThrowLoggedSQLException( m_aLogger, t.pEnv, *this );
+ }
+ }
+ }
+ catch(const Exception&)
+ {
+ Any anyEx = ::cppu::getCaughtException();
+ ::dbtools::throwFeatureNotImplementedSQLException( "XRowUpdate::updateBinaryStream", *this, anyEx );
+ }
+}
+
+void SAL_CALL java_sql_ResultSet::updateCharacterStream( sal_Int32 columnIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length )
+{
+ try
+ {
+ SDBThreadAttach t;
+ {
+
+ // initialize temporary variable
+ // Java-Call
+ static jmethodID mID(nullptr);
+ if ( !mID )
+ {
+ static const char * const cSignature = "(ILjava/io/Reader;I)V";
+ static const char * const cMethodName = "updateCharacterStream";
+ obtainMethodId_throwSQL(t.pEnv, cMethodName,cSignature, mID);
+ }
+
+ {
+ // convert Parameter
+ jobject obj = createCharArrayReader(x,length);
+ t.pEnv->CallVoidMethod( object, mID, columnIndex,obj,length);
+ ThrowLoggedSQLException( m_aLogger, t.pEnv, *this );
+ }
+ }
+ }
+ catch(const Exception&)
+ {
+ Any anyEx = ::cppu::getCaughtException();
+ ::dbtools::throwFeatureNotImplementedSQLException( "XRowUpdate::updateCharacterStream", *this, anyEx );
+ }
+}
+
+void SAL_CALL java_sql_ResultSet::updateObject( sal_Int32 columnIndex, const css::uno::Any& x )
+{
+ if(!::dbtools::implUpdateObject(this,columnIndex,x))
+ {
+ ::connectivity::SharedResources aResources;
+ const OUString sError( aResources.getResourceStringWithSubstitution(
+ STR_UNKNOWN_COLUMN_TYPE,
+ "$position$", OUString::number(columnIndex)
+ ) );
+ ::dbtools::throwGenericSQLException(sError,*this);
+ }
+}
+
+
+void SAL_CALL java_sql_ResultSet::updateNumericObject( sal_Int32 columnIndex, const css::uno::Any& x, sal_Int32 scale )
+{
+ // OSL_FAIL("java_sql_ResultSet::updateNumericObject: NYI");
+ try
+ {
+ SDBThreadAttach t;
+
+ {
+
+ // initialize temporary variable
+ // Java-Call
+ static jmethodID mID(nullptr);
+ if ( !mID )
+ {
+ static const char * const cSignature = "(ILjava/lang/Object;I)V";
+ static const char * const cMethodName = "updateObject";
+
+ obtainMethodId_throwSQL(t.pEnv, cMethodName,cSignature, mID);
+ }
+
+ {
+ // convert parameter
+ double nTemp = 0.0;
+ std::unique_ptr<java_math_BigDecimal> pBigDecimal;
+ if ( x >>= nTemp)
+ {
+ pBigDecimal.reset(new java_math_BigDecimal(nTemp));
+ }
+ else
+ pBigDecimal.reset(new java_math_BigDecimal(::comphelper::getString(x)));
+
+ t.pEnv->CallVoidMethod( object, mID, columnIndex,pBigDecimal->getJavaObject(),scale);
+ ThrowLoggedSQLException( m_aLogger, t.pEnv, *this );
+ }
+ }
+ }
+ catch(const Exception&)
+ {
+ updateObject( columnIndex,x);
+ }
+}
+
+sal_Int32 java_sql_ResultSet::getResultSetConcurrency() const
+{
+ static jmethodID mID(nullptr);
+ return callIntMethod_ThrowRuntime("getConcurrency", mID);
+}
+
+sal_Int32 java_sql_ResultSet::getResultSetType() const
+{
+ static jmethodID mID(nullptr);
+ return callIntMethod_ThrowRuntime("getType",mID);
+}
+
+sal_Int32 java_sql_ResultSet::getFetchDirection() const
+{
+ static jmethodID mID(nullptr);
+ return callIntMethod_ThrowRuntime("getFetchDirection", mID);
+}
+
+sal_Int32 java_sql_ResultSet::getFetchSize() const
+{
+ static jmethodID mID(nullptr);
+ return callIntMethod_ThrowRuntime("getFetchSize", mID);
+}
+
+OUString java_sql_ResultSet::getCursorName() const
+{
+ static jmethodID mID(nullptr);
+ return callStringMethod("getCursorName",mID);
+}
+
+
+void java_sql_ResultSet::setFetchDirection(sal_Int32 _par0)
+{
+ static jmethodID mID(nullptr);
+ callVoidMethodWithIntArg_ThrowRuntime("setFetchDirection", mID, _par0);
+}
+
+void SAL_CALL java_sql_ResultSet::refreshRow( )
+{
+ static jmethodID mID(nullptr);
+ callVoidMethod_ThrowSQL("refreshRow",mID);
+}
+
+void java_sql_ResultSet::setFetchSize(sal_Int32 _par0)
+{
+ static jmethodID mID(nullptr);
+ callVoidMethodWithIntArg_ThrowRuntime("setFetchSize", mID, _par0);
+}
+
+::cppu::IPropertyArrayHelper* java_sql_ResultSet::createArrayHelper( ) const
+{
+ return new ::cppu::OPropertyArrayHelper
+ {
+ {
+ {
+ ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_CURSORNAME),
+ PROPERTY_ID_CURSORNAME,
+ cppu::UnoType<OUString>::get(),
+ PropertyAttribute::READONLY
+ },
+ {
+ ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHDIRECTION),
+ PROPERTY_ID_FETCHDIRECTION,
+ cppu::UnoType<sal_Int32>::get(),
+ 0
+ },
+ {
+ ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHSIZE),
+ PROPERTY_ID_FETCHSIZE,
+ cppu::UnoType<sal_Int32>::get(),
+ 0
+ },
+ {
+ ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETCONCURRENCY),
+ PROPERTY_ID_RESULTSETCONCURRENCY,
+ cppu::UnoType<sal_Int32>::get(),
+ PropertyAttribute::READONLY
+ },
+ {
+ ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETTYPE),
+ PROPERTY_ID_RESULTSETTYPE,
+ cppu::UnoType<sal_Int32>::get(),
+ PropertyAttribute::READONLY
+ }
+ }
+ };
+}
+
+::cppu::IPropertyArrayHelper & java_sql_ResultSet::getInfoHelper()
+{
+ return *getArrayHelper();
+}
+
+sal_Bool java_sql_ResultSet::convertFastPropertyValue(
+ css::uno::Any & rConvertedValue,
+ css::uno::Any & rOldValue,
+ sal_Int32 nHandle,
+ const css::uno::Any& rValue )
+{
+ bool bRet = false;
+ switch(nHandle)
+ {
+ case PROPERTY_ID_CURSORNAME:
+ case PROPERTY_ID_RESULTSETCONCURRENCY:
+ case PROPERTY_ID_RESULTSETTYPE:
+ throw css::lang::IllegalArgumentException();
+ case PROPERTY_ID_FETCHDIRECTION:
+ bRet = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, getFetchDirection());
+ break;
+ case PROPERTY_ID_FETCHSIZE:
+ bRet = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, getFetchSize());
+ break;
+ default:
+ break;
+ }
+ return bRet;
+}
+
+
+void java_sql_ResultSet::setFastPropertyValue_NoBroadcast(
+ sal_Int32 nHandle,
+ const css::uno::Any& rValue
+ )
+{
+ switch(nHandle)
+ {
+ case PROPERTY_ID_CURSORNAME:
+ case PROPERTY_ID_RESULTSETCONCURRENCY:
+ case PROPERTY_ID_RESULTSETTYPE:
+ throw css::uno::Exception("cannot set prop " + OUString::number(nHandle), nullptr);
+ case PROPERTY_ID_FETCHDIRECTION:
+ setFetchDirection(comphelper::getINT32(rValue));
+ break;
+ case PROPERTY_ID_FETCHSIZE:
+ setFetchSize(comphelper::getINT32(rValue));
+ break;
+ default:
+ ;
+ }
+}
+
+void java_sql_ResultSet::getFastPropertyValue(
+ css::uno::Any& rValue,
+ sal_Int32 nHandle
+ ) const
+{
+ try
+ {
+ switch(nHandle)
+ {
+ case PROPERTY_ID_CURSORNAME:
+ rValue <<= getCursorName();
+ break;
+ case PROPERTY_ID_RESULTSETCONCURRENCY:
+ rValue <<= getResultSetConcurrency();
+ break;
+ case PROPERTY_ID_RESULTSETTYPE:
+ rValue <<= getResultSetType();
+ break;
+ case PROPERTY_ID_FETCHDIRECTION:
+ rValue <<= getFetchDirection();
+ break;
+ case PROPERTY_ID_FETCHSIZE:
+ rValue <<= getFetchSize();
+ break;
+ }
+ }
+ catch(const Exception&)
+ {
+ }
+}
+
+void SAL_CALL java_sql_ResultSet::acquire() noexcept
+{
+ java_sql_ResultSet_BASE::acquire();
+}
+
+void SAL_CALL java_sql_ResultSet::release() noexcept
+{
+ java_sql_ResultSet_BASE::release();
+}
+
+css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL java_sql_ResultSet::getPropertySetInfo( )
+{
+ return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper());
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/jdbc/ResultSetMetaData.cxx b/connectivity/source/drivers/jdbc/ResultSetMetaData.cxx
new file mode 100644
index 0000000000..fdf5bfe69c
--- /dev/null
+++ b/connectivity/source/drivers/jdbc/ResultSetMetaData.cxx
@@ -0,0 +1,200 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <java/sql/ResultSetMetaData.hxx>
+#include <java/sql/Connection.hxx>
+
+using namespace connectivity;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+
+
+//************ Class: java.sql.ResultSetMetaData
+
+
+jclass java_sql_ResultSetMetaData::theClass = nullptr;
+java_sql_ResultSetMetaData::java_sql_ResultSetMetaData( JNIEnv * pEnv, jobject myObj, java_sql_Connection& _rCon )
+ :java_lang_Object( pEnv, myObj )
+ ,m_pConnection( &_rCon )
+ ,m_nColumnCount(-1)
+{
+ SDBThreadAttach::addRef();
+}
+java_sql_ResultSetMetaData::~java_sql_ResultSetMetaData()
+{
+ SDBThreadAttach::releaseRef();
+}
+
+jclass java_sql_ResultSetMetaData::getMyClass() const
+{
+ // The class needs to be fetched just once, that is why it is static
+ if( !theClass )
+ theClass = findMyClass("java/sql/ResultSetMetaData");
+ return theClass;
+}
+
+
+sal_Int32 SAL_CALL java_sql_ResultSetMetaData::getColumnDisplaySize( sal_Int32 column )
+{
+ static jmethodID mID(nullptr);
+ return callIntMethodWithIntArg_ThrowSQL("getColumnDisplaySize",mID,column);
+}
+
+
+sal_Int32 SAL_CALL java_sql_ResultSetMetaData::getColumnType( sal_Int32 column )
+{
+ static jmethodID mID(nullptr);
+ return callIntMethodWithIntArg_ThrowSQL("getColumnType",mID,column);
+}
+
+
+sal_Int32 SAL_CALL java_sql_ResultSetMetaData::getColumnCount( )
+{
+ if ( m_nColumnCount == -1 )
+ {
+ static jmethodID mID(nullptr);
+ m_nColumnCount = callIntMethod_ThrowSQL("getColumnCount", mID);
+ } // if ( m_nColumnCount == -1 )
+ return m_nColumnCount;
+
+}
+
+
+sal_Bool SAL_CALL java_sql_ResultSetMetaData::isCaseSensitive( sal_Int32 column )
+{
+ static jmethodID mID(nullptr);
+ return callBooleanMethodWithIntArg( "isCaseSensitive", mID,column );
+}
+
+OUString SAL_CALL java_sql_ResultSetMetaData::getSchemaName( sal_Int32 column )
+{
+ static jmethodID mID(nullptr);
+ return callStringMethodWithIntArg("getSchemaName",mID,column);
+}
+
+
+OUString SAL_CALL java_sql_ResultSetMetaData::getColumnName( sal_Int32 column )
+{
+ static jmethodID mID(nullptr);
+ return callStringMethodWithIntArg("getColumnName",mID,column);
+}
+
+OUString SAL_CALL java_sql_ResultSetMetaData::getTableName( sal_Int32 column )
+{
+ static jmethodID mID(nullptr);
+ return callStringMethodWithIntArg("getTableName",mID,column);
+}
+
+OUString SAL_CALL java_sql_ResultSetMetaData::getCatalogName( sal_Int32 column )
+{
+ static jmethodID mID(nullptr);
+ return callStringMethodWithIntArg("getCatalogName",mID,column);
+}
+
+OUString SAL_CALL java_sql_ResultSetMetaData::getColumnTypeName( sal_Int32 column )
+{
+ static jmethodID mID(nullptr);
+ return callStringMethodWithIntArg("getColumnTypeName",mID,column);
+}
+
+OUString SAL_CALL java_sql_ResultSetMetaData::getColumnLabel( sal_Int32 column )
+{
+ static jmethodID mID(nullptr);
+ return callStringMethodWithIntArg("getColumnLabel",mID,column);
+}
+
+OUString SAL_CALL java_sql_ResultSetMetaData::getColumnServiceName( sal_Int32 column )
+{
+ static jmethodID mID(nullptr);
+ return callStringMethodWithIntArg("getColumnClassName",mID,column);
+}
+
+
+sal_Bool SAL_CALL java_sql_ResultSetMetaData::isCurrency( sal_Int32 column )
+{
+ if ( m_pConnection->isIgnoreCurrencyEnabled() )
+ return false;
+ static jmethodID mID(nullptr);
+ return callBooleanMethodWithIntArg( "isCurrency", mID,column );
+}
+
+
+sal_Bool SAL_CALL java_sql_ResultSetMetaData::isAutoIncrement( sal_Int32 column )
+{
+ static jmethodID mID(nullptr);
+ return callBooleanMethodWithIntArg( "isAutoIncrement", mID,column );
+}
+
+
+sal_Bool SAL_CALL java_sql_ResultSetMetaData::isSigned( sal_Int32 column )
+{
+ static jmethodID mID(nullptr);
+ return callBooleanMethodWithIntArg( "isSigned", mID,column );
+}
+
+sal_Int32 SAL_CALL java_sql_ResultSetMetaData::getPrecision( sal_Int32 column )
+{
+ static jmethodID mID(nullptr);
+ return callIntMethodWithIntArg_ThrowSQL("getPrecision",mID,column);
+}
+
+sal_Int32 SAL_CALL java_sql_ResultSetMetaData::getScale( sal_Int32 column )
+{
+ static jmethodID mID(nullptr);
+ return callIntMethodWithIntArg_ThrowSQL("getScale",mID,column);
+}
+
+sal_Int32 SAL_CALL java_sql_ResultSetMetaData::isNullable( sal_Int32 column )
+{
+ static jmethodID mID(nullptr);
+ return callIntMethodWithIntArg_ThrowSQL("isNullable",mID,column);
+}
+
+
+sal_Bool SAL_CALL java_sql_ResultSetMetaData::isSearchable( sal_Int32 column )
+{
+ static jmethodID mID(nullptr);
+ return callBooleanMethodWithIntArg( "isSearchable", mID,column );
+}
+
+
+sal_Bool SAL_CALL java_sql_ResultSetMetaData::isReadOnly( sal_Int32 column )
+{
+ static jmethodID mID(nullptr);
+ return callBooleanMethodWithIntArg( "isReadOnly", mID,column );
+}
+
+
+sal_Bool SAL_CALL java_sql_ResultSetMetaData::isDefinitelyWritable( sal_Int32 column )
+{
+ static jmethodID mID(nullptr);
+ return callBooleanMethodWithIntArg( "isDefinitelyWritable", mID,column );
+}
+
+sal_Bool SAL_CALL java_sql_ResultSetMetaData::isWritable( sal_Int32 column )
+{
+ static jmethodID mID(nullptr);
+ return callBooleanMethodWithIntArg( "isWritable", mID,column );
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/jdbc/SQLException.cxx b/connectivity/source/drivers/jdbc/SQLException.cxx
new file mode 100644
index 0000000000..9374407d1b
--- /dev/null
+++ b/connectivity/source/drivers/jdbc/SQLException.cxx
@@ -0,0 +1,87 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <java/sql/SQLException.hxx>
+
+using namespace connectivity;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::lang;
+
+//************ Class: java.sql.SQLException
+
+java_sql_SQLException::java_sql_SQLException( const java_sql_SQLException_BASE& _rException,const Reference< XInterface> & _rContext)
+ : css::sdbc::SQLException( _rException.getMessage(),
+ _rContext,
+ _rException.getSQLState(),
+ _rException.getErrorCode(),
+ Any(_rException.getNextException())
+ )
+{
+}
+
+java_sql_SQLException_BASE::java_sql_SQLException_BASE( JNIEnv * pEnv, jobject myObj ) : java_lang_Exception( pEnv, myObj )
+{
+}
+
+jclass java_sql_SQLException_BASE::theClass = nullptr;
+
+java_sql_SQLException_BASE::~java_sql_SQLException_BASE()
+{}
+
+
+jclass java_sql_SQLException_BASE::getMyClass() const
+{
+ return st_getMyClass();
+}
+jclass java_sql_SQLException_BASE::st_getMyClass()
+{
+ // The class needs to be fetched just once, that is why it is static
+ if( !theClass )
+ theClass = findMyClass("java/sql/SQLException");
+ return theClass;
+}
+
+css::sdbc::SQLException java_sql_SQLException_BASE::getNextException() const
+{
+ SDBThreadAttach t;
+ static jmethodID mID(nullptr);
+ jobject out = callObjectMethod(t.pEnv,"getNextException","()Ljava/sql/SQLException;", mID);
+ // WARNING: the caller will become the owner of the returned pointers !!!
+ if( out )
+ {
+ java_sql_SQLException_BASE warn_base(t.pEnv,out);
+ return css::sdbc::SQLException(java_sql_SQLException(warn_base,nullptr));
+ }
+
+ return css::sdbc::SQLException();
+}
+
+OUString java_sql_SQLException_BASE::getSQLState() const
+{
+ static jmethodID mID(nullptr);
+ return callStringMethod("getSQLState",mID);
+}
+sal_Int32 java_sql_SQLException_BASE::getErrorCode() const
+{
+ static jmethodID mID(nullptr);
+ return callIntMethod_ThrowSQL("getErrorCode", mID);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/jdbc/SQLWarning.cxx b/connectivity/source/drivers/jdbc/SQLWarning.cxx
new file mode 100644
index 0000000000..487665d7d0
--- /dev/null
+++ b/connectivity/source/drivers/jdbc/SQLWarning.cxx
@@ -0,0 +1,37 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <java/sql/SQLWarning.hxx>
+using namespace connectivity;
+
+//************ Class: java.sql.SQLWarning
+
+jclass java_sql_SQLWarning_BASE::theClass = nullptr;
+
+java_sql_SQLWarning_BASE::~java_sql_SQLWarning_BASE() {}
+
+jclass java_sql_SQLWarning_BASE::getMyClass() const
+{
+ // the class needs to be fetched only once, that is why it is static
+ if (!theClass)
+ theClass = findMyClass("java/sql/SQLWarning");
+ return theClass;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/jdbc/String.cxx b/connectivity/source/drivers/jdbc/String.cxx
new file mode 100644
index 0000000000..e229ef54a3
--- /dev/null
+++ b/connectivity/source/drivers/jdbc/String.cxx
@@ -0,0 +1,47 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <java/lang/String.hxx>
+#include <java/tools.hxx>
+using namespace connectivity;
+
+//************ Class: java.lang.String
+
+jclass java_lang_String::theClass = nullptr;
+
+java_lang_String::~java_lang_String() {}
+
+jclass java_lang_String::getMyClass() const { return st_getMyClass(); }
+jclass java_lang_String::st_getMyClass()
+{
+ // the class needs to be fetched only once, that is why it is static
+ if (!theClass)
+ theClass = findMyClass("java/lang/String");
+ return theClass;
+}
+
+java_lang_String::operator OUString()
+{
+ SDBThreadAttach t;
+ if (!t.pEnv)
+ return OUString();
+ return JavaString2String(t.pEnv, static_cast<jstring>(object));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/jdbc/Throwable.cxx b/connectivity/source/drivers/jdbc/Throwable.cxx
new file mode 100644
index 0000000000..db4bb89208
--- /dev/null
+++ b/connectivity/source/drivers/jdbc/Throwable.cxx
@@ -0,0 +1,59 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <java/lang/Throwable.hxx>
+
+using namespace connectivity;
+
+//************ Class: java.lang.Throwable
+
+jclass java_lang_Throwable::theClass = nullptr;
+
+java_lang_Throwable::~java_lang_Throwable() {}
+
+jclass java_lang_Throwable::getMyClass() const { return st_getMyClass(); }
+jclass java_lang_Throwable::st_getMyClass()
+{
+ // the class needs to be fetched only once, that is why it is static
+ if (!theClass)
+ theClass = findMyClass("java/lang/Throwable");
+ return theClass;
+}
+
+OUString java_lang_Throwable::getMessage() const
+{
+ static jmethodID mID(nullptr);
+ return callStringMethod("getMessage", mID);
+}
+
+OUString java_lang_Throwable::getLocalizedMessage() const
+{
+ static jmethodID mID(nullptr);
+ return callStringMethod("getLocalizedMessage", mID);
+}
+
+#if OSL_DEBUG_LEVEL > 0
+void java_lang_Throwable::printStackTrace() const
+{
+ static jmethodID mID(nullptr);
+ return callVoidMethod_ThrowSQL("printStackTrace", mID);
+}
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/jdbc/Timestamp.cxx b/connectivity/source/drivers/jdbc/Timestamp.cxx
new file mode 100644
index 0000000000..eb76247198
--- /dev/null
+++ b/connectivity/source/drivers/jdbc/Timestamp.cxx
@@ -0,0 +1,189 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <java/sql/Timestamp.hxx>
+#include <java/tools.hxx>
+#include <connectivity/dbconversion.hxx>
+#include <osl/diagnose.h>
+
+using namespace ::comphelper;
+using namespace connectivity;
+
+//************ Class: java.sql.Date
+
+
+jclass java_sql_Date::theClass = nullptr;
+java_sql_Date::java_sql_Date( const css::util::Date& _rOut ) : java_util_Date( nullptr, nullptr )
+{
+ SDBThreadAttach t;
+ if( !t.pEnv )
+ return;
+ jvalue args[1];
+ // Convert parameters
+ OUString sDateStr = ::dbtools::DBTypeConversion::toDateString(_rOut);
+ args[0].l = convertwchar_tToJavaString(t.pEnv,sDateStr);
+
+ // Turn of Java-Call for the constructor
+ // initialise temporary variables
+ jobject tempObj;
+ static jmethodID mID(nullptr);
+ if ( !mID )
+ {
+ static const char * const cSignature = "(Ljava/lang/String;)Ljava/sql/Date;";
+ mID = t.pEnv->GetStaticMethodID( getMyClass(), "valueOf", cSignature );
+ }
+ OSL_ENSURE(mID,"Unknown method id!");
+ tempObj = t.pEnv->CallStaticObjectMethod( getMyClass(), mID, args[0].l );
+ saveRef( t.pEnv, tempObj );
+ t.pEnv->DeleteLocalRef( tempObj );
+ // and clean
+}
+
+java_sql_Date::~java_sql_Date()
+{}
+
+jclass java_sql_Date::getMyClass() const
+{
+ return st_getMyClass();
+}
+jclass java_sql_Date::st_getMyClass()
+{
+ // the class needs only be fetched once, that is why it is static
+ if( !theClass )
+ theClass = findMyClass("java/sql/Date");
+ return theClass;
+}
+
+
+java_sql_Date::operator css::util::Date()
+{
+ return ::dbtools::DBTypeConversion::toDate(toString());
+}
+
+
+//************ Class: java.sql.Time
+
+
+jclass java_sql_Time::theClass = nullptr;
+
+java_sql_Time::~java_sql_Time()
+{}
+
+jclass java_sql_Time::getMyClass() const
+{
+ return st_getMyClass();
+}
+jclass java_sql_Time::st_getMyClass()
+{
+ // the class needs only be fetched once, that is why it is static
+ if( !theClass )
+ theClass = findMyClass("java/sql/Time");
+ return theClass;
+}
+java_sql_Time::java_sql_Time( const css::util::Time& _rOut ): java_util_Date( nullptr, nullptr )
+{
+ SDBThreadAttach t;
+ if( !t.pEnv )
+ return;
+ jvalue args[1];
+ // Convert parameters
+ // java.sql.Time supports only whole seconds...
+ OUString sDateStr = ::dbtools::DBTypeConversion::toTimeStringS(_rOut);
+ args[0].l = convertwchar_tToJavaString(t.pEnv,sDateStr);
+
+ // Turn off Java-Call for the constructor
+ // initialise temporary variables
+ jobject tempObj;
+ static jmethodID mID(nullptr);
+ if ( !mID )
+ {
+ static const char * const cSignature = "(Ljava/lang/String;)Ljava/sql/Time;";
+ mID = t.pEnv->GetStaticMethodID( getMyClass(), "valueOf", cSignature );
+ }
+ OSL_ENSURE(mID,"Unknown method id!");
+ tempObj = t.pEnv->CallStaticObjectMethod( getMyClass(), mID, args[0].l );
+ t.pEnv->DeleteLocalRef(static_cast<jstring>(args[0].l));
+ saveRef( t.pEnv, tempObj );
+ t.pEnv->DeleteLocalRef( tempObj );
+ // and clean
+}
+
+java_sql_Time::operator css::util::Time()
+{
+ return ::dbtools::DBTypeConversion::toTime(toString());
+}
+
+//************ Class: java.sql.Timestamp
+
+
+jclass java_sql_Timestamp::theClass = nullptr;
+
+java_sql_Timestamp::~java_sql_Timestamp()
+{}
+
+jclass java_sql_Timestamp::getMyClass() const
+{
+ return st_getMyClass();
+}
+
+jclass java_sql_Timestamp::st_getMyClass()
+{
+ // the class needs only be fetched once, that is why it is static
+ if( !theClass )
+ theClass = findMyClass("java/sql/Timestamp");
+ return theClass;
+}
+
+java_sql_Timestamp::java_sql_Timestamp(const css::util::DateTime& _rOut)
+ :java_util_Date( nullptr, nullptr )
+{
+ SDBThreadAttach t;
+ if( !t.pEnv )
+ return;
+ jvalue args[1];
+ // Convert parameters
+ OUString sDateStr = ::dbtools::DBTypeConversion::toDateTimeString(_rOut);
+
+ args[0].l = convertwchar_tToJavaString(t.pEnv,sDateStr);
+
+ // Turn off Java-Call for the constructor
+ // initialise temporary variables
+ jobject tempObj;
+ static jmethodID mID(nullptr);
+ if ( !mID )
+ {
+ static const char * const cSignature = "(Ljava/lang/String;)Ljava/sql/Timestamp;";
+ mID = t.pEnv->GetStaticMethodID( getMyClass(), "valueOf", cSignature );
+ }
+ OSL_ENSURE(mID,"Unknown method id!");
+ tempObj = t.pEnv->CallStaticObjectMethod( getMyClass(), mID, args[0].l );
+
+ saveRef( t.pEnv, tempObj );
+ t.pEnv->DeleteLocalRef( tempObj );
+ // and clean
+}
+
+
+java_sql_Timestamp::operator css::util::DateTime()
+{
+ return ::dbtools::DBTypeConversion::toDateTime(toString());
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/jdbc/jdbc.component b/connectivity/source/drivers/jdbc/jdbc.component
new file mode 100644
index 0000000000..86a6a079b4
--- /dev/null
+++ b/connectivity/source/drivers/jdbc/jdbc.component
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ -->
+
+<!-- Recent Java 6 VMs make calls to JNI Attach/DetachCurrentThread (which this
+ code does extensively) very expensive. A follow-up JVM fix reduced the
+ overhead significantly again for all threads but the main thread. So a
+ quick hack to improve performance of this component again is to confine it
+ in the affine apartment (where all code will run on a single, dedicated
+ thread that is guaranteed no to be the main thread). However, a better fix
+ would still be to redesign the code so that it does not call
+ Attach/DetachCurrentThread so frequently:
+-->
+
+<component loader="com.sun.star.loader.SharedLibrary"
+ environment="@CPPU_ENV@:affine"
+ xmlns="http://openoffice.org/2010/uno-components">
+ <implementation name="com.sun.star.comp.sdbc.JDBCDriver"
+ constructor="connectivity_java_sql_Driver_get_implementation">
+ <service name="com.sun.star.sdbc.Driver"/>
+ </implementation>
+</component>
diff --git a/connectivity/source/drivers/jdbc/tools.cxx b/connectivity/source/drivers/jdbc/tools.cxx
new file mode 100644
index 0000000000..4a4d5069ea
--- /dev/null
+++ b/connectivity/source/drivers/jdbc/tools.cxx
@@ -0,0 +1,261 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <string.h>
+#include <java/tools.hxx>
+#include <java/util/Property.hxx>
+#include <com/sun/star/sdbc/DriverPropertyInfo.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <connectivity/dbexception.hxx>
+#include <osl/diagnose.h>
+
+using namespace connectivity;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+
+void java_util_Properties::setProperty(const OUString& key, const OUString& value)
+{
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+
+ {
+ jvalue args[2];
+ // Convert Parameter
+ args[0].l = convertwchar_tToJavaString(t.pEnv,key);
+ args[1].l = convertwchar_tToJavaString(t.pEnv,value);
+ // Initialize temporary Variables
+ static const char * const cSignature = "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Object;";
+ static const char * const cMethodName = "setProperty";
+ // Turn off Java-Call
+ static jmethodID mID(nullptr);
+ obtainMethodId_throwSQL(t.pEnv, cMethodName,cSignature, mID);
+ jobject out = t.pEnv->CallObjectMethod(object, mID, args[0].l,args[1].l);
+ ThrowSQLException(t.pEnv,nullptr);
+ t.pEnv->DeleteLocalRef(static_cast<jstring>(args[1].l));
+ t.pEnv->DeleteLocalRef(static_cast<jstring>(args[0].l));
+ ThrowSQLException(t.pEnv,nullptr);
+ if(out)
+ t.pEnv->DeleteLocalRef(out);
+ } //t.pEnv
+ // WARNING: The caller will be owner of the returned pointers!!!
+}
+jclass java_util_Properties::theClass = nullptr;
+
+java_util_Properties::~java_util_Properties()
+{}
+
+jclass java_util_Properties::getMyClass() const
+{
+ // the class needs only be called once, that is why it is static
+ if( !theClass )
+ theClass = findMyClass("java/util/Properties");
+ return theClass;
+}
+
+
+java_util_Properties::java_util_Properties( ): java_lang_Object( nullptr, nullptr )
+{
+ SDBThreadAttach t;
+ if( !t.pEnv )
+ return;
+ // Turn off Java-Call for the constructor
+ // Initialize temporary Variables
+ static const char * const cSignature = "()V";
+ jobject tempObj;
+ static jmethodID mID(nullptr);
+ obtainMethodId_throwSQL(t.pEnv, "<init>",cSignature, mID);
+ tempObj = t.pEnv->NewObject( getMyClass(), mID);
+ saveRef( t.pEnv, tempObj );
+ t.pEnv->DeleteLocalRef( tempObj );
+}
+
+
+jstring connectivity::convertwchar_tToJavaString(JNIEnv *pEnv,const OUString& _rTemp)
+{
+ OSL_ENSURE(pEnv,"Environment is NULL!");
+ jstring pStr = pEnv->NewString(
+ reinterpret_cast<jchar const *>(_rTemp.getStr()), _rTemp.getLength());
+ pEnv->ExceptionClear();
+ OSL_ENSURE(pStr,"Could not create a jsstring object!");
+ return pStr;
+}
+
+
+std::unique_ptr<java_util_Properties> connectivity::createStringPropertyArray(const Sequence< PropertyValue >& info )
+{
+ std::unique_ptr<java_util_Properties> pProps(new java_util_Properties());
+ const PropertyValue* pBegin = info.getConstArray();
+ const PropertyValue* pEnd = pBegin + info.getLength();
+
+ for(;pBegin != pEnd;++pBegin)
+ {
+ // these are properties used internally by LibreOffice,
+ // and should not be passed to the JDBC driver
+ // (which probably does not know anything about them anyway).
+ if ( pBegin->Name != "JavaDriverClass"
+ && pBegin->Name != "JavaDriverClassPath"
+ && pBegin->Name != "SystemProperties"
+ && pBegin->Name != "CharSet"
+ && pBegin->Name != "AppendTableAliasName"
+ && pBegin->Name != "AppendTableAliasInSelect"
+ && pBegin->Name != "DisplayVersionColumns"
+ && pBegin->Name != "GeneratedValues"
+ && pBegin->Name != "UseIndexDirectionKeyword"
+ && pBegin->Name != "UseKeywordAsBeforeAlias"
+ && pBegin->Name != "AddIndexAppendix"
+ && pBegin->Name != "FormsCheckRequiredFields"
+ && pBegin->Name != "GenerateASBeforeCorrelationName"
+ && pBegin->Name != "EscapeDateTime"
+ && pBegin->Name != "ParameterNameSubstitution"
+ && pBegin->Name != "IsPasswordRequired"
+ && pBegin->Name != "IsAutoRetrievingEnabled"
+ && pBegin->Name != "AutoRetrievingStatement"
+ && pBegin->Name != "UseCatalogInSelect"
+ && pBegin->Name != "UseSchemaInSelect"
+ && pBegin->Name != "AutoIncrementCreation"
+ && pBegin->Name != "Extension"
+ && pBegin->Name != "NoNameLengthLimit"
+ && pBegin->Name != "EnableSQL92Check"
+ && pBegin->Name != "EnableOuterJoinEscape"
+ && pBegin->Name != "BooleanComparisonMode"
+ && pBegin->Name != "IgnoreCurrency"
+ && pBegin->Name != "TypeInfoSettings"
+ && pBegin->Name != "IgnoreDriverPrivileges"
+ && pBegin->Name != "ImplicitCatalogRestriction"
+ && pBegin->Name != "ImplicitSchemaRestriction"
+ && pBegin->Name != "SupportsTableCreation"
+ && pBegin->Name != "UseJava"
+ && pBegin->Name != "Authentication"
+ && pBegin->Name != "PreferDosLikeLineEnds"
+ && pBegin->Name != "PrimaryKeySupport"
+ && pBegin->Name != "RespectDriverResultSetType"
+ )
+ {
+ OUString aStr;
+ OSL_VERIFY( pBegin->Value >>= aStr );
+ pProps->setProperty(pBegin->Name,aStr);
+ }
+ }
+ return pProps;
+}
+
+OUString connectivity::JavaString2String(JNIEnv *pEnv,jstring Str)
+{
+ OUString aStr;
+ if(Str)
+ {
+ jboolean bCopy(true);
+ const jchar* pChar = pEnv->GetStringChars(Str,&bCopy);
+ jsize len = pEnv->GetStringLength(Str);
+ aStr = OUString(reinterpret_cast<sal_Unicode const *>(pChar), len);
+
+ if(bCopy)
+ pEnv->ReleaseStringChars(Str,pChar);
+ pEnv->DeleteLocalRef(Str);
+ }
+ return aStr;
+}
+
+jobject connectivity::convertTypeMapToJavaMap(const Reference< css::container::XNameAccess > & _rMap)
+{
+ if ( _rMap.is() )
+ {
+ css::uno::Sequence< OUString > aNames = _rMap->getElementNames();
+ if ( aNames.hasElements() )
+ ::dbtools::throwFeatureNotImplementedSQLException( "Type maps", nullptr );
+ }
+ return nullptr;
+}
+
+bool connectivity::isExceptionOccurred(JNIEnv *pEnv)
+{
+ if ( !pEnv )
+ return false;
+
+ jthrowable pThrowable = pEnv->ExceptionOccurred();
+ bool bRet = pThrowable != nullptr;
+ if ( pThrowable )
+ {
+ pEnv->ExceptionClear();
+ pEnv->DeleteLocalRef(pThrowable);
+ }
+
+ return bRet;
+}
+
+jobject connectivity::createByteInputStream(const css::uno::Reference< css::io::XInputStream >& x,sal_Int32 length)
+{
+ SDBThreadAttach t;
+ if( !t.pEnv || !x.is() )
+ return nullptr;
+ // Turn off Java-Call for the constructor
+ // Initialize temporary variables
+ jclass clazz = java_lang_Object::findMyClass("java/io/ByteArrayInputStream");
+ static jmethodID mID(nullptr);
+ if ( !mID )
+ {
+ static const char * const cSignature = "([B)V";
+ mID = t.pEnv->GetMethodID( clazz, "<init>", cSignature );
+ OSL_ENSURE( mID, cSignature );
+ if ( !mID )
+ throw SQLException();
+ } // if ( !_inout_MethodID )
+ jbyteArray pByteArray = t.pEnv->NewByteArray(length);
+ Sequence< sal_Int8 > aData;
+ x->readBytes(aData,length);
+ jboolean p = false;
+ memcpy(t.pEnv->GetByteArrayElements(pByteArray,&p),aData.getArray(),aData.getLength());
+ jobject out = t.pEnv->NewObject( clazz, mID,pByteArray);
+ t.pEnv->DeleteLocalRef(pByteArray);
+ return out;
+}
+
+jobject connectivity::createCharArrayReader(const css::uno::Reference< css::io::XInputStream >& x,sal_Int32 length)
+{
+ SDBThreadAttach t;
+ if( !t.pEnv || !x.is() )
+ return nullptr;
+ // Turn off Java-Call for the constructor
+ // Initialize temporary Variables
+ jclass clazz = java_lang_Object::findMyClass("java/io/CharArrayReader");
+ static jmethodID mID(nullptr);
+ if ( !mID )
+ {
+ static const char * const cSignature = "([C)V";
+ mID = t.pEnv->GetMethodID( clazz, "<init>", cSignature );
+ OSL_ENSURE( mID, cSignature );
+ if ( !mID )
+ throw SQLException();
+ } // if ( !_inout_MethodID )
+ jcharArray pCharArray = t.pEnv->NewCharArray(length);
+ Sequence< sal_Int8 > aData;
+ x->readBytes(aData,length);
+ jboolean p = false;
+ memcpy(t.pEnv->GetCharArrayElements(pCharArray,&p),aData.getArray(),aData.getLength());
+ jobject out = t.pEnv->NewObject( clazz, mID,pCharArray);
+ t.pEnv->DeleteLocalRef(pCharArray);
+ return out;
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/macab/MacabAddressBook.cxx b/connectivity/source/drivers/macab/MacabAddressBook.cxx
new file mode 100644
index 0000000000..7ade1ac0a8
--- /dev/null
+++ b/connectivity/source/drivers/macab/MacabAddressBook.cxx
@@ -0,0 +1,249 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include "MacabAddressBook.hxx"
+#include "MacabRecords.hxx"
+#include "MacabGroup.hxx"
+
+#include <vector>
+
+#include <premac.h>
+#include <Carbon/Carbon.h>
+#include <AddressBook/ABAddressBookC.h>
+#include <postmac.h>
+#include <connectivity/CommonTools.hxx>
+
+using namespace connectivity::macab;
+using namespace ::com::sun::star::uno;
+
+namespace {
+
+void manageDuplicateGroups(std::vector<MacabGroup *> _xGroups)
+{
+ /* If we have two cases of groups, say, family, this makes it:
+ * family
+ * family (2)
+ */
+ std::vector<MacabGroup *>::reverse_iterator iter1, iter2;
+ sal_Int32 count;
+
+ for(iter1 = _xGroups.rbegin(); iter1 != _xGroups.rend(); ++iter1)
+ {
+ /* If the name matches the default table name, there is already
+ * (obviously) a conflict. So, start the count of groups with this
+ * name at 2 instead of 1.
+ */
+ if( (*iter1)->getName() == MacabAddressBook::getDefaultTableName() )
+ count = 2;
+ else
+ count = 1;
+
+ iter2 = iter1;
+ for( ++iter2; iter2 != _xGroups.rend(); ++iter2)
+ {
+ if( (*iter1)->getName() == (*iter2)->getName() )
+ {
+ count++;
+ }
+ }
+
+ // duplicate!
+ if(count != 1)
+ {
+ OUString sName = (*iter1)->getName() + " (" +
+ OUString::number(count) +
+ ")";
+ (*iter1)->setName(sName);
+ }
+ }
+}
+
+}
+
+MacabAddressBook::MacabAddressBook( )
+ : m_aAddressBook(ABGetSharedAddressBook()),
+ m_xMacabRecords(nullptr),
+ m_bRetrievedGroups(false)
+{
+ if(m_aAddressBook == nullptr)
+ {
+ // TODO: tell the user to reset the permission via "tccutil reset AddressBook"
+ // or the system preferences and try again, this time granting the access
+ throw RuntimeException(
+ "failed to access the macOS address book - permission not granted?" );
+ }
+}
+
+
+MacabAddressBook::~MacabAddressBook()
+{
+ if(m_xMacabRecords != nullptr)
+ {
+ delete m_xMacabRecords;
+ m_xMacabRecords = nullptr;
+ }
+
+ for(MacabGroup* pMacabGroup : m_xMacabGroups)
+ delete pMacabGroup;
+
+ m_bRetrievedGroups = false;
+}
+
+
+/* Get the address book's default table name. This is the table name that
+ * refers to the table containing _all_ records in the address book.
+ */
+const OUString & MacabAddressBook::getDefaultTableName()
+{
+ /* This string probably needs to be localized. */
+ static constexpr OUString aDefaultTableName
+ (u"Address Book"_ustr);
+
+ return aDefaultTableName;
+}
+
+
+MacabRecords *MacabAddressBook::getMacabRecords()
+{
+ /* If the MacabRecords don't exist, create them. */
+ if(m_xMacabRecords == nullptr)
+ {
+ m_xMacabRecords = new MacabRecords(m_aAddressBook);
+ m_xMacabRecords->setName(getDefaultTableName());
+ m_xMacabRecords->initialize();
+ }
+
+ return m_xMacabRecords;
+}
+
+
+/* Get the MacabRecords for a given name: either a group name or the
+ * default table name.
+ */
+MacabRecords *MacabAddressBook::getMacabRecords(std::u16string_view _tableName)
+{
+ if(_tableName == getDefaultTableName())
+ {
+ return getMacabRecords();
+ }
+ else
+ {
+ return getMacabGroup(_tableName);
+ }
+}
+
+
+MacabRecords *MacabAddressBook::getMacabRecordsMatch(const OUString& _tableName)
+{
+ if(match(_tableName, getDefaultTableName(), '\0'))
+ {
+ return getMacabRecords();
+ }
+
+ return getMacabGroupMatch(_tableName);
+}
+
+
+std::vector<MacabGroup *> MacabAddressBook::getMacabGroups()
+{
+ /* If the MacabGroups haven't been created yet, create them. */
+ if(!m_bRetrievedGroups)
+ {
+ /* If the MacabRecords haven't been created yet, create them. */
+ if(m_xMacabRecords == nullptr)
+ {
+ m_xMacabRecords = new MacabRecords(m_aAddressBook);
+ m_xMacabRecords->setName(getDefaultTableName());
+ m_xMacabRecords->initialize();
+ }
+
+ CFArrayRef allGroups = ABCopyArrayOfAllGroups(m_aAddressBook);
+ sal_Int32 nGroups = CFArrayGetCount(allGroups);
+ m_xMacabGroups = std::vector<MacabGroup *>(nGroups);
+
+ sal_Int32 i;
+ ABGroupRef xGroup;
+
+ /* Go through each group and create a MacabGroup out of it. */
+ for(i = 0; i < nGroups; i++)
+ {
+ xGroup = static_cast<ABGroupRef>(const_cast<void *>(CFArrayGetValueAtIndex(allGroups, i)));
+ m_xMacabGroups[i] = new MacabGroup(m_aAddressBook, m_xMacabRecords, xGroup);
+ }
+
+ CFRelease(allGroups);
+
+ /* Manage duplicates. */
+ manageDuplicateGroups(m_xMacabGroups);
+ m_bRetrievedGroups = true;
+ }
+
+ return m_xMacabGroups;
+}
+
+
+MacabGroup *MacabAddressBook::getMacabGroup(std::u16string_view _groupName)
+{
+ // initialize groups if not already initialized
+ if(!m_bRetrievedGroups)
+ getMacabGroups();
+
+ sal_Int32 nGroups = m_xMacabGroups.size();
+ sal_Int32 i;
+
+ for(i = 0; i < nGroups; i++)
+ {
+ if(m_xMacabGroups[i] != nullptr)
+ {
+ if(m_xMacabGroups[i]->getName() == _groupName)
+ {
+ return m_xMacabGroups[i];
+ }
+ }
+ }
+
+ return nullptr;
+}
+
+
+MacabGroup *MacabAddressBook::getMacabGroupMatch(OUString const & _groupName)
+{
+ // initialize groups if not already initialized
+ if(!m_bRetrievedGroups)
+ getMacabGroups();
+
+ sal_Int32 nGroups = m_xMacabGroups.size();
+ sal_Int32 i;
+
+ for(i = 0; i < nGroups; i++)
+ {
+ if(m_xMacabGroups[i] != nullptr)
+ {
+ if(match(m_xMacabGroups[i]->getName(), _groupName, '\0'))
+ {
+ return m_xMacabGroups[i];
+ }
+ }
+ }
+
+ return nullptr;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/macab/MacabAddressBook.hxx b/connectivity/source/drivers/macab/MacabAddressBook.hxx
new file mode 100644
index 0000000000..a23e0c1eb2
--- /dev/null
+++ b/connectivity/source/drivers/macab/MacabAddressBook.hxx
@@ -0,0 +1,60 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "MacabRecords.hxx"
+#include "MacabGroup.hxx"
+
+#include <string_view>
+#include <vector>
+
+#include <premac.h>
+#include <Carbon/Carbon.h>
+#include <AddressBook/ABAddressBookC.h>
+#include <postmac.h>
+
+namespace connectivity::macab
+{
+ class MacabAddressBook
+ {
+ protected:
+ ABAddressBookRef m_aAddressBook;
+ MacabRecords *m_xMacabRecords;
+ std::vector<MacabGroup *> m_xMacabGroups;
+ bool m_bRetrievedGroups;
+
+ public:
+ MacabAddressBook();
+ ~MacabAddressBook();
+ static const OUString & getDefaultTableName();
+
+ MacabRecords *getMacabRecords();
+ std::vector<MacabGroup *> getMacabGroups();
+
+ MacabGroup *getMacabGroup(std::u16string_view _groupName);
+ MacabRecords *getMacabRecords(std::u16string_view _tableName);
+
+ MacabGroup *getMacabGroupMatch(const OUString& _groupName);
+ MacabRecords *getMacabRecordsMatch(const OUString& _tableName);
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/macab/MacabCatalog.cxx b/connectivity/source/drivers/macab/MacabCatalog.cxx
new file mode 100644
index 0000000000..d6485ab1c9
--- /dev/null
+++ b/connectivity/source/drivers/macab/MacabCatalog.cxx
@@ -0,0 +1,112 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include "MacabCatalog.hxx"
+#include "MacabConnection.hxx"
+#include "MacabTables.hxx"
+#include <com/sun/star/sdbc/XRow.hpp>
+
+using namespace connectivity::macab;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+using namespace ::cppu;
+
+
+MacabCatalog::MacabCatalog(MacabConnection* _pCon)
+ : connectivity::sdbcx::OCatalog(_pCon),
+ m_pConnection(_pCon)
+{
+}
+
+void MacabCatalog::refreshTables()
+{
+ ::std::vector< OUString> aVector;
+ Sequence< OUString > aTypes { "%" };
+ Reference< XResultSet > xResult = m_xMetaData->getTables(
+ Any(), "%", "%", aTypes);
+
+ if (xResult.is())
+ {
+ Reference< XRow > xRow(xResult,UNO_QUERY);
+ OUString aName;
+ // const OUString& sDot = MacabCatalog::getDot();
+
+ while (xResult->next())
+ {
+ // aName = xRow->getString(2);
+ // aName += sDot;
+ aName = xRow->getString(3);
+ aVector.push_back(aName);
+ }
+ }
+ if (m_pTables)
+ m_pTables->reFill(aVector);
+ else
+ m_pTables.reset( new MacabTables(m_xMetaData,*this,m_aMutex,aVector) );
+}
+
+void MacabCatalog::refreshViews()
+{
+}
+
+void MacabCatalog::refreshGroups()
+{
+}
+
+void MacabCatalog::refreshUsers()
+{
+}
+
+const OUString& MacabCatalog::getDot()
+{
+ static constexpr OUString sDot = u"."_ustr;
+ return sDot;
+}
+
+
+// XTablesSupplier
+Reference< XNameAccess > SAL_CALL MacabCatalog::getTables( )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(rBHelper.bDisposed);
+
+ try
+ {
+ if (!m_pTables)
+ refreshTables();
+ }
+ catch( const RuntimeException& )
+ {
+ // allowed to leave this method
+ throw;
+ }
+ catch( const Exception& )
+ {
+ // allowed
+ }
+
+ return m_pTables.get();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/macab/MacabCatalog.hxx b/connectivity/source/drivers/macab/MacabCatalog.hxx
new file mode 100644
index 0000000000..1757bb9088
--- /dev/null
+++ b/connectivity/source/drivers/macab/MacabCatalog.hxx
@@ -0,0 +1,51 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sdbcx/VCatalog.hxx>
+
+namespace connectivity::macab
+{
+ class MacabConnection;
+
+ class MacabCatalog : public connectivity::sdbcx::OCatalog
+ {
+ MacabConnection* m_pConnection; // used to get the metadata
+
+ public:
+ explicit MacabCatalog(MacabConnection* _pCon);
+
+ MacabConnection* getConnection() const { return m_pConnection; }
+
+ static const OUString& getDot();
+
+ // implementation of the pure virtual methods
+ virtual void refreshTables() override;
+ virtual void refreshViews() override;
+ virtual void refreshGroups() override;
+ virtual void refreshUsers() override;
+
+ // XTablesSupplier
+ virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getTables(
+ ) override;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/macab/MacabColumns.cxx b/connectivity/source/drivers/macab/MacabColumns.cxx
new file mode 100644
index 0000000000..6a49ad1d06
--- /dev/null
+++ b/connectivity/source/drivers/macab/MacabColumns.cxx
@@ -0,0 +1,94 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include "MacabColumns.hxx"
+#include "MacabTable.hxx"
+#include "MacabTables.hxx"
+#include "MacabCatalog.hxx"
+#include <connectivity/sdbcx/VColumn.hxx>
+#include <com/sun/star/sdbc/XRow.hpp>
+
+using namespace connectivity::macab;
+using namespace connectivity::sdbcx;
+using namespace connectivity;
+using namespace ::comphelper;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+
+
+sdbcx::ObjectType MacabColumns::createObject(const OUString& _rName)
+{
+ const Any aCatalog;
+ const OUString sCatalogName;
+ const OUString sSchemaName(m_pTable->getSchema());
+ const OUString sTableName(m_pTable->getTableName());
+ Reference< XResultSet > xResult = m_pTable->getConnection()->getMetaData()->getColumns(
+ aCatalog, sSchemaName, sTableName, _rName);
+
+ sdbcx::ObjectType xRet;
+ if (xResult.is())
+ {
+ Reference< XRow > xRow(xResult,UNO_QUERY);
+
+ while (xResult->next())
+ {
+ if (xRow->getString(4) == _rName)
+ {
+ xRet = new OColumn(
+ _rName,
+ xRow->getString(6),
+ xRow->getString(13),
+ xRow->getString(12),
+ xRow->getInt(11),
+ xRow->getInt(7),
+ xRow->getInt(9),
+ xRow->getInt(5),
+ false,
+ false,
+ false,
+ true,
+ sCatalogName,
+ sSchemaName,
+ sTableName);
+ break;
+ }
+ }
+ }
+
+ return xRet;
+}
+
+void MacabColumns::impl_refresh()
+{
+ m_pTable->refreshColumns();
+}
+
+MacabColumns::MacabColumns( MacabTable* _pTable,
+ ::osl::Mutex& _rMutex,
+ const ::std::vector< OUString> &_rVector)
+ : sdbcx::OCollection(*_pTable, true, _rMutex, _rVector),
+ m_pTable(_pTable)
+{
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/macab/MacabColumns.hxx b/connectivity/source/drivers/macab/MacabColumns.hxx
new file mode 100644
index 0000000000..7123af89d3
--- /dev/null
+++ b/connectivity/source/drivers/macab/MacabColumns.hxx
@@ -0,0 +1,42 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "MacabTable.hxx"
+#include <connectivity/sdbcx/VCollection.hxx>
+
+namespace connectivity::macab
+{
+ class MacabColumns : public sdbcx::OCollection
+ {
+ protected:
+ MacabTable* m_pTable;
+
+ virtual sdbcx::ObjectType createObject(const OUString& _rName) override;
+ virtual void impl_refresh() override;
+
+ public:
+ MacabColumns( MacabTable* _pTable,
+ ::osl::Mutex& _rMutex,
+ const ::std::vector< OUString> &_rVector);
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/macab/MacabConnection.cxx b/connectivity/source/drivers/macab/MacabConnection.cxx
new file mode 100644
index 0000000000..eaa6cf5232
--- /dev/null
+++ b/connectivity/source/drivers/macab/MacabConnection.cxx
@@ -0,0 +1,316 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include "MacabConnection.hxx"
+#include "MacabAddressBook.hxx"
+#include "MacabDatabaseMetaData.hxx"
+#include "MacabStatement.hxx"
+#include "MacabPreparedStatement.hxx"
+#include "MacabDriver.hxx"
+#include "MacabCatalog.hxx"
+#include <com/sun/star/sdbc/ColumnValue.hpp>
+#include <com/sun/star/sdbc/TransactionIsolation.hpp>
+#include <cppuhelper/weak.hxx>
+
+using namespace connectivity::macab;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::sdbc;
+using namespace com::sun::star::sdbcx;
+
+IMPLEMENT_SERVICE_INFO(MacabConnection, "com.sun.star.sdbc.drivers.MacabConnection", "com.sun.star.sdbc.Connection")
+
+MacabConnection::MacabConnection(MacabDriver* _pDriver)
+ : m_pAddressBook(nullptr),
+ m_pDriver(_pDriver)
+{
+ m_pDriver->acquire();
+}
+
+MacabConnection::~MacabConnection()
+{
+ if (!doIsClosed())
+ doClose();
+
+ m_pDriver->release();
+ m_pDriver = nullptr;
+}
+
+void MacabConnection::construct(const OUString&, const Sequence< PropertyValue >&)
+{
+ osl_atomic_increment( &m_refCount );
+
+ // get the macOS shared address book
+ m_pAddressBook = new MacabAddressBook();
+
+ osl_atomic_decrement( &m_refCount );
+}
+// XServiceInfo
+
+Reference< XStatement > SAL_CALL MacabConnection::createStatement( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabConnection_BASE::rBHelper.bDisposed);
+
+ // create a statement
+ // the statement can only be executed once
+ Reference< XStatement > xReturn = new MacabStatement(this);
+ m_aStatements.push_back(WeakReferenceHelper(xReturn));
+ return xReturn;
+}
+
+Reference< XPreparedStatement > SAL_CALL MacabConnection::prepareStatement( const OUString& _sSql )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabConnection_BASE::rBHelper.bDisposed);
+
+ // create a statement
+ // the statement can only be executed more than once
+ Reference< XPreparedStatement > xReturn = new MacabPreparedStatement(this, _sSql);
+ m_aStatements.push_back(WeakReferenceHelper(xReturn));
+ return xReturn;
+}
+
+Reference< XPreparedStatement > SAL_CALL MacabConnection::prepareCall( const OUString& )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabConnection_BASE::rBHelper.bDisposed);
+
+ // not implemented yet :-) a task to do
+ return nullptr;
+}
+
+OUString SAL_CALL MacabConnection::nativeSQL( const OUString& _sSql )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ // when you need to transform SQL92 to you driver specific you can do it here
+
+ return _sSql;
+}
+
+void SAL_CALL MacabConnection::setAutoCommit( sal_Bool )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabConnection_BASE::rBHelper.bDisposed);
+ // here you have to set your commit mode please have a look at the jdbc documentation to get a clear explanation
+}
+
+sal_Bool SAL_CALL MacabConnection::getAutoCommit( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabConnection_BASE::rBHelper.bDisposed);
+ // you have to distinguish which if you are in autocommit mode or not
+ // at normal case true should be fine here
+
+ return true;
+}
+
+void SAL_CALL MacabConnection::commit( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabConnection_BASE::rBHelper.bDisposed);
+
+ // when you database does support transactions you should commit here
+}
+
+void SAL_CALL MacabConnection::rollback( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabConnection_BASE::rBHelper.bDisposed);
+
+ // same as commit but for the other case
+}
+
+sal_Bool SAL_CALL MacabConnection::isClosed( )
+{
+ return doIsClosed();
+}
+
+bool MacabConnection::doIsClosed()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ // just simple -> we are closed when we are disposed, that means someone called dispose(); (XComponent)
+ return MacabConnection_BASE::rBHelper.bDisposed;
+}
+
+Reference< XDatabaseMetaData > SAL_CALL MacabConnection::getMetaData( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabConnection_BASE::rBHelper.bDisposed);
+
+ // here we have to create the class with biggest interface
+ // The answer is 42 :-)
+ Reference< XDatabaseMetaData > xMetaData = m_xMetaData;
+ if (!xMetaData.is())
+ {
+ xMetaData = new MacabDatabaseMetaData(this); // need the connection because it can return it
+ m_xMetaData = xMetaData;
+ }
+
+ return xMetaData;
+}
+
+void SAL_CALL MacabConnection::setReadOnly( sal_Bool )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabConnection_BASE::rBHelper.bDisposed);
+
+ // set you connection to readonly
+}
+
+sal_Bool SAL_CALL MacabConnection::isReadOnly( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabConnection_BASE::rBHelper.bDisposed);
+
+ // return if your connection to readonly
+ return false;
+}
+
+void SAL_CALL MacabConnection::setCatalog( const OUString& )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabConnection_BASE::rBHelper.bDisposed);
+
+ // if your database doesn't work with catalogs you go to next method otherwise you know what to do
+}
+
+OUString SAL_CALL MacabConnection::getCatalog( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabConnection_BASE::rBHelper.bDisposed);
+
+
+ // return your current catalog
+ return OUString();
+}
+
+void SAL_CALL MacabConnection::setTransactionIsolation( sal_Int32 )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabConnection_BASE::rBHelper.bDisposed);
+
+ // set your isolation level
+ // please have a look at @see com.sun.star.sdbc.TransactionIsolation
+}
+
+sal_Int32 SAL_CALL MacabConnection::getTransactionIsolation( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabConnection_BASE::rBHelper.bDisposed);
+
+
+ // please have a look at @see com.sun.star.sdbc.TransactionIsolation
+ return TransactionIsolation::NONE;
+}
+
+Reference< css::container::XNameAccess > SAL_CALL MacabConnection::getTypeMap( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabConnection_BASE::rBHelper.bDisposed);
+
+ // if your driver has special database types you can return it here
+
+ return nullptr;
+}
+
+void SAL_CALL MacabConnection::setTypeMap( const Reference< css::container::XNameAccess >& )
+{
+ // the other way around
+}
+
+// XCloseable
+void SAL_CALL MacabConnection::close( )
+{
+ doClose();
+}
+
+void MacabConnection::doClose()
+{
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabConnection_BASE::rBHelper.bDisposed);
+ }
+ dispose();
+}
+
+// XWarningsSupplier
+Any SAL_CALL MacabConnection::getWarnings( )
+{
+ // when you collected some warnings -> return it
+ return Any();
+}
+
+void SAL_CALL MacabConnection::clearWarnings( )
+{
+ // you should clear your collected warnings here
+}
+
+void MacabConnection::disposing()
+{
+ // we noticed that we should be destroyed in near future so we have to dispose our statements
+ ::osl::MutexGuard aGuard(m_aMutex);
+
+ for (auto& rxStatement : m_aStatements)
+ {
+ Reference< XComponent > xComp(rxStatement.get(), UNO_QUERY);
+ if (xComp.is())
+ xComp->dispose();
+ }
+ m_aStatements.clear();
+
+ if (m_pAddressBook != nullptr)
+ {
+ delete m_pAddressBook;
+ m_pAddressBook = nullptr;
+ }
+
+ m_xMetaData.clear();
+
+ MacabConnection_BASE::disposing();
+}
+
+Reference< XTablesSupplier > MacabConnection::createCatalog()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ Reference< XTablesSupplier > xTab = m_xCatalog;
+ if (!m_xCatalog.is())
+ {
+ xTab = new MacabCatalog(this);
+ m_xCatalog = xTab;
+ }
+ return xTab;
+}
+
+MacabAddressBook* MacabConnection::getAddressBook() const
+{
+ return m_pAddressBook;
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT void* createMacabConnection( void* _pDriver )
+{
+ // by definition, the pointer crossing library boundaries as void ptr is acquired once
+ return cppu::acquire(new MacabConnection( static_cast< MacabDriver* >( _pDriver ) ));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/macab/MacabConnection.hxx b/connectivity/source/drivers/macab/MacabConnection.hxx
new file mode 100644
index 0000000000..dc2bfa34f5
--- /dev/null
+++ b/connectivity/source/drivers/macab/MacabConnection.hxx
@@ -0,0 +1,110 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <connectivity/CommonTools.hxx>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/sdbc/XWarningsSupplier.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <com/sun/star/sdbcx/XTablesSupplier.hpp>
+#include <cppuhelper/compbase.hxx>
+#include <TConnection.hxx>
+
+namespace connectivity::macab
+{
+
+ typedef ::cppu::WeakComponentImplHelper<css::sdbc::XConnection,
+ css::sdbc::XWarningsSupplier,
+ css::lang::XServiceInfo
+ > OMetaConnection_BASE;
+
+ class MacabDriver;
+ class MacabAddressBook;
+
+ typedef std::vector< css::uno::WeakReferenceHelper > OWeakRefArray;
+
+ typedef connectivity::OMetaConnection MacabConnection_BASE;
+
+ class MacabConnection : public MacabConnection_BASE
+ {
+ protected:
+
+ // Data attributes
+
+ MacabAddressBook* m_pAddressBook; // the address book
+ MacabDriver* m_pDriver; // pointer to the owning driver object
+ css::uno::Reference< css::sdbcx::XTablesSupplier>
+ m_xCatalog; // needed for the SQL interpreter
+
+ private:
+ bool doIsClosed();
+
+ void doClose();
+
+ public:
+ /// @throws css::sdbc::SQLException
+ virtual void construct( const OUString& url,const css::uno::Sequence< css::beans::PropertyValue >& info);
+
+ explicit MacabConnection(MacabDriver* _pDriver);
+ virtual ~MacabConnection() override;
+
+ // OComponentHelper
+ virtual void SAL_CALL disposing() override;
+
+ // XServiceInfo
+ DECLARE_SERVICE_INFO();
+
+ // XConnection
+ virtual css::uno::Reference< css::sdbc::XStatement > SAL_CALL createStatement( ) override;
+ virtual css::uno::Reference< css::sdbc::XPreparedStatement > SAL_CALL prepareStatement( const OUString& sql ) override;
+ virtual css::uno::Reference< css::sdbc::XPreparedStatement > SAL_CALL prepareCall( const OUString& sql ) override;
+ virtual OUString SAL_CALL nativeSQL( const OUString& sql ) override;
+ virtual void SAL_CALL setAutoCommit( sal_Bool autoCommit ) override;
+ virtual sal_Bool SAL_CALL getAutoCommit( ) override;
+ virtual void SAL_CALL commit( ) override;
+ virtual void SAL_CALL rollback( ) override;
+ virtual sal_Bool SAL_CALL isClosed( ) override;
+ virtual css::uno::Reference< css::sdbc::XDatabaseMetaData > SAL_CALL getMetaData( ) override;
+ virtual void SAL_CALL setReadOnly( sal_Bool readOnly ) override;
+ virtual sal_Bool SAL_CALL isReadOnly( ) override;
+ virtual void SAL_CALL setCatalog( const OUString& catalog ) override;
+ virtual OUString SAL_CALL getCatalog( ) override;
+ virtual void SAL_CALL setTransactionIsolation( sal_Int32 level ) override;
+ virtual sal_Int32 SAL_CALL getTransactionIsolation( ) override;
+ virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getTypeMap( ) override;
+ virtual void SAL_CALL setTypeMap( const css::uno::Reference< css::container::XNameAccess >& typeMap ) override;
+
+ // XCloseable
+ virtual void SAL_CALL close( ) override;
+
+ // XWarningsSupplier
+ virtual css::uno::Any SAL_CALL getWarnings( ) override;
+ virtual void SAL_CALL clearWarnings( ) override;
+
+ // needed for the SQL interpreter
+ css::uno::Reference< css::sdbcx::XTablesSupplier > createCatalog();
+
+ // accessors
+ MacabDriver* getDriver() const { return m_pDriver;}
+ MacabAddressBook* getAddressBook() const;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/macab/MacabDatabaseMetaData.cxx b/connectivity/source/drivers/macab/MacabDatabaseMetaData.cxx
new file mode 100644
index 0000000000..b0b04fc08f
--- /dev/null
+++ b/connectivity/source/drivers/macab/MacabDatabaseMetaData.cxx
@@ -0,0 +1,1073 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include "MacabDatabaseMetaData.hxx"
+#include "MacabAddressBook.hxx"
+#include "MacabHeader.hxx"
+#include "MacabGroup.hxx"
+#include "macabutilities.hxx"
+
+#include "MacabDriver.hxx"
+#include <FDatabaseMetaDataResultSet.hxx>
+#include <OTypeInfo.hxx>
+#include <com/sun/star/sdbc/ColumnSearch.hpp>
+#include <com/sun/star/sdbc/ColumnValue.hpp>
+#include <com/sun/star/sdbc/ResultSetType.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <com/sun/star/sdbc/TransactionIsolation.hpp>
+#include <rtl/ref.hxx>
+
+#include <vector>
+
+using namespace connectivity::macab;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::sdbc;
+
+MacabDatabaseMetaData::MacabDatabaseMetaData(MacabConnection* _pCon)
+ : m_xConnection(_pCon),
+ m_bUseCatalog(true)
+{
+ OSL_ENSURE(_pCon,"MacabDatabaseMetaData::MacabDatabaseMetaData: No connection set!");
+
+ osl_atomic_increment( &m_refCount );
+ m_bUseCatalog = !(usesLocalFiles() || usesLocalFilePerTable());
+ osl_atomic_decrement( &m_refCount );
+}
+
+MacabDatabaseMetaData::~MacabDatabaseMetaData()
+{
+}
+
+OUString SAL_CALL MacabDatabaseMetaData::getCatalogSeparator( )
+{
+ if (m_bUseCatalog)
+ { // do some special here for you database
+ }
+
+ return OUString();
+}
+
+sal_Int32 SAL_CALL MacabDatabaseMetaData::getMaxBinaryLiteralLength( )
+{
+ return 0; // 0 means no limit
+}
+
+sal_Int32 SAL_CALL MacabDatabaseMetaData::getMaxRowSize( )
+{
+ return 0; // 0 means no limit
+}
+
+sal_Int32 SAL_CALL MacabDatabaseMetaData::getMaxCatalogNameLength( )
+{
+ return 0; // 0 means no limit
+}
+
+sal_Int32 SAL_CALL MacabDatabaseMetaData::getMaxCharLiteralLength( )
+{
+ return 0; // 0 means no limit
+}
+
+sal_Int32 SAL_CALL MacabDatabaseMetaData::getMaxColumnNameLength( )
+{
+ return 0; // 0 means no limit
+}
+
+sal_Int32 SAL_CALL MacabDatabaseMetaData::getMaxColumnsInIndex( )
+{
+ return 0; // 0 means no limit
+}
+
+sal_Int32 SAL_CALL MacabDatabaseMetaData::getMaxCursorNameLength( )
+{
+ return 0; // 0 means no limit
+}
+
+sal_Int32 SAL_CALL MacabDatabaseMetaData::getMaxConnections( )
+{
+ return 0; // 0 means no limit
+}
+
+sal_Int32 SAL_CALL MacabDatabaseMetaData::getMaxColumnsInTable( )
+{
+ return 0; // 0 means no limit
+}
+
+sal_Int32 SAL_CALL MacabDatabaseMetaData::getMaxStatementLength( )
+{
+ return 0; // 0 means no limit
+}
+
+sal_Int32 SAL_CALL MacabDatabaseMetaData::getMaxTableNameLength( )
+{
+ return 0; // 0 means no limit
+}
+
+sal_Int32 SAL_CALL MacabDatabaseMetaData::getMaxTablesInSelect( )
+{
+ // MaxTablesInSelect describes how many tables can participate in the FROM part of a given SELECT statement,
+ // currently, the resultset/statement implementations can cope with one table only
+ return 1;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::doesMaxRowSizeIncludeBlobs( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::storesLowerCaseQuotedIdentifiers( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::storesLowerCaseIdentifiers( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::storesMixedCaseQuotedIdentifiers( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::storesMixedCaseIdentifiers( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::storesUpperCaseQuotedIdentifiers( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::storesUpperCaseIdentifiers( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsAlterTableWithAddColumn( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsAlterTableWithDropColumn( )
+{
+ return false;
+}
+
+sal_Int32 SAL_CALL MacabDatabaseMetaData::getMaxIndexLength( )
+{
+ return 0; // 0 means no limit
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsNonNullableColumns( )
+{
+ return false;
+}
+
+OUString SAL_CALL MacabDatabaseMetaData::getCatalogTerm( )
+{
+ return OUString();
+}
+
+OUString SAL_CALL MacabDatabaseMetaData::getIdentifierQuoteString( )
+{
+ // normally this is "
+ return "\"";
+}
+
+OUString SAL_CALL MacabDatabaseMetaData::getExtraNameCharacters( )
+{
+ return OUString();
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsDifferentTableCorrelationNames( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::isCatalogAtStart( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::dataDefinitionIgnoredInTransactions( )
+{
+ return true;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::dataDefinitionCausesTransactionCommit( )
+{
+ return true;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsDataManipulationTransactionsOnly( )
+{
+ return true;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsDataDefinitionAndDataManipulationTransactions( )
+{
+ return true;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsPositionedDelete( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsPositionedUpdate( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsOpenStatementsAcrossRollback( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsOpenStatementsAcrossCommit( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsOpenCursorsAcrossCommit( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsOpenCursorsAcrossRollback( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsTransactionIsolationLevel( sal_Int32 )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsSchemasInDataManipulation( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsANSI92FullSQL( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsANSI92EntryLevelSQL( )
+{
+ return true; // should be supported at least
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsIntegrityEnhancementFacility( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsSchemasInIndexDefinitions( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsSchemasInTableDefinitions( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsCatalogsInTableDefinitions( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsCatalogsInIndexDefinitions( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsCatalogsInDataManipulation( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsOuterJoins( )
+{
+ return false;
+}
+
+sal_Int32 SAL_CALL MacabDatabaseMetaData::getMaxStatements( )
+{
+ return 0; // 0 means no limit
+}
+
+sal_Int32 SAL_CALL MacabDatabaseMetaData::getMaxProcedureNameLength( )
+{
+ return 0; // 0 means no limit
+}
+
+sal_Int32 SAL_CALL MacabDatabaseMetaData::getMaxSchemaNameLength( )
+{
+ return 0; // 0 means no limit
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsTransactions( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::allProceduresAreCallable( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsStoredProcedures( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsSelectForUpdate( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::allTablesAreSelectable( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::isReadOnly( )
+{
+ // for the moment, we have read-only addresses, but this might change in the future
+ return true;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::usesLocalFiles( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::usesLocalFilePerTable( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsTypeConversion( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::nullPlusNonNullIsNull( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsColumnAliasing( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsTableCorrelationNames( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsConvert( sal_Int32, sal_Int32 )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsExpressionsInOrderBy( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsGroupBy( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsGroupByBeyondSelect( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsGroupByUnrelated( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsMultipleTransactions( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsMultipleResultSets( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsLikeEscapeClause( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsOrderByUnrelated( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsUnion( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsUnionAll( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsMixedCaseIdentifiers( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsMixedCaseQuotedIdentifiers( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::nullsAreSortedAtEnd( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::nullsAreSortedAtStart( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::nullsAreSortedHigh( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::nullsAreSortedLow( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsSchemasInProcedureCalls( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsSchemasInPrivilegeDefinitions( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsCatalogsInProcedureCalls( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsCatalogsInPrivilegeDefinitions( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsCorrelatedSubqueries( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsSubqueriesInComparisons( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsSubqueriesInExists( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsSubqueriesInIns( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsSubqueriesInQuantifieds( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsANSI92IntermediateSQL( )
+{
+ return false;
+}
+
+OUString SAL_CALL MacabDatabaseMetaData::getURL( )
+{
+ // if someday we support more than the default address book,
+ // this method should return the URL which was used to create it
+ return "sdbc:address:macab:";
+}
+
+OUString SAL_CALL MacabDatabaseMetaData::getUserName( )
+{
+ return OUString();
+}
+
+OUString SAL_CALL MacabDatabaseMetaData::getDriverName( )
+{
+ return "macab";
+}
+
+OUString SAL_CALL MacabDatabaseMetaData::getDriverVersion()
+{
+ return MACAB_DRIVER_VERSION;
+}
+
+OUString SAL_CALL MacabDatabaseMetaData::getDatabaseProductVersion( )
+{
+ return OUString();
+}
+
+OUString SAL_CALL MacabDatabaseMetaData::getDatabaseProductName( )
+{
+ return OUString();
+}
+
+OUString SAL_CALL MacabDatabaseMetaData::getProcedureTerm( )
+{
+ return OUString();
+}
+
+OUString SAL_CALL MacabDatabaseMetaData::getSchemaTerm( )
+{
+ return OUString();
+}
+
+sal_Int32 SAL_CALL MacabDatabaseMetaData::getDriverMajorVersion( )
+{
+ return MACAB_DRIVER_VERSION_MAJOR;
+}
+
+sal_Int32 SAL_CALL MacabDatabaseMetaData::getDefaultTransactionIsolation( )
+{
+ return TransactionIsolation::NONE;
+}
+
+sal_Int32 SAL_CALL MacabDatabaseMetaData::getDriverMinorVersion( )
+{
+ return MACAB_DRIVER_VERSION_MINOR;
+}
+
+OUString SAL_CALL MacabDatabaseMetaData::getSQLKeywords( )
+{
+ return OUString();
+}
+
+OUString SAL_CALL MacabDatabaseMetaData::getSearchStringEscape( )
+{
+ return OUString();
+}
+
+OUString SAL_CALL MacabDatabaseMetaData::getStringFunctions( )
+{
+ return OUString();
+}
+
+OUString SAL_CALL MacabDatabaseMetaData::getTimeDateFunctions( )
+{
+ return OUString();
+}
+
+OUString SAL_CALL MacabDatabaseMetaData::getSystemFunctions( )
+{
+ return OUString();
+}
+
+OUString SAL_CALL MacabDatabaseMetaData::getNumericFunctions( )
+{
+ return OUString();
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsExtendedSQLGrammar( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsCoreSQLGrammar( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsMinimumSQLGrammar( )
+{
+ return true;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsFullOuterJoins( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsLimitedOuterJoins( )
+{
+ return false;
+}
+
+sal_Int32 SAL_CALL MacabDatabaseMetaData::getMaxColumnsInGroupBy( )
+{
+ return 0; // 0 means no limit
+}
+
+sal_Int32 SAL_CALL MacabDatabaseMetaData::getMaxColumnsInOrderBy( )
+{
+ return 0; // 0 means no limit
+}
+
+sal_Int32 SAL_CALL MacabDatabaseMetaData::getMaxColumnsInSelect( )
+{
+ return 0; // 0 means no limit
+}
+
+sal_Int32 SAL_CALL MacabDatabaseMetaData::getMaxUserNameLength( )
+{
+ return 0; // 0 means no limit
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsResultSetType( sal_Int32 setType )
+{
+ switch (setType)
+ {
+ case ResultSetType::FORWARD_ONLY:
+ case ResultSetType::SCROLL_INSENSITIVE:
+ return true;
+ }
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsResultSetConcurrency( sal_Int32 setType, sal_Int32 )
+{
+ switch (setType)
+ {
+ case ResultSetType::FORWARD_ONLY:
+ case ResultSetType::SCROLL_INSENSITIVE:
+ return true;
+ }
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::ownUpdatesAreVisible( sal_Int32 )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::ownDeletesAreVisible( sal_Int32 )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::ownInsertsAreVisible( sal_Int32 )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::othersUpdatesAreVisible( sal_Int32 )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::othersDeletesAreVisible( sal_Int32 )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::othersInsertsAreVisible( sal_Int32 )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::updatesAreDetected( sal_Int32 )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::deletesAreDetected( sal_Int32 )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::insertsAreDetected( sal_Int32 )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsBatchUpdates( )
+{
+ return false;
+}
+
+Reference< XConnection > SAL_CALL MacabDatabaseMetaData::getConnection( )
+{
+ return m_xConnection;
+}
+
+Reference< XResultSet > SAL_CALL MacabDatabaseMetaData::getTableTypes( )
+{
+ rtl::Reference<::connectivity::ODatabaseMetaDataResultSet> pResult = new ::connectivity::ODatabaseMetaDataResultSet(ODatabaseMetaDataResultSet::eTableTypes);
+
+ static ODatabaseMetaDataResultSet::ORows aRows = []
+ {
+ static constexpr OUStringLiteral aTable = u"TABLE";
+ ODatabaseMetaDataResultSet::ORows tmp;
+ ODatabaseMetaDataResultSet::ORow aRow(2);
+ aRow[0] = ODatabaseMetaDataResultSet::getEmptyValue();
+ aRow[1] = new ORowSetValueDecorator(OUString(aTable));
+ tmp.push_back(aRow);
+ return tmp;
+ }();
+ pResult->setRows(std::vector(aRows));
+ return pResult;
+}
+
+Reference< XResultSet > SAL_CALL MacabDatabaseMetaData::getTypeInfo( )
+{
+ rtl::Reference<ODatabaseMetaDataResultSet> pResult = new ODatabaseMetaDataResultSet(ODatabaseMetaDataResultSet::eTypeInfo);
+
+ static ODatabaseMetaDataResultSet::ORows aRows = []()
+ {
+ ODatabaseMetaDataResultSet::ORows tmp;
+ ODatabaseMetaDataResultSet::ORow aRow(19);
+
+ // We support four types: char, timestamp, integer, float
+ aRow[0] = ODatabaseMetaDataResultSet::getEmptyValue();
+ aRow[1] = new ORowSetValueDecorator(OUString("CHAR"));
+ aRow[2] = new ORowSetValueDecorator(DataType::CHAR);
+ aRow[3] = new ORowSetValueDecorator(sal_Int32(254));
+ aRow[4] = ODatabaseMetaDataResultSet::getQuoteValue();
+ aRow[5] = ODatabaseMetaDataResultSet::getQuoteValue();
+ aRow[6] = ODatabaseMetaDataResultSet::getEmptyValue();
+ aRow[7] = new ORowSetValueDecorator(sal_Int32(ColumnValue::NULLABLE));
+ aRow[8] = ODatabaseMetaDataResultSet::get1Value();
+ aRow[9] = new ORowSetValueDecorator(sal_Int32(ColumnSearch::CHAR));
+ aRow[10] = ODatabaseMetaDataResultSet::get1Value();
+ aRow[11] = ODatabaseMetaDataResultSet::get0Value();
+ aRow[12] = ODatabaseMetaDataResultSet::get0Value();
+ aRow[13] = ODatabaseMetaDataResultSet::getEmptyValue();
+ aRow[14] = ODatabaseMetaDataResultSet::get0Value();
+ aRow[15] = ODatabaseMetaDataResultSet::get0Value();
+ aRow[16] = ODatabaseMetaDataResultSet::getEmptyValue();
+ aRow[17] = ODatabaseMetaDataResultSet::getEmptyValue();
+ aRow[18] = new ORowSetValueDecorator(sal_Int32(10));
+
+ tmp.push_back(aRow);
+
+ aRow[1] = new ORowSetValueDecorator(OUString("TIMESTAMP"));
+ aRow[2] = new ORowSetValueDecorator(DataType::TIMESTAMP);
+ aRow[3] = new ORowSetValueDecorator(sal_Int32(19));
+ aRow[4] = ODatabaseMetaDataResultSet::getQuoteValue();
+ aRow[5] = ODatabaseMetaDataResultSet::getQuoteValue();
+ tmp.push_back(aRow);
+
+ aRow[1] = new ORowSetValueDecorator(OUString("INTEGER"));
+ aRow[2] = new ORowSetValueDecorator(DataType::INTEGER);
+ aRow[3] = new ORowSetValueDecorator(sal_Int32(20));
+ aRow[15] = new ORowSetValueDecorator(sal_Int32(20));
+ tmp.push_back(aRow);
+
+ aRow[1] = new ORowSetValueDecorator(OUString("FLOAT"));
+ aRow[2] = new ORowSetValueDecorator(DataType::FLOAT);
+ aRow[3] = new ORowSetValueDecorator(sal_Int32(20));
+ aRow[15] = new ORowSetValueDecorator(sal_Int32(15));
+ tmp.push_back(aRow);
+
+ return tmp;
+ }();
+ pResult->setRows(std::vector(aRows));
+ return pResult;
+}
+
+Reference< XResultSet > SAL_CALL MacabDatabaseMetaData::getCatalogs( )
+{
+ return new ODatabaseMetaDataResultSet( ODatabaseMetaDataResultSet::eCatalogs );
+}
+
+Reference< XResultSet > SAL_CALL MacabDatabaseMetaData::getSchemas( )
+{
+ return new ODatabaseMetaDataResultSet( ODatabaseMetaDataResultSet::eSchemas );
+}
+
+Reference< XResultSet > SAL_CALL MacabDatabaseMetaData::getColumnPrivileges(
+ const Any&, const OUString&, const OUString&,
+ const OUString& )
+{
+ return new ODatabaseMetaDataResultSet( ODatabaseMetaDataResultSet::eColumnPrivileges );
+}
+
+Reference< XResultSet > SAL_CALL MacabDatabaseMetaData::getColumns(
+ const Any&,
+ const OUString&,
+ const OUString& tableNamePattern,
+ const OUString& columnNamePattern)
+{
+ rtl::Reference<::connectivity::ODatabaseMetaDataResultSet> pResult = new ::connectivity::ODatabaseMetaDataResultSet(::connectivity::ODatabaseMetaDataResultSet::eColumns);
+ MacabRecords *aRecords;
+ OUString sTableName;
+
+ aRecords = m_xConnection->getAddressBook()->getMacabRecordsMatch(tableNamePattern);
+
+ ODatabaseMetaDataResultSet::ORows aRows;
+ if(aRecords != nullptr)
+ {
+ MacabHeader *aHeader = aRecords->getHeader();
+ sTableName = aRecords->getName();
+
+ ODatabaseMetaDataResultSet::ORow aRow(19);
+
+ aRow[0] = ODatabaseMetaDataResultSet::getEmptyValue();
+ aRow[1] = ODatabaseMetaDataResultSet::getEmptyValue();
+ aRow[2] = ODatabaseMetaDataResultSet::getEmptyValue();
+ aRow[3] = new ORowSetValueDecorator(sTableName);
+ aRow[8] = ODatabaseMetaDataResultSet::getEmptyValue();
+ aRow[9] = ODatabaseMetaDataResultSet::get0Value();
+ aRow[10] = new ORowSetValueDecorator(sal_Int32(10));
+ aRow[11] = ODatabaseMetaDataResultSet::get1Value();
+ aRow[12] = ODatabaseMetaDataResultSet::getEmptyValue();
+ aRow[13] = ODatabaseMetaDataResultSet::getEmptyValue();
+ aRow[14] = ODatabaseMetaDataResultSet::getEmptyValue();
+ aRow[15] = ODatabaseMetaDataResultSet::getEmptyValue();
+ aRow[16] = new ORowSetValueDecorator(sal_Int32(254));
+ aRow[18] = new ORowSetValueDecorator(OUString("YES"));
+
+ sal_Int32 nPosition = 1;
+ OUString sName;
+
+ MacabHeader::iterator aField;
+
+ for ( aField = aHeader->begin();
+ aField != aHeader->end();
+ ++aField, ++nPosition)
+ {
+
+ sName = CFStringToOUString(static_cast<CFStringRef>((*aField)->value));
+ if (match(columnNamePattern, sName, '\0'))
+ {
+ aRow[4] = new ORowSetValueDecorator(sName);
+ aRow[17] = new ORowSetValueDecorator(nPosition);
+ switch((*aField)->type)
+ {
+ case kABStringProperty:
+ aRow[5] = new ORowSetValueDecorator(DataType::CHAR);
+ aRow[6] = new ORowSetValueDecorator(OUString("CHAR"));
+ aRow[7] = new ORowSetValueDecorator(sal_Int32(256));
+ aRows.push_back(aRow);
+ break;
+ case kABDateProperty:
+ aRow[5] = new ORowSetValueDecorator(DataType::TIMESTAMP);
+ aRow[6] = new ORowSetValueDecorator(OUString("TIMESTAMP"));
+ aRows.push_back(aRow);
+ break;
+ case kABIntegerProperty:
+ aRow[5] = new ORowSetValueDecorator(DataType::INTEGER);
+ aRow[6] = new ORowSetValueDecorator(OUString("INTEGER"));
+ aRow[7] = new ORowSetValueDecorator(sal_Int32(20));
+ aRows.push_back(aRow);
+ break;
+ case kABRealProperty:
+ aRow[5] = new ORowSetValueDecorator(DataType::FLOAT);
+ aRow[6] = new ORowSetValueDecorator(OUString("FLOAT"));
+ aRow[7] = new ORowSetValueDecorator(sal_Int32(15));
+ aRows.push_back(aRow);
+ break;
+ default:
+ ;
+ // shouldn't happen -- throw an error...?
+ }
+ }
+ }
+ }
+ pResult->setRows(std::move(aRows));
+ return pResult;
+}
+
+Reference< XResultSet > SAL_CALL MacabDatabaseMetaData::getTables(
+ const Any&,
+ const OUString&,
+ const OUString&,
+ const Sequence< OUString >& types)
+{
+ rtl::Reference<ODatabaseMetaDataResultSet> pResult = new ODatabaseMetaDataResultSet(::connectivity::ODatabaseMetaDataResultSet::eTables);
+
+ // check whether we have tables in the requested types
+ // for the moment, we answer only the "TABLE" table type
+ // when no types are given at all, we return all the tables
+ static constexpr OUString aTable = u"TABLE"_ustr;
+ bool bTableFound = false;
+ const OUString* p = types.getConstArray(),
+ * pEnd = p + types.getLength();
+
+ if (p == pEnd)
+ {
+ bTableFound = true;
+ }
+ else while (p < pEnd)
+ {
+ if (match(*p, aTable, '\0'))
+ {
+ bTableFound = true;
+ break;
+ }
+ p++;
+ }
+ if (!bTableFound)
+ return pResult;
+
+ static ODatabaseMetaDataResultSet::ORows aRows = [&]()
+ {
+ ODatabaseMetaDataResultSet::ORows tmp;
+ ODatabaseMetaDataResultSet::ORow aRow(6);
+
+ MacabRecords *xRecords = m_xConnection->getAddressBook()->getMacabRecords();
+ std::vector<MacabGroup *> xGroups = m_xConnection->getAddressBook()->getMacabGroups();
+ sal_Int32 i, nGroups;
+ nGroups = xGroups.size();
+
+ aRow[0] = ODatabaseMetaDataResultSet::getEmptyValue();
+ aRow[1] = ODatabaseMetaDataResultSet::getEmptyValue();
+ aRow[2] = ODatabaseMetaDataResultSet::getEmptyValue();
+ aRow[3] = new ORowSetValueDecorator(xRecords->getName());
+ aRow[4] = new ORowSetValueDecorator(aTable);
+ aRow[5] = ODatabaseMetaDataResultSet::getEmptyValue();
+ tmp.push_back(aRow);
+
+ for(i = 0; i < nGroups; i++)
+ {
+ aRow[3] = new ORowSetValueDecorator(xGroups[i]->getName());
+ tmp.push_back(aRow);
+ }
+ return tmp;
+ }();
+ pResult->setRows(std::vector(aRows));
+ return pResult;
+}
+
+Reference< XResultSet > SAL_CALL MacabDatabaseMetaData::getProcedureColumns(
+ const Any&, const OUString&,
+ const OUString&, const OUString& )
+{
+ return new ODatabaseMetaDataResultSet( ODatabaseMetaDataResultSet::eProcedureColumns );
+}
+
+Reference< XResultSet > SAL_CALL MacabDatabaseMetaData::getProcedures(
+ const Any&, const OUString&,
+ const OUString& )
+{
+ return new ODatabaseMetaDataResultSet( ODatabaseMetaDataResultSet::eProcedures );
+}
+
+Reference< XResultSet > SAL_CALL MacabDatabaseMetaData::getVersionColumns(
+ const Any&, const OUString&, const OUString& table )
+{
+ rtl::Reference<::connectivity::ODatabaseMetaDataResultSet> pResult = new ::connectivity::ODatabaseMetaDataResultSet(::connectivity::ODatabaseMetaDataResultSet::eVersionColumns);
+
+ ODatabaseMetaDataResultSet::ORows aRows;
+
+ if (m_xConnection->getAddressBook()->getMacabRecords(table) != nullptr)
+ {
+ ODatabaseMetaDataResultSet::ORow aRow( 9 );
+
+ OUString sName = CFStringToOUString(kABModificationDateProperty);
+
+ aRow[0] = ODatabaseMetaDataResultSet::getEmptyValue();
+ aRow[1] = ODatabaseMetaDataResultSet::getEmptyValue();
+ aRow[2] = new ORowSetValueDecorator(sName);
+ aRow[3] = new ORowSetValueDecorator(DataType::TIMESTAMP);
+ aRow[4] = new ORowSetValueDecorator(OUString("TIMESTAMP"));
+
+ aRow[5] = ODatabaseMetaDataResultSet::getEmptyValue();
+ aRow[6] = ODatabaseMetaDataResultSet::getEmptyValue();
+ aRow[7] = ODatabaseMetaDataResultSet::getEmptyValue();
+ aRow[8] = ODatabaseMetaDataResultSet::getEmptyValue();
+
+ aRows.push_back(aRow);
+ }
+ pResult->setRows(std::move(aRows));
+ return pResult;
+}
+
+Reference< XResultSet > SAL_CALL MacabDatabaseMetaData::getExportedKeys(
+ const Any&, const OUString&, const OUString& )
+{
+ return new ODatabaseMetaDataResultSet( ODatabaseMetaDataResultSet::eExportedKeys );
+}
+
+Reference< XResultSet > SAL_CALL MacabDatabaseMetaData::getImportedKeys(
+ const Any&, const OUString&, const OUString& )
+{
+ return new ODatabaseMetaDataResultSet( ODatabaseMetaDataResultSet::eImportedKeys );
+}
+
+Reference< XResultSet > SAL_CALL MacabDatabaseMetaData::getPrimaryKeys(
+ const Any&, const OUString&, const OUString& )
+{
+ return new ODatabaseMetaDataResultSet( ODatabaseMetaDataResultSet::ePrimaryKeys );
+}
+
+Reference< XResultSet > SAL_CALL MacabDatabaseMetaData::getIndexInfo(
+ const Any&, const OUString&, const OUString&,
+ sal_Bool, sal_Bool )
+{
+ return new ODatabaseMetaDataResultSet( ODatabaseMetaDataResultSet::eIndexInfo );
+}
+
+Reference< XResultSet > SAL_CALL MacabDatabaseMetaData::getBestRowIdentifier(
+ const Any&, const OUString&, const OUString&, sal_Int32,
+ sal_Bool )
+{
+ return new ODatabaseMetaDataResultSet( ODatabaseMetaDataResultSet::eBestRowIdentifier );
+}
+
+Reference< XResultSet > SAL_CALL MacabDatabaseMetaData::getTablePrivileges(
+ const Any&, const OUString&, const OUString& )
+{
+ return new ODatabaseMetaDataResultSet( ODatabaseMetaDataResultSet::eTablePrivileges );
+}
+
+Reference< XResultSet > SAL_CALL MacabDatabaseMetaData::getCrossReference(
+ const Any&, const OUString&,
+ const OUString&, const Any&,
+ const OUString&, const OUString& )
+{
+ return new ODatabaseMetaDataResultSet( ODatabaseMetaDataResultSet::eCrossReference );
+}
+
+Reference< XResultSet > SAL_CALL MacabDatabaseMetaData::getUDTs( const Any&, const OUString&, const OUString&, const Sequence< sal_Int32 >& )
+{
+ OSL_FAIL("Not implemented yet!");
+ throw SQLException();
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/macab/MacabDatabaseMetaData.hxx b/connectivity/source/drivers/macab/MacabDatabaseMetaData.hxx
new file mode 100644
index 0000000000..662be1c018
--- /dev/null
+++ b/connectivity/source/drivers/macab/MacabDatabaseMetaData.hxx
@@ -0,0 +1,195 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "MacabConnection.hxx"
+#include <com/sun/star/sdbc/XDatabaseMetaData.hpp>
+#include <cppuhelper/implbase.hxx>
+
+namespace connectivity::macab
+{
+
+ class MacabDatabaseMetaData : public ::cppu::WeakImplHelper< css::sdbc::XDatabaseMetaData>
+ {
+ rtl::Reference< MacabConnection > m_xConnection;
+ bool m_bUseCatalog;
+
+ public:
+
+ MacabConnection* getOwnConnection() const { return m_xConnection.get(); }
+
+ explicit MacabDatabaseMetaData(MacabConnection* _pCon);
+ virtual ~MacabDatabaseMetaData() override;
+
+ // this interface is really BIG
+ // XDatabaseMetaData
+ virtual sal_Bool SAL_CALL allProceduresAreCallable( ) override;
+ virtual sal_Bool SAL_CALL allTablesAreSelectable( ) override;
+ virtual OUString SAL_CALL getURL( ) override;
+ virtual OUString SAL_CALL getUserName( ) override;
+ virtual sal_Bool SAL_CALL isReadOnly( ) override;
+ virtual sal_Bool SAL_CALL nullsAreSortedHigh( ) override;
+ virtual sal_Bool SAL_CALL nullsAreSortedLow( ) override;
+ virtual sal_Bool SAL_CALL nullsAreSortedAtStart( ) override;
+ virtual sal_Bool SAL_CALL nullsAreSortedAtEnd( ) override;
+ virtual OUString SAL_CALL getDatabaseProductName( ) override;
+ virtual OUString SAL_CALL getDatabaseProductVersion( ) override;
+ virtual OUString SAL_CALL getDriverName( ) override;
+ virtual OUString SAL_CALL getDriverVersion( ) override;
+ virtual sal_Int32 SAL_CALL getDriverMajorVersion( ) override;
+ virtual sal_Int32 SAL_CALL getDriverMinorVersion( ) override;
+ virtual sal_Bool SAL_CALL usesLocalFiles( ) override;
+ virtual sal_Bool SAL_CALL usesLocalFilePerTable( ) override;
+ virtual sal_Bool SAL_CALL supportsMixedCaseIdentifiers( ) override;
+ virtual sal_Bool SAL_CALL storesUpperCaseIdentifiers( ) override;
+ virtual sal_Bool SAL_CALL storesLowerCaseIdentifiers( ) override;
+ virtual sal_Bool SAL_CALL storesMixedCaseIdentifiers( ) override;
+ virtual sal_Bool SAL_CALL supportsMixedCaseQuotedIdentifiers( ) override;
+ virtual sal_Bool SAL_CALL storesUpperCaseQuotedIdentifiers( ) override;
+ virtual sal_Bool SAL_CALL storesLowerCaseQuotedIdentifiers( ) override;
+ virtual sal_Bool SAL_CALL storesMixedCaseQuotedIdentifiers( ) override;
+ virtual OUString SAL_CALL getIdentifierQuoteString( ) override;
+ virtual OUString SAL_CALL getSQLKeywords( ) override;
+ virtual OUString SAL_CALL getNumericFunctions( ) override;
+ virtual OUString SAL_CALL getStringFunctions( ) override;
+ virtual OUString SAL_CALL getSystemFunctions( ) override;
+ virtual OUString SAL_CALL getTimeDateFunctions( ) override;
+ virtual OUString SAL_CALL getSearchStringEscape( ) override;
+ virtual OUString SAL_CALL getExtraNameCharacters( ) override;
+ virtual sal_Bool SAL_CALL supportsAlterTableWithAddColumn( ) override;
+ virtual sal_Bool SAL_CALL supportsAlterTableWithDropColumn( ) override;
+ virtual sal_Bool SAL_CALL supportsColumnAliasing( ) override;
+ virtual sal_Bool SAL_CALL nullPlusNonNullIsNull( ) override;
+ virtual sal_Bool SAL_CALL supportsTypeConversion( ) override;
+ virtual sal_Bool SAL_CALL supportsConvert( sal_Int32 fromType, sal_Int32 toType ) override;
+ virtual sal_Bool SAL_CALL supportsTableCorrelationNames( ) override;
+ virtual sal_Bool SAL_CALL supportsDifferentTableCorrelationNames( ) override;
+ virtual sal_Bool SAL_CALL supportsExpressionsInOrderBy( ) override;
+ virtual sal_Bool SAL_CALL supportsOrderByUnrelated( ) override;
+ virtual sal_Bool SAL_CALL supportsGroupBy( ) override;
+ virtual sal_Bool SAL_CALL supportsGroupByUnrelated( ) override;
+ virtual sal_Bool SAL_CALL supportsGroupByBeyondSelect( ) override;
+ virtual sal_Bool SAL_CALL supportsLikeEscapeClause( ) override;
+ virtual sal_Bool SAL_CALL supportsMultipleResultSets( ) override;
+ virtual sal_Bool SAL_CALL supportsMultipleTransactions( ) override;
+ virtual sal_Bool SAL_CALL supportsNonNullableColumns( ) override;
+ virtual sal_Bool SAL_CALL supportsMinimumSQLGrammar( ) override;
+ virtual sal_Bool SAL_CALL supportsCoreSQLGrammar( ) override;
+ virtual sal_Bool SAL_CALL supportsExtendedSQLGrammar( ) override;
+ virtual sal_Bool SAL_CALL supportsANSI92EntryLevelSQL( ) override;
+ virtual sal_Bool SAL_CALL supportsANSI92IntermediateSQL( ) override;
+ virtual sal_Bool SAL_CALL supportsANSI92FullSQL( ) override;
+ virtual sal_Bool SAL_CALL supportsIntegrityEnhancementFacility( ) override;
+ virtual sal_Bool SAL_CALL supportsOuterJoins( ) override;
+ virtual sal_Bool SAL_CALL supportsFullOuterJoins( ) override;
+ virtual sal_Bool SAL_CALL supportsLimitedOuterJoins( ) override;
+ virtual OUString SAL_CALL getSchemaTerm( ) override;
+ virtual OUString SAL_CALL getProcedureTerm( ) override;
+ virtual OUString SAL_CALL getCatalogTerm( ) override;
+ virtual sal_Bool SAL_CALL isCatalogAtStart( ) override;
+ virtual OUString SAL_CALL getCatalogSeparator( ) override;
+ virtual sal_Bool SAL_CALL supportsSchemasInDataManipulation( ) override;
+ virtual sal_Bool SAL_CALL supportsSchemasInProcedureCalls( ) override;
+ virtual sal_Bool SAL_CALL supportsSchemasInTableDefinitions( ) override;
+ virtual sal_Bool SAL_CALL supportsSchemasInIndexDefinitions( ) override;
+ virtual sal_Bool SAL_CALL supportsSchemasInPrivilegeDefinitions( ) override;
+ virtual sal_Bool SAL_CALL supportsCatalogsInDataManipulation( ) override;
+ virtual sal_Bool SAL_CALL supportsCatalogsInProcedureCalls( ) override;
+ virtual sal_Bool SAL_CALL supportsCatalogsInTableDefinitions( ) override;
+ virtual sal_Bool SAL_CALL supportsCatalogsInIndexDefinitions( ) override;
+ virtual sal_Bool SAL_CALL supportsCatalogsInPrivilegeDefinitions( ) override;
+ virtual sal_Bool SAL_CALL supportsPositionedDelete( ) override;
+ virtual sal_Bool SAL_CALL supportsPositionedUpdate( ) override;
+ virtual sal_Bool SAL_CALL supportsSelectForUpdate( ) override;
+ virtual sal_Bool SAL_CALL supportsStoredProcedures( ) override;
+ virtual sal_Bool SAL_CALL supportsSubqueriesInComparisons( ) override;
+ virtual sal_Bool SAL_CALL supportsSubqueriesInExists( ) override;
+ virtual sal_Bool SAL_CALL supportsSubqueriesInIns( ) override;
+ virtual sal_Bool SAL_CALL supportsSubqueriesInQuantifieds( ) override;
+ virtual sal_Bool SAL_CALL supportsCorrelatedSubqueries( ) override;
+ virtual sal_Bool SAL_CALL supportsUnion( ) override;
+ virtual sal_Bool SAL_CALL supportsUnionAll( ) override;
+ virtual sal_Bool SAL_CALL supportsOpenCursorsAcrossCommit( ) override;
+ virtual sal_Bool SAL_CALL supportsOpenCursorsAcrossRollback( ) override;
+ virtual sal_Bool SAL_CALL supportsOpenStatementsAcrossCommit( ) override;
+ virtual sal_Bool SAL_CALL supportsOpenStatementsAcrossRollback( ) override;
+ virtual sal_Int32 SAL_CALL getMaxBinaryLiteralLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxCharLiteralLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxColumnNameLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxColumnsInGroupBy( ) override;
+ virtual sal_Int32 SAL_CALL getMaxColumnsInIndex( ) override;
+ virtual sal_Int32 SAL_CALL getMaxColumnsInOrderBy( ) override;
+ virtual sal_Int32 SAL_CALL getMaxColumnsInSelect( ) override;
+ virtual sal_Int32 SAL_CALL getMaxColumnsInTable( ) override;
+ virtual sal_Int32 SAL_CALL getMaxConnections( ) override;
+ virtual sal_Int32 SAL_CALL getMaxCursorNameLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxIndexLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxSchemaNameLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxProcedureNameLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxCatalogNameLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxRowSize( ) override;
+ virtual sal_Bool SAL_CALL doesMaxRowSizeIncludeBlobs( ) override;
+ virtual sal_Int32 SAL_CALL getMaxStatementLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxStatements( ) override;
+ virtual sal_Int32 SAL_CALL getMaxTableNameLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxTablesInSelect( ) override;
+ virtual sal_Int32 SAL_CALL getMaxUserNameLength( ) override;
+ virtual sal_Int32 SAL_CALL getDefaultTransactionIsolation( ) override;
+ virtual sal_Bool SAL_CALL supportsTransactions( ) override;
+ virtual sal_Bool SAL_CALL supportsTransactionIsolationLevel( sal_Int32 level ) override;
+ virtual sal_Bool SAL_CALL supportsDataDefinitionAndDataManipulationTransactions( ) override;
+ virtual sal_Bool SAL_CALL supportsDataManipulationTransactionsOnly( ) override;
+ virtual sal_Bool SAL_CALL dataDefinitionCausesTransactionCommit( ) override;
+ virtual sal_Bool SAL_CALL dataDefinitionIgnoredInTransactions( ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getProcedures( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& procedureNamePattern ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getProcedureColumns( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& procedureNamePattern, const OUString& columnNamePattern ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getTables( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& tableNamePattern, const css::uno::Sequence< OUString >& types ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getSchemas( ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getCatalogs( ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getTableTypes( ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getColumns( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& tableNamePattern, const OUString& columnNamePattern ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getColumnPrivileges( const css::uno::Any& catalog, const OUString& schema, const OUString& table, const OUString& columnNamePattern ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getTablePrivileges( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& tableNamePattern ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getBestRowIdentifier( const css::uno::Any& catalog, const OUString& schema, const OUString& table, sal_Int32 scope, sal_Bool nullable ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getVersionColumns( const css::uno::Any& catalog, const OUString& schema, const OUString& table ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getPrimaryKeys( const css::uno::Any& catalog, const OUString& schema, const OUString& table ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getImportedKeys( const css::uno::Any& catalog, const OUString& schema, const OUString& table ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getExportedKeys( const css::uno::Any& catalog, const OUString& schema, const OUString& table ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getCrossReference( const css::uno::Any& primaryCatalog, const OUString& primarySchema, const OUString& primaryTable, const css::uno::Any& foreignCatalog, const OUString& foreignSchema, const OUString& foreignTable ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getTypeInfo( ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getIndexInfo( const css::uno::Any& catalog, const OUString& schema, const OUString& table, sal_Bool unique, sal_Bool approximate ) override;
+ virtual sal_Bool SAL_CALL supportsResultSetType( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL supportsResultSetConcurrency( sal_Int32 setType, sal_Int32 concurrency ) override;
+ virtual sal_Bool SAL_CALL ownUpdatesAreVisible( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL ownDeletesAreVisible( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL ownInsertsAreVisible( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL othersUpdatesAreVisible( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL othersDeletesAreVisible( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL othersInsertsAreVisible( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL updatesAreDetected( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL deletesAreDetected( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL insertsAreDetected( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL supportsBatchUpdates( ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getUDTs( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& typeNamePattern, const css::uno::Sequence< sal_Int32 >& types ) override;
+ virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL getConnection( ) override;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/macab/MacabDriver.cxx b/connectivity/source/drivers/macab/MacabDriver.cxx
new file mode 100644
index 0000000000..9c68e48f12
--- /dev/null
+++ b/connectivity/source/drivers/macab/MacabDriver.cxx
@@ -0,0 +1,310 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include "MacabDriver.hxx"
+#include "MacabConnection.hxx"
+
+#include <com/sun/star/sdb/SQLContext.hpp>
+#include <com/sun/star/lang/NullPointerException.hpp>
+#include <com/sun/star/frame/Desktop.hpp>
+#include <sal/log.hxx>
+#include <comphelper/diagnose_ex.hxx>
+#include <strings.hrc>
+#include <cppuhelper/supportsservice.hxx>
+
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::sdbc;
+using namespace com::sun::star::sdb;
+using namespace com::sun::star::frame;
+using namespace connectivity::macab;
+
+namespace {
+
+/** throws a generic SQL exception with SQLState S1000 and error code 0
+ */
+void throwGenericSQLException( const OUString& _rMessage )
+{
+ SQLException aError;
+ aError.Message = _rMessage;
+ aError.SQLState = "S1000";
+ aError.ErrorCode = 0;
+ throw aError;
+}
+
+/** throws an SQLException saying that no Mac OS installation was found
+ */
+void throwNoMacOSException()
+{
+ ::connectivity::SharedResources aResources;
+ const OUString sError( aResources.getResourceString(
+ STR_NO_MAC_OS_FOUND
+ ) );
+ throwGenericSQLException( sError );
+}
+
+
+}
+
+// = MacabImplModule
+
+
+MacabImplModule::MacabImplModule()
+ :m_bAttemptedLoadModule(false)
+ ,m_hConnectorModule(nullptr)
+ ,m_pConnectionFactoryFunc(nullptr)
+{
+}
+
+
+bool MacabImplModule::isMacOSPresent()
+{
+ return impl_loadModule();
+}
+
+
+namespace
+{
+ template< typename FUNCTION >
+ void lcl_getFunctionFromModuleOrUnload( oslModule& _rModule, const char* _pAsciiSymbolName, FUNCTION& _rFunction )
+ {
+ _rFunction = nullptr;
+ if ( _rModule )
+ {
+
+ const OUString sSymbolName = OUString::createFromAscii( _pAsciiSymbolName );
+ _rFunction = reinterpret_cast<FUNCTION>( osl_getSymbol( _rModule, sSymbolName.pData ) );
+
+ if ( !_rFunction )
+ { // did not find the symbol
+ SAL_WARN( "connectivity.macab", "lcl_getFunctionFromModuleOrUnload: could not find the symbol " << _pAsciiSymbolName );
+ osl_unloadModule( _rModule );
+ _rModule = nullptr;
+ }
+ }
+ }
+}
+
+
+extern "C" { static void thisModule() {} }
+
+bool MacabImplModule::impl_loadModule()
+{
+ if ( m_bAttemptedLoadModule )
+ return ( m_hConnectorModule != nullptr );
+ m_bAttemptedLoadModule = true;
+
+ OSL_ENSURE( !m_hConnectorModule && !m_pConnectionFactoryFunc,
+ "MacabImplModule::impl_loadModule: inconsistence: inconsistency (never attempted load before, but some values already set)!");
+
+ constexpr OUString sModuleName( u"" SAL_MODULENAME( "macabdrv1" ) ""_ustr );
+ m_hConnectorModule = osl_loadModuleRelative( &thisModule, sModuleName.pData, SAL_LOADMODULE_NOW ); // LAZY! #i61335#
+ OSL_ENSURE( m_hConnectorModule, "MacabImplModule::impl_loadModule: could not load the implementation library!" );
+ if ( !m_hConnectorModule )
+ return false;
+
+ lcl_getFunctionFromModuleOrUnload( m_hConnectorModule, "createMacabConnection", m_pConnectionFactoryFunc );
+
+ if ( !m_hConnectorModule )
+ // one of the symbols did not exist
+ throw RuntimeException();
+
+ return true;
+}
+
+
+void MacabImplModule::impl_unloadModule()
+{
+ OSL_PRECOND( m_hConnectorModule != nullptr, "MacabImplModule::impl_unloadModule: no module!" );
+
+ osl_unloadModule( m_hConnectorModule );
+ m_hConnectorModule = nullptr;
+
+ m_pConnectionFactoryFunc = nullptr;
+
+ m_bAttemptedLoadModule = false;
+}
+
+
+void MacabImplModule::init()
+{
+ if ( !impl_loadModule() )
+ throwNoMacOSException();
+
+}
+
+
+MacabConnection* MacabImplModule::createConnection( MacabDriver* _pDriver ) const
+{
+ OSL_PRECOND( m_hConnectorModule, "MacabImplModule::createConnection: not initialized!" );
+
+ void* pUntypedConnection = (*m_pConnectionFactoryFunc)( _pDriver );
+ if ( !pUntypedConnection )
+ throw RuntimeException();
+
+ return static_cast< MacabConnection* >( pUntypedConnection );
+}
+
+
+void MacabImplModule::shutdown()
+{
+ if ( !m_hConnectorModule )
+ return;
+
+ impl_unloadModule();
+}
+
+
+// = MacabDriver
+
+MacabDriver::MacabDriver(
+ const Reference< css::uno::XComponentContext >& _rxContext)
+ : MacabDriver_BASE(m_aMutex),
+ m_xContext(_rxContext),
+ m_aImplModule()
+{
+ if ( !m_xContext.is() )
+ throw NullPointerException();
+
+ osl_atomic_increment( &m_refCount );
+ try
+ {
+ Reference< XDesktop2 > xDesktop = Desktop::create( m_xContext );
+ xDesktop->addTerminateListener( this );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("connectivity.macab");
+ }
+ osl_atomic_decrement( &m_refCount );
+}
+
+void MacabDriver::disposing()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+
+ // when driver will be destroyed so all our connections have to be destroyed as well
+ for (auto& rxConnection : m_xConnections)
+ {
+ Reference< XComponent > xComp(rxConnection.get(), UNO_QUERY);
+ if (xComp.is())
+ xComp->dispose();
+ }
+ m_xConnections.clear();
+
+ WeakComponentImplHelperBase::disposing();
+}
+
+OUString SAL_CALL MacabDriver::getImplementationName( )
+{
+ return "com.sun.star.comp.sdbc.macab.Driver";
+}
+
+sal_Bool SAL_CALL MacabDriver::supportsService( const OUString& _rServiceName )
+{
+ return cppu::supportsService(this, _rServiceName);
+}
+
+Sequence< OUString > SAL_CALL MacabDriver::getSupportedServiceNames( )
+{
+ // which service is supported
+ // for more information @see com.sun.star.sdbc.Driver
+ return { "com.sun.star.sdbc.Driver" };
+}
+
+Reference< XConnection > SAL_CALL MacabDriver::connect( const OUString& url, const Sequence< PropertyValue >& info )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+
+ m_aImplModule.init();
+
+ // create a new connection with the given properties and append it to our vector
+ MacabConnection* pConnection = m_aImplModule.createConnection( this );
+ SAL_WARN_IF( !pConnection, "connectivity.macab", "MacabDriver::connect: no connection has been created by the factory!" );
+
+ // by definition, the factory function returned an object which was acquired once
+ Reference< XConnection > xConnection = pConnection;
+ pConnection->release();
+
+ // late constructor call which can throw exception and allows a correct dtor call when so
+ pConnection->construct( url, info );
+
+ // remember it
+ m_xConnections.push_back( WeakReferenceHelper( *pConnection ) );
+
+ return xConnection;
+}
+
+sal_Bool SAL_CALL MacabDriver::acceptsURL( const OUString& url )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+
+ if ( !m_aImplModule.isMacOSPresent() )
+ return false;
+
+ // here we have to look whether we support this URL format
+ return url == "sdbc:address:macab";
+}
+
+Sequence< DriverPropertyInfo > SAL_CALL MacabDriver::getPropertyInfo( const OUString&, const Sequence< PropertyValue >& )
+{
+ // if you have something special to say, return it here :-)
+ return Sequence< DriverPropertyInfo >();
+}
+
+sal_Int32 SAL_CALL MacabDriver::getMajorVersion( )
+{
+ return MACAB_DRIVER_VERSION_MAJOR;
+}
+
+sal_Int32 SAL_CALL MacabDriver::getMinorVersion( )
+{
+ return MACAB_DRIVER_VERSION_MINOR;
+}
+
+void SAL_CALL MacabDriver::queryTermination( const EventObject& )
+{
+ // nothing to do, nothing to veto
+}
+
+void SAL_CALL MacabDriver::notifyTermination( const EventObject& )
+{
+ m_aImplModule.shutdown();
+}
+
+void SAL_CALL MacabDriver::disposing( const EventObject& )
+{
+ // not interested in (this is the disposing of the desktop, if any)
+}
+
+OUString MacabDriver::impl_getConfigurationSettingsPath()
+{
+ return "/org.openoffice.Office.DataAccess/DriverSettings/com.sun.star.comp.sdbc.macab.Driver";
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+connectivity_MacabDriver_get_implementation(
+ css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new MacabDriver(context));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/macab/MacabDriver.hxx b/connectivity/source/drivers/macab/MacabDriver.hxx
new file mode 100644
index 0000000000..d18f5e9827
--- /dev/null
+++ b/connectivity/source/drivers/macab/MacabDriver.hxx
@@ -0,0 +1,161 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/sdbc/XDriver.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/frame/XTerminateListener.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <cppuhelper/compbase.hxx>
+#include <osl/module.h>
+
+// the address book driver's version
+#define MACAB_DRIVER_VERSION "0.1"
+#define MACAB_DRIVER_VERSION_MAJOR 0
+#define MACAB_DRIVER_VERSION_MINOR 1
+
+namespace connectivity::macab
+{
+ class MacabConnection;
+ class MacabDriver;
+
+ typedef void* (SAL_CALL * ConnectionFactoryFunction)( void* _pDriver );
+
+ typedef std::vector< css::uno::WeakReferenceHelper > OWeakRefArray;
+
+
+ // = MacabImplModule
+
+ class MacabImplModule
+ {
+ private:
+ /// Did we already attempt to load the module and to retrieve the symbols?
+ bool m_bAttemptedLoadModule;
+ oslModule m_hConnectorModule;
+ ConnectionFactoryFunction m_pConnectionFactoryFunc;
+
+ public:
+ MacabImplModule();
+
+ /** determines whether there is a mac OS present in the environment
+ */
+ bool isMacOSPresent();
+
+ /** initializes the implementation module.
+
+ @throws css::uno::RuntimeException
+ if the module could be loaded, but required symbols are missing
+ @throws css::sdbc::SQLException
+ if no Mac OS was found at all
+ */
+ void init();
+
+ /** shuts down the impl module
+ */
+ void shutdown();
+
+ /** creates a new connection
+ @precond
+ <member>init</member> has been called before
+ @throws css::uno::RuntimeException
+ if no connection object could be created (which is a severe error, normally impossible)
+ */
+ MacabConnection* createConnection( MacabDriver* _pDriver ) const;
+
+ private:
+ /** loads the implementation module and retrieves the needed symbols
+
+ Save against being called multiple times.
+
+ @return <TRUE/> if the module could be loaded successfully.
+
+ @throws css::uno::RuntimeException
+ if the module could be loaded, but required symbols are missing
+ */
+ bool impl_loadModule();
+
+ /** unloads the implementation module, and resets all function pointers to <NULL/>
+ @precond m_hConnectorModule is not <NULL/>
+ */
+ void impl_unloadModule();
+ };
+
+
+ // = MacabDriver
+
+ typedef ::cppu::WeakComponentImplHelper< css::sdbc::XDriver,
+ css::lang::XServiceInfo,
+ css::frame::XTerminateListener > MacabDriver_BASE;
+ class MacabDriver : public MacabDriver_BASE
+ {
+ protected:
+ ::osl::Mutex m_aMutex; // mutex is need to control member access
+ OWeakRefArray m_xConnections; // vector containing a list of all the
+ // MacabConnection objects for this Driver
+ css::uno::Reference< css::uno::XComponentContext >
+ m_xContext; // the multi-service factory
+ MacabImplModule m_aImplModule;
+
+ public:
+ css::uno::Reference< css::uno::XComponentContext > const &
+ getComponentContext() const { return m_xContext; }
+
+ /** returns the path of our configuration settings
+ */
+ static OUString impl_getConfigurationSettingsPath();
+
+ explicit MacabDriver(const css::uno::Reference< css::uno::XComponentContext >& _rxContext);
+ protected:
+
+ // OComponentHelper
+ virtual void SAL_CALL disposing() override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+ // XDriver
+ virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL connect( const OUString& url, const css::uno::Sequence< css::beans::PropertyValue >& info ) override;
+ virtual sal_Bool SAL_CALL acceptsURL( const OUString& url ) override;
+ virtual css::uno::Sequence< css::sdbc::DriverPropertyInfo > SAL_CALL getPropertyInfo( const OUString& url, const css::uno::Sequence< css::beans::PropertyValue >& info ) override;
+ virtual sal_Int32 SAL_CALL getMajorVersion() override;
+ virtual sal_Int32 SAL_CALL getMinorVersion() override;
+
+ // XTerminateListener
+ virtual void SAL_CALL queryTermination( const css::lang::EventObject& Event ) override;
+ virtual void SAL_CALL notifyTermination( const css::lang::EventObject& Event ) override;
+
+ // XEventListener
+ virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override;
+
+ private:
+ /** shuts down the library which contains the real implementations
+
+ This method is safe against being called multiple times
+
+ @precond our mutex is locked
+ */
+ void impl_shutdownImplementationModule();
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/macab/MacabGroup.cxx b/connectivity/source/drivers/macab/MacabGroup.cxx
new file mode 100644
index 0000000000..a57f1729fc
--- /dev/null
+++ b/connectivity/source/drivers/macab/MacabGroup.cxx
@@ -0,0 +1,93 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include "MacabGroup.hxx"
+#include "MacabRecords.hxx"
+#include "macabutilities.hxx"
+
+using namespace connectivity::macab;
+
+
+/* A MacabGroup is basically a MacabRecords with a different constructor.
+ * It only exists as a different entity for clarification purposes (a group
+ * is its own entity in the macOS Address Book) and because its
+ * construction is so unique (it is based on an already existent
+ * MacabRecords of the entire address book).
+ */
+MacabGroup::MacabGroup(const ABAddressBookRef _addressBook, const MacabRecords *_allRecords, const ABGroupRef _xGroup)
+ : MacabRecords(_addressBook)
+{
+ sal_Int32 i, j, nAllRecordsSize;
+ CFArrayRef xGroupMembers = ABGroupCopyArrayOfAllMembers(_xGroup);
+ ABPersonRef xPerson;
+ CFStringRef sGroupMemberUID;
+ bool bFound;
+ macabfield *xRecordField;
+
+ // Set the group's name (stored in MacabRecords as m_sName)
+ CFStringRef sGroupName;
+ sGroupName = static_cast<CFStringRef>(ABRecordCopyValue(_xGroup, kABGroupNameProperty));
+ m_sName = CFStringToOUString(sGroupName);
+ CFRelease(sGroupName);
+
+ // The _group's_ records (remember MacabGroup inherits from MacabRecords)
+ recordsSize = static_cast<sal_Int32>(CFArrayGetCount(xGroupMembers));
+ records = new MacabRecord *[recordsSize];
+ setHeader(_allRecords->getHeader());
+
+ /* Go through each record in the group and try to find that record's UID
+ * in the MacabRecords that was passed in. If it is found, add that
+ * record to the group. Otherwise, report an error. (All records should
+ * exist in the MacabRecords that was passed in.)
+ */
+ nAllRecordsSize = _allRecords->size();
+ for(i = 0; i < recordsSize; i++)
+ {
+ xPerson = static_cast<ABPersonRef>(const_cast<void *>(CFArrayGetValueAtIndex(xGroupMembers,i)));
+ if(xPerson != nullptr)
+ {
+ sGroupMemberUID = static_cast<CFStringRef>(ABRecordCopyValue(xPerson, kABUIDProperty));
+ if(sGroupMemberUID != nullptr)
+ {
+ bFound = false;
+ for(j = 0; j < nAllRecordsSize; j++)
+ {
+ xRecordField = _allRecords->getField(j,CFStringToOUString(kABUIDProperty));
+ if(xRecordField != nullptr && xRecordField->value != nullptr)
+ {
+ if(CFEqual(xRecordField->value, sGroupMemberUID))
+ {
+ /* Found the matching UID! Insert into the group... */
+ insertRecord(_allRecords->getRecord(j));
+ bFound = true;
+ break;
+ }
+ }
+ }
+ OSL_ENSURE(bFound, "MacabGroup::MacabGroup : Could not find group member based on UID!");
+ CFRelease(sGroupMemberUID);
+ }
+ }
+ }
+
+ CFRelease(xGroupMembers);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/macab/MacabGroup.hxx b/connectivity/source/drivers/macab/MacabGroup.hxx
new file mode 100644
index 0000000000..ddcd47b464
--- /dev/null
+++ b/connectivity/source/drivers/macab/MacabGroup.hxx
@@ -0,0 +1,38 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "MacabRecords.hxx"
+
+#include <premac.h>
+#include <Carbon/Carbon.h>
+#include <AddressBook/ABAddressBookC.h>
+#include <postmac.h>
+
+
+namespace connectivity::macab
+{
+ class MacabGroup: public MacabRecords {
+ public:
+ MacabGroup(const ABAddressBookRef _addressBook, const MacabRecords *_allRecords, const ABGroupRef _xGroup);
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/macab/MacabHeader.cxx b/connectivity/source/drivers/macab/MacabHeader.cxx
new file mode 100644
index 0000000000..da270dd05a
--- /dev/null
+++ b/connectivity/source/drivers/macab/MacabHeader.cxx
@@ -0,0 +1,330 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include "MacabHeader.hxx"
+#include "MacabRecord.hxx"
+#include "macabutilities.hxx"
+
+#include <math.h>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <connectivity/dbconversion.hxx>
+
+using namespace connectivity::macab;
+using namespace com::sun::star::sdbc;
+using namespace com::sun::star::util;
+using namespace ::dbtools;
+
+
+MacabHeader::MacabHeader(const sal_Int32 _size, macabfield **_fields)
+{
+ sal_Int32 i;
+ size = _size;
+ fields = std::make_unique<macabfield *[]>(size);
+ for(i = 0; i < size; i++)
+ {
+ if(_fields[i] == nullptr)
+ {
+ fields[i] = nullptr;
+ }
+ else
+ {
+ /* The constructor duplicates the macabfields it gets because they
+ * are either deleted later or used for other purposes.
+ */
+ fields[i] = new macabfield;
+ fields[i]->type = _fields[i]->type;
+ fields[i]->value = _fields[i]->value;
+ if (fields[i]->value)
+ CFRetain(fields[i]->value);
+ }
+ }
+
+}
+
+
+MacabHeader::MacabHeader()
+{
+ size = 0;
+ fields = nullptr;
+}
+
+
+MacabHeader::~MacabHeader()
+{
+}
+
+
+void MacabHeader::operator+= (const MacabHeader *r)
+{
+ /* Add one MacabHeader to another. Anything not already in the header is
+ * added to the end of it.
+ */
+ sal_Int32 rSize = r->getSize();
+ if(rSize != 0) // If the new header does actually have fields
+ {
+ /* If our header is currently empty, just copy all of the fields from
+ * the new header to this one.
+ */
+ if(size == 0)
+ {
+ sal_Int32 i;
+ size = rSize;
+ fields = std::make_unique<macabfield *[]>(size);
+ for(i = 0; i < size; i++)
+ {
+ fields[i] = r->copy(i);
+ }
+ }
+
+ /* Otherwise, only add the duplicates. We do this with a two-pass
+ * approach. First, find out how many fields to add, then reallocate
+ * the size of the fields array and add the old ones at the end.
+ * (More precisely, we create a _new_ fields array with the new length
+ * allocated to it, then get all of the fields from the current
+ * fields array to it, then copy the non-duplicates from the new
+ * header to the end.)
+ */
+ else
+ {
+ sal_Int32 i;
+ sal_Int32 numToAdd = 0, numAdded = 0;
+ macabfield **newFields;
+ for( i = 0; i < rSize; i++)
+ {
+ if(!contains(r->get(i)))
+ {
+ numToAdd++;
+ }
+ }
+
+ newFields = new macabfield *[size+numToAdd];
+ for(i = 0; i < size; i++)
+ {
+ newFields[i] = copy(i);
+ }
+
+ for( i = 0; i < rSize; i++)
+ {
+ if(!contains(r->get(i)))
+ {
+ newFields[size+numAdded] = r->copy(i);
+ numAdded++;
+ if(numAdded == numToAdd)
+ break;
+ }
+ }
+
+ releaseFields();
+ size += numAdded;
+ fields.reset(newFields);
+ }
+ }
+}
+
+
+OUString MacabHeader::getString(const sal_Int32 i) const
+{
+ OUString nRet;
+
+ if(i < size)
+ {
+ if(fields[i] == nullptr || fields[i]->value == nullptr || CFGetTypeID(fields[i]->value) != CFStringGetTypeID())
+ return OUString();
+ try
+ {
+ nRet = CFStringToOUString(static_cast<CFStringRef>(fields[i]->value));
+ }
+ catch(...){ }
+ }
+
+ return nRet;
+}
+
+
+void MacabHeader::sortRecord()
+{
+ sortRecord(0,size);
+}
+
+
+macabfield **MacabHeader::sortRecord(const sal_Int32 _start, const sal_Int32 _length)
+{
+ /* Sort using mergesort. Because it uses mergesort, it is recursive and
+ * not in place (so it creates a new array at every step of the
+ * recursion), so if you prefer to use a different sort, please feel
+ * free to implement it.
+ */
+ macabfield** sorted = new macabfield *[_length];
+ if(_length <= 2)
+ {
+ if(_length == 2)
+ {
+ if(compareFields(fields[_start], fields[_start+1]) > 0)
+ {
+ sorted[0] = get(_start+1);
+ sorted[1] = get(_start);
+ }
+ else
+ {
+ sorted[0] = get(_start);
+ sorted[1] = get(_start+1);
+ }
+ }
+ else if(_length == 1)
+ {
+ sorted[0] = get(_start);
+ }
+ }
+ else
+ {
+ sal_Int32 halfLength = floor(_length/2);
+ sal_Int32 fp = 0, lp = 0;
+ sal_Int32 i;
+ macabfield **firstHalf = sortRecord(_start, halfLength);
+ macabfield **lastHalf = sortRecord(_start+halfLength, _length-halfLength);
+
+ for(i = 0; i < _length; i++)
+ {
+ if(compareFields(firstHalf[fp],lastHalf[lp]) < 0)
+ {
+ sorted[i] = firstHalf[fp++];
+ if(fp == halfLength)
+ {
+ for( i++; i < _length; i++)
+ {
+ sorted[i] = lastHalf[lp++];
+ }
+ break;
+ }
+ }
+ else
+ {
+ sorted[i] = lastHalf[lp++];
+ if(lp == _length - halfLength)
+ {
+ for( i++; i < _length; i++)
+ {
+ sorted[i] = firstHalf[fp++];
+ }
+ break;
+ }
+ }
+ }
+ if(_length == size)
+ {
+ fields.reset(sorted);
+ }
+ delete firstHalf;
+ delete lastHalf;
+ }
+ return sorted;
+}
+
+sal_Int32 MacabHeader::compareFields(const macabfield *_field1, const macabfield *_field2)
+{
+ /* Comparing two fields in a MacabHeader is different than comparing two
+ * fields in a MacabRecord. It starts in the same way (if one of the two
+ * fields is NULL, it belongs after the other, so it is considered
+ * "greater"). But, then, all headers are CFStrings, no matter what
+ * type they claim to be (since they actually hold the expected type for
+ * the records with that header). That being said, all we have to do is
+ * the built-in CFStringCompare.
+ */
+ if(_field1 == _field2)
+ return 0;
+ if(_field1 == nullptr)
+ return 1;
+ if(_field2 == nullptr)
+ return -1;
+
+ CFComparisonResult result = CFStringCompare(
+ static_cast<CFStringRef>(_field1->value),
+ static_cast<CFStringRef>(_field2->value),
+ 0); // 0 = no options (like ignore case)
+
+ return static_cast<sal_Int32>(result);
+}
+
+
+sal_Int32 MacabHeader::getColumnNumber(std::u16string_view s) const
+{
+ sal_Int32 i;
+ for(i = 0; i < size; i++)
+ {
+ if(getString(i) == s)
+ break;
+ }
+
+ if(i == size)
+ i = -1;
+
+ return i;
+}
+
+
+MacabHeader *MacabHeader::begin()
+{
+ return this;
+}
+
+
+MacabHeader::iterator::iterator ()
+{
+}
+
+
+MacabHeader::iterator& MacabHeader::iterator::operator= (MacabHeader *_record)
+{
+ id = 0;
+ record = _record;
+ return *this;
+}
+
+
+void MacabHeader::iterator::operator++ ()
+{
+ id++;
+}
+
+
+bool MacabHeader::iterator::operator!= (const sal_Int32 i) const
+{
+ return(id != i);
+}
+
+
+bool MacabHeader::iterator::operator== (const sal_Int32 i) const
+{
+ return(id == i);
+}
+
+
+macabfield *MacabHeader::iterator::operator* () const
+{
+ return record->get(id);
+}
+
+
+sal_Int32 MacabHeader::end() const
+{
+ return size;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/macab/MacabHeader.hxx b/connectivity/source/drivers/macab/MacabHeader.hxx
new file mode 100644
index 0000000000..24b3fc7b0b
--- /dev/null
+++ b/connectivity/source/drivers/macab/MacabHeader.hxx
@@ -0,0 +1,61 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <string_view>
+
+#include "MacabRecord.hxx"
+
+namespace connectivity::macab
+{
+ class MacabHeader: public MacabRecord{
+ protected:
+ macabfield **sortRecord(sal_Int32 _start, sal_Int32 _length);
+ public:
+ MacabHeader();
+ MacabHeader(const sal_Int32 _size, macabfield **_fields);
+ virtual ~MacabHeader() override;
+ void operator+= (const MacabHeader *r);
+ OUString getString(const sal_Int32 i) const;
+ void sortRecord();
+ sal_Int32 getColumnNumber(std::u16string_view s) const;
+
+ static sal_Int32 compareFields(const macabfield *_field1, const macabfield *_field2);
+
+ MacabHeader *begin();
+ sal_Int32 end() const;
+ class iterator{
+ protected:
+ sal_Int32 id;
+ MacabHeader *record;
+ public:
+ iterator& operator= (MacabHeader *_record);
+ iterator();
+ void operator++ ();
+ bool operator!= (const sal_Int32 i) const;
+ bool operator== (const sal_Int32 i) const;
+ macabfield *operator* () const;
+ };
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/macab/MacabPreparedStatement.cxx b/connectivity/source/drivers/macab/MacabPreparedStatement.cxx
new file mode 100644
index 0000000000..6d72345b60
--- /dev/null
+++ b/connectivity/source/drivers/macab/MacabPreparedStatement.cxx
@@ -0,0 +1,343 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include "MacabPreparedStatement.hxx"
+#include "MacabAddressBook.hxx"
+#include <propertyids.hxx>
+#include <connectivity/dbexception.hxx>
+#include <connectivity/dbtools.hxx>
+#include <strings.hrc>
+#include <resource/sharedresources.hxx>
+
+using namespace connectivity::macab;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::sdbc;
+using namespace com::sun::star::util;
+
+IMPLEMENT_SERVICE_INFO(MacabPreparedStatement, "com.sun.star.sdbc.drivers.MacabPreparedStatement", "com.sun.star.sdbc.PreparedStatement");
+
+void MacabPreparedStatement::checkAndResizeParameters(sal_Int32 nParams)
+{
+ if ( !m_aParameterRow.is() )
+ m_aParameterRow = new OValueVector();
+
+ if (nParams < 1)
+ ::dbtools::throwInvalidIndexException(*this);
+
+ if (nParams >= static_cast<sal_Int32>(m_aParameterRow->size()))
+ m_aParameterRow->resize(nParams);
+}
+
+void MacabPreparedStatement::setMacabFields() const
+{
+ ::rtl::Reference<connectivity::OSQLColumns> xColumns; // selected columns
+
+ xColumns = m_aSQLIterator.getSelectColumns();
+ if (!xColumns.is())
+ {
+ ::connectivity::SharedResources aResources;
+ const OUString sError( aResources.getResourceString(
+ STR_INVALID_COLUMN_SELECTION
+ ) );
+ ::dbtools::throwGenericSQLException(sError,nullptr);
+ }
+ m_xMetaData->setMacabFields(xColumns);
+}
+
+void MacabPreparedStatement::resetParameters() const
+{
+ m_nParameterIndex = 0;
+}
+
+void MacabPreparedStatement::getNextParameter(OUString &rParameter) const
+{
+ if (m_nParameterIndex >= static_cast<sal_Int32>(m_aParameterRow->size()))
+ {
+ ::connectivity::SharedResources aResources;
+ const OUString sError( aResources.getResourceString(
+ STR_INVALID_PARA_COUNT
+ ) );
+ ::dbtools::throwGenericSQLException(sError,*const_cast<MacabPreparedStatement *>(this));
+ }
+
+ rParameter = (*m_aParameterRow)[m_nParameterIndex].getString();
+
+ m_nParameterIndex++;
+}
+
+MacabPreparedStatement::MacabPreparedStatement(
+ MacabConnection* _pConnection,
+ const OUString& sql)
+ : MacabPreparedStatement_BASE(_pConnection),
+ m_sSqlStatement(sql),
+ m_bPrepared(false),
+ m_nParameterIndex(0),
+ m_aParameterRow()
+{
+
+}
+
+MacabPreparedStatement::~MacabPreparedStatement()
+{
+}
+
+void MacabPreparedStatement::disposing()
+{
+ MacabPreparedStatement_BASE::disposing();
+
+ if (m_aParameterRow.is())
+ {
+ m_aParameterRow->clear();
+ m_aParameterRow = nullptr;
+ }
+}
+
+Reference< XResultSetMetaData > SAL_CALL MacabPreparedStatement::getMetaData()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabCommonStatement_BASE::rBHelper.bDisposed);
+
+ if (!m_xMetaData.is())
+ {
+ const OSQLTables& xTabs = m_aSQLIterator.getTables();
+ OUString sTableName = MacabAddressBook::getDefaultTableName();
+
+ if(! xTabs.empty() )
+ {
+
+ // can only deal with one table at a time
+ if(xTabs.size() == 1 && !m_aSQLIterator.hasErrors() )
+ sTableName = xTabs.begin()->first;
+
+ }
+ m_xMetaData = new MacabResultSetMetaData(getOwnConnection(),sTableName);
+ setMacabFields();
+ }
+ Reference< XResultSetMetaData > xMetaData = m_xMetaData;
+ return xMetaData;
+}
+
+void SAL_CALL MacabPreparedStatement::close()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabCommonStatement_BASE::rBHelper.bDisposed);
+
+ // Reset last warning message
+ try {
+ clearWarnings ();
+ MacabCommonStatement::close();
+ }
+ catch (SQLException &) {
+ // If we get an error, ignore
+ }
+
+ // Remove this Statement object from the Connection object's
+ // list
+}
+
+sal_Bool SAL_CALL MacabPreparedStatement::execute()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabCommonStatement_BASE::rBHelper.bDisposed);
+
+ Reference< XResultSet> xRS = MacabCommonStatement::executeQuery(m_sSqlStatement);
+
+ return xRS.is();
+}
+
+sal_Int32 SAL_CALL MacabPreparedStatement::executeUpdate()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabCommonStatement_BASE::rBHelper.bDisposed);
+
+ // same as in statement with the difference that this statement also can contain parameter
+ return 0;
+}
+
+Reference< XConnection > SAL_CALL MacabPreparedStatement::getConnection()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabCommonStatement_BASE::rBHelper.bDisposed);
+
+ return m_pConnection;
+}
+
+Reference< XResultSet > SAL_CALL MacabPreparedStatement::executeQuery()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabCommonStatement_BASE::rBHelper.bDisposed);
+
+ Reference< XResultSet > rs = MacabCommonStatement::executeQuery(m_sSqlStatement);
+
+ return rs;
+}
+
+void SAL_CALL MacabPreparedStatement::setNull(sal_Int32 parameterIndex, sal_Int32)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabCommonStatement_BASE::rBHelper.bDisposed);
+
+ checkAndResizeParameters(parameterIndex);
+
+ (*m_aParameterRow)[parameterIndex - 1].setNull();
+}
+
+void SAL_CALL MacabPreparedStatement::setObjectNull(sal_Int32, sal_Int32, const OUString&)
+{
+ ::dbtools::throwFunctionNotSupportedSQLException("setObjectNull", nullptr);
+}
+
+void SAL_CALL MacabPreparedStatement::setBoolean(sal_Int32, sal_Bool)
+{
+ ::dbtools::throwFunctionNotSupportedSQLException("setBoolean", nullptr);
+}
+
+void SAL_CALL MacabPreparedStatement::setByte(sal_Int32, sal_Int8)
+{
+ ::dbtools::throwFunctionNotSupportedSQLException("setByte", nullptr);
+}
+
+void SAL_CALL MacabPreparedStatement::setShort(sal_Int32, sal_Int16)
+{
+ ::dbtools::throwFunctionNotSupportedSQLException("setShort", nullptr);
+}
+
+void SAL_CALL MacabPreparedStatement::setInt(sal_Int32, sal_Int32)
+{
+ ::dbtools::throwFunctionNotSupportedSQLException("setInt", nullptr);
+}
+
+void SAL_CALL MacabPreparedStatement::setLong(sal_Int32, sal_Int64)
+{
+ ::dbtools::throwFunctionNotSupportedSQLException("setLong", nullptr);
+}
+
+void SAL_CALL MacabPreparedStatement::setFloat(sal_Int32, float)
+{
+ ::dbtools::throwFunctionNotSupportedSQLException("setFloat", nullptr);
+}
+
+void SAL_CALL MacabPreparedStatement::setDouble(sal_Int32, double)
+{
+ ::dbtools::throwFunctionNotSupportedSQLException("setDouble", nullptr);
+}
+
+void SAL_CALL MacabPreparedStatement::setString(sal_Int32 parameterIndex, const OUString &x)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabCommonStatement_BASE::rBHelper.bDisposed);
+
+ checkAndResizeParameters(parameterIndex);
+
+ (*m_aParameterRow)[parameterIndex - 1] = x;
+}
+
+void SAL_CALL MacabPreparedStatement::setBytes(sal_Int32, const Sequence< sal_Int8 >&)
+{
+ ::dbtools::throwFunctionNotSupportedSQLException("setBytes", nullptr);
+}
+
+void SAL_CALL MacabPreparedStatement::setDate(sal_Int32, const Date&)
+{
+ ::dbtools::throwFunctionNotSupportedSQLException("setDate", nullptr);
+}
+
+void SAL_CALL MacabPreparedStatement::setTime(sal_Int32, const css::util::Time&)
+{
+
+ ::dbtools::throwFunctionNotSupportedSQLException("setTime", nullptr);
+}
+
+void SAL_CALL MacabPreparedStatement::setTimestamp(sal_Int32, const DateTime&)
+{
+ ::dbtools::throwFunctionNotSupportedSQLException("setTimestamp", nullptr);
+}
+
+void SAL_CALL MacabPreparedStatement::setBinaryStream(sal_Int32, const Reference< css::io::XInputStream >&, sal_Int32)
+{
+ ::dbtools::throwFunctionNotSupportedSQLException("setBinaryStream", nullptr);
+}
+
+void SAL_CALL MacabPreparedStatement::setCharacterStream(sal_Int32, const Reference< css::io::XInputStream >&, sal_Int32)
+{
+ ::dbtools::throwFunctionNotSupportedSQLException("setCharacterStream", nullptr);
+}
+
+void SAL_CALL MacabPreparedStatement::setObject(sal_Int32 parameterIndex, const Any& x)
+{
+ if(!::dbtools::implSetObject(this,parameterIndex,x))
+ {
+ const OUString sError( m_pConnection->getResources().getResourceStringWithSubstitution(
+ STR_UNKNOWN_PARA_TYPE,
+ "$position$", OUString::number(parameterIndex)
+ ) );
+ ::dbtools::throwGenericSQLException(sError,*this);
+ }
+}
+
+void SAL_CALL MacabPreparedStatement::setObjectWithInfo(sal_Int32, const Any&, sal_Int32, sal_Int32)
+{
+ ::dbtools::throwFunctionNotSupportedSQLException("setObjectWithInfo", nullptr);
+}
+
+void SAL_CALL MacabPreparedStatement::setRef(sal_Int32, const Reference< XRef >&)
+{
+ ::dbtools::throwFunctionNotSupportedSQLException("setRef", nullptr);
+}
+
+void SAL_CALL MacabPreparedStatement::setBlob(sal_Int32, const Reference< XBlob >&)
+{
+ ::dbtools::throwFunctionNotSupportedSQLException("setBlob", nullptr);
+}
+
+void SAL_CALL MacabPreparedStatement::setClob(sal_Int32, const Reference< XClob >&)
+{
+ ::dbtools::throwFunctionNotSupportedSQLException("setClob", nullptr);
+}
+
+void SAL_CALL MacabPreparedStatement::setArray(sal_Int32, const Reference< XArray >&)
+{
+ ::dbtools::throwFunctionNotSupportedSQLException("setArray", nullptr);
+}
+
+void SAL_CALL MacabPreparedStatement::clearParameters()
+{
+ ::dbtools::throwFunctionNotSupportedSQLException("clearParameters", nullptr);
+}
+
+void MacabPreparedStatement::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,const Any& rValue)
+{
+ switch (nHandle)
+ {
+ case PROPERTY_ID_RESULTSETCONCURRENCY:
+ break;
+ case PROPERTY_ID_RESULTSETTYPE:
+ break;
+ case PROPERTY_ID_FETCHDIRECTION:
+ break;
+ case PROPERTY_ID_USEBOOKMARKS:
+ break;
+ default:
+ MacabCommonStatement::setFastPropertyValue_NoBroadcast(nHandle,rValue);
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/macab/MacabPreparedStatement.hxx b/connectivity/source/drivers/macab/MacabPreparedStatement.hxx
new file mode 100644
index 0000000000..6e649bf647
--- /dev/null
+++ b/connectivity/source/drivers/macab/MacabPreparedStatement.hxx
@@ -0,0 +1,111 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "MacabStatement.hxx"
+#include "MacabResultSetMetaData.hxx"
+#include <connectivity/FValue.hxx>
+#include <com/sun/star/sdbc/XParameters.hpp>
+#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
+#include <cppuhelper/implbase.hxx>
+
+namespace connectivity::macab
+{
+ typedef ::cppu::ImplInheritanceHelper< MacabCommonStatement,
+ css::sdbc::XPreparedStatement,
+ css::sdbc::XParameters,
+ css::sdbc::XResultSetMetaDataSupplier,
+ css::lang::XServiceInfo> MacabPreparedStatement_BASE;
+
+ class MacabPreparedStatement : public MacabPreparedStatement_BASE
+ {
+ protected:
+ OUString m_sSqlStatement;
+ ::rtl::Reference< MacabResultSetMetaData >
+ m_xMetaData;
+ bool m_bPrepared;
+ mutable sal_Int32 m_nParameterIndex;
+ OValueRow m_aParameterRow;
+
+ /// @throws css::sdbc::SQLException
+ void checkAndResizeParameters(sal_Int32 nParams);
+ /// @throws css::sdbc::SQLException
+ void setMacabFields() const;
+
+ protected:
+ virtual void SAL_CALL setFastPropertyValue_NoBroadcast(
+ sal_Int32 nHandle,
+ const css::uno::Any& rValue) override;
+
+ virtual void resetParameters() const override;
+ virtual void getNextParameter(OUString &rParameter) const override;
+ virtual ~MacabPreparedStatement() override;
+
+ public:
+ DECLARE_SERVICE_INFO();
+ MacabPreparedStatement(MacabConnection* _pConnection, const OUString& sql);
+
+ // OComponentHelper
+ virtual void SAL_CALL disposing() override;
+
+ // XPreparedStatement
+ using MacabCommonStatement::executeQuery;
+ using MacabCommonStatement::executeUpdate;
+ using MacabCommonStatement::execute;
+
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL executeQuery( ) override;
+ virtual sal_Int32 SAL_CALL executeUpdate( ) override;
+ virtual sal_Bool SAL_CALL execute( ) override;
+ virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL getConnection( ) override;
+
+ // XParameters
+ virtual void SAL_CALL setNull( sal_Int32 parameterIndex, sal_Int32 sqlType ) override;
+ virtual void SAL_CALL setObjectNull( sal_Int32 parameterIndex, sal_Int32 sqlType, const OUString& typeName ) override;
+ virtual void SAL_CALL setBoolean( sal_Int32 parameterIndex, sal_Bool x ) override;
+ virtual void SAL_CALL setByte( sal_Int32 parameterIndex, sal_Int8 x ) override;
+ virtual void SAL_CALL setShort( sal_Int32 parameterIndex, sal_Int16 x ) override;
+ virtual void SAL_CALL setInt( sal_Int32 parameterIndex, sal_Int32 x ) override;
+ virtual void SAL_CALL setLong( sal_Int32 parameterIndex, sal_Int64 x ) override;
+ virtual void SAL_CALL setFloat( sal_Int32 parameterIndex, float x ) override;
+ virtual void SAL_CALL setDouble( sal_Int32 parameterIndex, double x ) override;
+ virtual void SAL_CALL setString( sal_Int32 parameterIndex, const OUString& x ) override;
+ virtual void SAL_CALL setBytes( sal_Int32 parameterIndex, const css::uno::Sequence< sal_Int8 >& x ) override;
+ virtual void SAL_CALL setDate( sal_Int32 parameterIndex, const css::util::Date& x ) override;
+ virtual void SAL_CALL setTime( sal_Int32 parameterIndex, const css::util::Time& x ) override;
+ virtual void SAL_CALL setTimestamp( sal_Int32 parameterIndex, const css::util::DateTime& x ) override;
+ virtual void SAL_CALL setBinaryStream( sal_Int32 parameterIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override;
+ virtual void SAL_CALL setCharacterStream( sal_Int32 parameterIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override;
+ virtual void SAL_CALL setObject( sal_Int32 parameterIndex, const css::uno::Any& x ) override;
+ virtual void SAL_CALL setObjectWithInfo( sal_Int32 parameterIndex, const css::uno::Any& x, sal_Int32 targetSqlType, sal_Int32 scale ) override;
+ virtual void SAL_CALL setRef( sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XRef >& x ) override;
+ virtual void SAL_CALL setBlob( sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XBlob >& x ) override;
+ virtual void SAL_CALL setClob( sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XClob >& x ) override;
+ virtual void SAL_CALL setArray( sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XArray >& x ) override;
+ virtual void SAL_CALL clearParameters( ) override;
+
+ // XCloseable
+ virtual void SAL_CALL close( ) override;
+
+ // XResultSetMetaDataSupplier
+ virtual css::uno::Reference< css::sdbc::XResultSetMetaData > SAL_CALL getMetaData( ) override;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/macab/MacabRecord.cxx b/connectivity/source/drivers/macab/MacabRecord.cxx
new file mode 100644
index 0000000000..3072e1eaa2
--- /dev/null
+++ b/connectivity/source/drivers/macab/MacabRecord.cxx
@@ -0,0 +1,336 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include "MacabRecord.hxx"
+#include "macabutilities.hxx"
+#include <com/sun/star/util/DateTime.hpp>
+
+#include <premac.h>
+#include <Carbon/Carbon.h>
+#include <AddressBook/ABAddressBookC.h>
+#include <postmac.h>
+#include <connectivity/dbconversion.hxx>
+
+using namespace connectivity::macab;
+using namespace com::sun::star::util;
+using namespace ::dbtools;
+
+
+MacabRecord::MacabRecord() : size(0)
+{
+}
+
+
+MacabRecord::MacabRecord(const sal_Int32 _size)
+ : size(_size),
+ fields(std::make_unique<macabfield *[]>(size))
+{
+ sal_Int32 i;
+ for(i = 0; i < size; i++)
+ fields[i] = nullptr;
+}
+
+
+MacabRecord::~MacabRecord()
+{
+ if(size > 0)
+ {
+ releaseFields();
+ int i;
+ for(i = 0; i < size; i++)
+ {
+ delete fields[i];
+ fields[i] = nullptr;
+ }
+ }
+}
+
+
+void MacabRecord::insertAtColumn (CFTypeRef _value, ABPropertyType _type, const sal_Int32 _column)
+{
+ if(_column < size)
+ {
+ if(fields[_column] == nullptr)
+ fields[_column] = new macabfield;
+
+ fields[_column]->value = _value;
+ if (fields[_column]->value)
+ CFRetain(fields[_column]->value);
+ fields[_column]->type = _type;
+ }
+}
+
+
+bool MacabRecord::contains (const macabfield *_field) const
+{
+ if(_field == nullptr)
+ return false;
+ else
+ return contains(_field->value);
+}
+
+
+bool MacabRecord::contains (const CFTypeRef _value) const
+{
+ sal_Int32 i;
+ for(i = 0; i < size; i++)
+ {
+ if(fields[i] != nullptr)
+ {
+ if(CFEqual(fields[i]->value, _value))
+ {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+
+sal_Int32 MacabRecord::getSize() const
+{
+ return size;
+}
+
+
+macabfield *MacabRecord::copy(const sal_Int32 i) const
+{
+ /* Note: copy(i) creates a new macabfield identical to that at
+ * location i, whereas get(i) returns a pointer to the macabfield
+ * at location i.
+ */
+ if(i < size)
+ {
+ macabfield *_copy = new macabfield;
+ _copy->type = fields[i]->type;
+ _copy->value = fields[i]->value;
+ if (_copy->value)
+ CFRetain(_copy->value);
+ return _copy;
+ }
+
+ return nullptr;
+}
+
+
+macabfield *MacabRecord::get(const sal_Int32 i) const
+{
+ /* Note: copy(i) creates a new macabfield identical to that at
+ * location i, whereas get(i) returns a pointer to the macabfield
+ * at location i.
+ */
+ if(i < size)
+ {
+ return fields[i];
+ }
+
+ return nullptr;
+}
+
+
+void MacabRecord::releaseFields()
+{
+ /* This method is, at the moment, only used in MacabHeader.cxx, but
+ * the idea is simple: if you are not destroying this object but want
+ * to clear it of its macabfields, you should release each field's
+ * value.
+ */
+ sal_Int32 i;
+ for(i = 0; i < size; i++)
+ CFRelease(fields[i]->value);
+}
+
+
+sal_Int32 MacabRecord::compareFields(const macabfield *_field1, const macabfield *_field2)
+{
+
+ /* When comparing records, if either field is NULL (and the other is
+ * not), that field is considered "greater than" the other, so that it
+ * shows up later in the list when fields are ordered.
+ */
+ if(_field1 == _field2)
+ return 0;
+ if(_field1 == nullptr)
+ return 1;
+ if(_field2 == nullptr)
+ return -1;
+
+ /* If they aren't the same type, for now, return the one with
+ * the smaller type ID... I don't know of a better way to compare
+ * two different data types.
+ */
+ if(_field1->type != _field2->type)
+ return(_field1->type - _field2->type);
+
+ CFComparisonResult result;
+
+ /* Carbon has a unique compare function for each data type: */
+ switch(_field1->type)
+ {
+ case kABStringProperty:
+ result = CFStringCompare(
+ static_cast<CFStringRef>(_field1->value),
+ static_cast<CFStringRef>(_field2->value),
+ kCFCompareLocalized); // Specifies that the comparison should take into account differences related to locale, such as the thousands separator character.
+ break;
+
+ case kABDateProperty:
+ result = CFDateCompare(
+ static_cast<CFDateRef>(_field1->value),
+ static_cast<CFDateRef>(_field2->value),
+ nullptr); // NULL = unused variable
+ break;
+
+ case kABIntegerProperty:
+ case kABRealProperty:
+ result = CFNumberCompare(
+ static_cast<CFNumberRef>(_field1->value),
+ static_cast<CFNumberRef>(_field2->value),
+ nullptr); // NULL = unused variable
+ break;
+
+ default:
+ result = kCFCompareEqualTo; // can't compare
+ }
+
+ return static_cast<sal_Int32>(result);
+}
+
+
+/* Create a macabfield out of an OUString and type. Together with the
+ * method fieldToString() (below), it is possible to switch conveniently
+ * between an OUString and a macabfield (for use when creating and handling
+ * SQL statement).
+ */
+macabfield *MacabRecord::createMacabField(const OUString& _newFieldString, const ABPropertyType _abType)
+{
+ macabfield *newField = nullptr;
+ switch(_abType)
+ {
+ case kABStringProperty:
+ newField = new macabfield;
+ newField->value = OUStringToCFString(_newFieldString);
+ newField->type = _abType;
+ break;
+ case kABDateProperty:
+ {
+ DateTime aDateTime = DBTypeConversion::toDateTime(_newFieldString);
+
+ // bad format...
+ if(aDateTime.Year == 0 && aDateTime.Month == 0 && aDateTime.Day == 0)
+ {
+ }
+ else
+ {
+ double nTime = DBTypeConversion::toDouble(aDateTime, DBTypeConversion::getStandardDate());
+ nTime -= kCFAbsoluteTimeIntervalSince1970;
+ newField = new macabfield;
+ newField->value = CFDateCreate(nullptr, static_cast<CFAbsoluteTime>(nTime));
+ newField->type = _abType;
+ }
+ }
+ break;
+ case kABIntegerProperty:
+ try
+ {
+ sal_Int64 nVal = _newFieldString.toInt64();
+
+ newField = new macabfield;
+ newField->value = CFNumberCreate(nullptr,kCFNumberLongType, &nVal);
+ newField->type = _abType;
+ }
+ // bad format...
+ catch(...)
+ {
+ }
+ break;
+ case kABRealProperty:
+ try
+ {
+ double nVal = _newFieldString.toDouble();
+
+ newField = new macabfield;
+ newField->value = CFNumberCreate(nullptr,kCFNumberDoubleType, &nVal);
+ newField->type = _abType;
+ }
+ // bad format...
+ catch(...)
+ {
+ }
+ break;
+ default:
+ ;
+ }
+ return newField;
+}
+
+
+/* Create an OUString out of a macabfield. Together with the method
+ * createMacabField() (above), it is possible to switch conveniently
+ * between an OUString and a macabfield (for use when creating and handling
+ * SQL statement).
+ */
+OUString MacabRecord::fieldToString(const macabfield *_aField)
+{
+ if(_aField == nullptr)
+ return OUString();
+
+ OUString fieldString;
+
+ switch(_aField->type)
+ {
+ case kABStringProperty:
+ fieldString = CFStringToOUString(static_cast<CFStringRef>(_aField->value));
+ break;
+ case kABDateProperty:
+ {
+ DateTime aTime = CFDateToDateTime(static_cast<CFDateRef>(_aField->value));
+ fieldString = DBTypeConversion::toDateTimeString(aTime);
+ }
+ break;
+ case kABIntegerProperty:
+ {
+ CFNumberType numberType = CFNumberGetType( static_cast<CFNumberRef>(_aField->value) );
+ sal_Int64 nVal;
+ // Should we check for the wrong type here, e.g., a float?
+ bool m_bSuccess = !CFNumberGetValue(static_cast<CFNumberRef>(_aField->value), numberType, &nVal);
+ if(m_bSuccess)
+ fieldString = OUString::number(nVal);
+ }
+ break;
+ case kABRealProperty:
+ {
+ CFNumberType numberType = CFNumberGetType( static_cast<CFNumberRef>(_aField->value) );
+ double nVal;
+ // Should we check for the wrong type here, e.g., an int?
+ bool m_bSuccess = !CFNumberGetValue(static_cast<CFNumberRef>(_aField->value), numberType, &nVal);
+ if(m_bSuccess)
+ fieldString = OUString::number(nVal);
+ }
+ break;
+ default:
+ ;
+ }
+ return fieldString;
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/macab/MacabRecord.hxx b/connectivity/source/drivers/macab/MacabRecord.hxx
new file mode 100644
index 0000000000..5184eefc8a
--- /dev/null
+++ b/connectivity/source/drivers/macab/MacabRecord.hxx
@@ -0,0 +1,71 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <memory>
+
+#include <sal/types.h>
+#include <osl/diagnose.h>
+#include <rtl/ustring.hxx>
+
+#include <premac.h>
+#include <Carbon/Carbon.h>
+#include <AddressBook/ABAddressBookC.h>
+#include <postmac.h>
+
+namespace connectivity::macab
+{
+ /* a MacabRecord is at root a list of macabfields (which is just
+ * something to hold both a CFTypeRef (a CoreFoundation object) and
+ * its Address Book type.
+ */
+ struct macabfield
+ {
+ CFTypeRef value;
+ ABPropertyType type;
+ };
+
+ class MacabRecord{
+ protected:
+ sal_Int32 size;
+ std::unique_ptr<macabfield *[]> fields;
+ protected:
+ void releaseFields();
+ public:
+ MacabRecord();
+ explicit MacabRecord(const sal_Int32 _size);
+ virtual ~MacabRecord();
+ void insertAtColumn (CFTypeRef _value, ABPropertyType _type, const sal_Int32 _column);
+ bool contains(const macabfield *_field) const;
+ bool contains(const CFTypeRef _value) const;
+ sal_Int32 getSize() const;
+ macabfield *copy(const sal_Int32 i) const;
+ macabfield *get(const sal_Int32 i) const;
+
+ static sal_Int32 compareFields(const macabfield *_field1, const macabfield *_field2);
+ static macabfield *createMacabField(const OUString& _newFieldString, const ABPropertyType _abtype);
+ static OUString fieldToString(const macabfield *_aField);
+
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/macab/MacabRecords.cxx b/connectivity/source/drivers/macab/MacabRecords.cxx
new file mode 100644
index 0000000000..07d462425e
--- /dev/null
+++ b/connectivity/source/drivers/macab/MacabRecords.cxx
@@ -0,0 +1,1160 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include "MacabRecords.hxx"
+#include "MacabRecord.hxx"
+#include "MacabHeader.hxx"
+#include "macabutilities.hxx"
+
+#include <premac.h>
+#include <Carbon/Carbon.h>
+#include <AddressBook/ABAddressBookC.h>
+#include <postmac.h>
+#include <com/sun/star/util/DateTime.hpp>
+
+using namespace connectivity::macab;
+using namespace com::sun::star::util;
+
+namespace {
+
+void manageDuplicateHeaders(macabfield **_headerNames, const sal_Int32 _length)
+{
+ /* If we have two cases of, say, phone: home, this makes it:
+ * phone: home (1)
+ * phone: home (2)
+ */
+ sal_Int32 i, j;
+ sal_Int32 count;
+ for(i = _length-1; i >= 0; i--)
+ {
+ count = 1;
+ for( j = i-1; j >= 0; j--)
+ {
+ if(CFEqual(_headerNames[i]->value, _headerNames[j]->value))
+ {
+ count++;
+ }
+ }
+
+ // duplicate!
+ if(count != 1)
+ {
+ // There is probably a better way to do this...
+ OUString newName = CFStringToOUString(static_cast<CFStringRef>(_headerNames[i]->value));
+ CFRelease(_headerNames[i]->value);
+ newName += " (" + OUString::number(count) + ")";
+ _headerNames[i]->value = OUStringToCFString(newName);
+ }
+ }
+}
+
+}
+
+MacabRecords::MacabRecords(const ABAddressBookRef _addressBook, MacabHeader *_header, MacabRecord **_records, sal_Int32 _numRecords)
+ : recordsSize(_numRecords), currentRecord(_numRecords), recordType(kABPersonRecordType),
+ header(_header), records(_records), addressBook(_addressBook)
+{
+ /* Variables constructed... */
+ bootstrap_CF_types();
+ bootstrap_requiredProperties();
+}
+
+
+/* Creates a MacabRecords from another: copies the length, name, and
+ * address book of the original, but the header or the records themselves.
+ * The idea is that the only reason to copy a MacabRecords is to create
+ * a filtered version of it, which can have the same length (to avoid
+ * resizing) and will work from the same base addressbook, but might have
+ * entirely different values and even (possibly in the future) a different
+ * header.
+ */
+MacabRecords::MacabRecords(const MacabRecords *_copy)
+ : recordsSize(_copy->recordsSize), currentRecord(0), recordType(kABPersonRecordType),
+ header(nullptr), records(new MacabRecord *[recordsSize]), addressBook(_copy->addressBook),
+ m_sName(_copy->m_sName)
+{
+ /* Variables constructed... */
+ bootstrap_CF_types();
+ bootstrap_requiredProperties();
+}
+
+
+MacabRecords::MacabRecords(const ABAddressBookRef _addressBook)
+ : recordsSize(0), currentRecord(0), recordType(kABPersonRecordType),
+ header(nullptr), records(nullptr), addressBook(_addressBook)
+{
+ /* Variables constructed... */
+ bootstrap_CF_types();
+ bootstrap_requiredProperties();
+}
+
+
+void MacabRecords::initialize()
+{
+
+ /* Make sure everything is NULL before initializing. (We usually just
+ * initialize after we use the constructor that takes only a
+ * MacabAddressBook, so these variables will most likely already be
+ * NULL.
+ */
+ if(records != nullptr)
+ {
+ sal_Int32 i;
+
+ for(i = 0; i < recordsSize; i++)
+ delete records[i];
+
+ delete [] records;
+ }
+
+ if(header != nullptr)
+ delete header;
+
+ /* We can handle both default record Address Book record types in
+ * this method, though only kABPersonRecordType is ever used.
+ */
+ CFArrayRef allRecords;
+ if(CFStringCompare(recordType, kABPersonRecordType, 0) == kCFCompareEqualTo)
+ allRecords = ABCopyArrayOfAllPeople(addressBook);
+ else
+ allRecords = ABCopyArrayOfAllGroups(addressBook);
+
+ ABRecordRef record;
+ sal_Int32 i;
+ recordsSize = static_cast<sal_Int32>(CFArrayGetCount(allRecords));
+ records = new MacabRecord *[recordsSize];
+
+ /* First, we create the header... */
+ header = createHeaderForRecordType(allRecords, recordType);
+
+ /* Then, we create each of the records... */
+ for(i = 0; i < recordsSize; i++)
+ {
+ record = const_cast<ABRecordRef>(CFArrayGetValueAtIndex(allRecords, i));
+ records[i] = createMacabRecord(record, header, recordType);
+ }
+ currentRecord = recordsSize;
+
+ CFRelease(allRecords);
+}
+
+
+MacabRecords::~MacabRecords()
+{
+}
+
+
+void MacabRecords::setHeader(MacabHeader *_header)
+{
+ if(header != nullptr)
+ delete header;
+ header = _header;
+}
+
+
+MacabHeader *MacabRecords::getHeader() const
+{
+ return header;
+}
+
+
+/* Inserts a MacabRecord at a given location. If there is already a
+ * MacabRecord at that location, return it.
+ */
+MacabRecord *MacabRecords::insertRecord(MacabRecord *_newRecord, const sal_Int32 _location)
+{
+ MacabRecord *oldRecord;
+
+ /* If the location is greater than the current allocated size of this
+ * MacabRecords, allocate more space.
+ */
+ if(_location >= recordsSize)
+ {
+ sal_Int32 i;
+ MacabRecord **newRecordsArray = new MacabRecord *[_location+1];
+ for(i = 0; i < recordsSize; i++)
+ {
+ newRecordsArray[i] = records[i];
+ }
+ delete [] records;
+ records = newRecordsArray;
+ }
+
+ /* Remember: currentRecord refers to one above the highest existing
+ * record (i.e., it refers to where to place the next record if a
+ * location is not given).
+ */
+ if(_location >= currentRecord)
+ currentRecord = _location+1;
+
+ oldRecord = records[_location];
+ records[_location] = _newRecord;
+ return oldRecord;
+}
+
+
+/* Insert a record at the next available place. */
+void MacabRecords::insertRecord(MacabRecord *_newRecord)
+{
+ insertRecord(_newRecord, currentRecord);
+}
+
+
+MacabRecord *MacabRecords::getRecord(const sal_Int32 _location) const
+{
+ if(_location >= recordsSize)
+ return nullptr;
+ return records[_location];
+}
+
+
+macabfield *MacabRecords::getField(const sal_Int32 _recordNumber, const sal_Int32 _columnNumber) const
+{
+ if(_recordNumber >= recordsSize)
+ return nullptr;
+
+ MacabRecord *record = records[_recordNumber];
+
+ if(_columnNumber < 0 || _columnNumber >= record->getSize())
+ return nullptr;
+
+ return record->get(_columnNumber);
+}
+
+
+macabfield *MacabRecords::getField(const sal_Int32 _recordNumber, std::u16string_view _columnName)
+ const
+{
+ if(header != nullptr)
+ {
+ sal_Int32 columnNumber = header->getColumnNumber(_columnName);
+ if(columnNumber == -1)
+ return nullptr;
+
+ return getField(_recordNumber, columnNumber);
+ }
+ else
+ {
+ // error: shouldn't access field with null header!
+ return nullptr;
+ }
+}
+
+
+sal_Int32 MacabRecords::getFieldNumber(std::u16string_view _columnName) const
+{
+ if(header != nullptr)
+ return header->getColumnNumber(_columnName);
+ else
+ // error: shouldn't access field with null header!
+ return -1;
+}
+
+
+/* Create the lcl_CFTypes array -- we need this because there is no
+ * way to get the ABType of an object from the object itself, and the
+ * function ABTypeOfProperty can't handle multiple levels of data
+ * (e.g., it can tell us that "address" is of type
+ * kABDictionaryProperty, but it cannot tell us that all of the keys
+ * and values in the dictionary have type kABStringProperty. On the
+ * other hand, we _can_ get the CFType out of any object.
+ * Unfortunately, all information about CFTypeIDs comes with the
+ * warning that they change between releases, so we build them
+ * ourselves here. (The one that we can't build is for multivalues,
+ * e.g., kABMultiStringProperty. All of these appear to have the
+ * same type: 1, but there is no function that I've found to give
+ * us that dynamically in case that number ever changes.
+ */
+void MacabRecords::bootstrap_CF_types()
+{
+ lcl_CFTypes = {
+ {CFNumberGetTypeID(), kABIntegerProperty},
+ {CFStringGetTypeID(), kABStringProperty},
+ {CFDateGetTypeID(), kABDateProperty},
+ {CFArrayGetTypeID(), kABArrayProperty},
+ {CFDictionaryGetTypeID(), kABDictionaryProperty},
+ {CFDataGetTypeID(), kABDataProperty}};
+}
+
+
+/* This is based on the possible fields required in the mail merge template
+ * in sw. If the fields possible there change, it would be optimal to
+ * change these fields as well.
+ */
+void MacabRecords::bootstrap_requiredProperties()
+{
+ requiredProperties = {
+ kABTitleProperty, kABFirstNameProperty, kABLastNameProperty, kABOrganizationProperty,
+ kABAddressProperty, kABPhoneProperty, kABEmailProperty};
+}
+
+
+/* Create the header for a given record type and a given array of records.
+ * Because the array of records and the record type are given, if you want
+ * to, you can run this method on the members of a group, or on any other
+ * filtered list of people and get a header relevant to them (e.g., if
+ * they only have home addresses, the work address fields won't show up).
+ */
+MacabHeader *MacabRecords::createHeaderForRecordType(const CFArrayRef _records, const CFStringRef _recordType) const
+{
+ /* We have two types of properties for a given record type, nonrequired
+ * and required. Required properties are ones that will show up whether
+ * or not they are empty. Nonrequired properties will only show up if
+ * at least one record in the set has that property filled. The reason
+ * is that some properties, like the kABTitleProperty are required by
+ * the mail merge wizard (in module sw) but are by default not shown in
+ * the macOS address book, so they would be weeded out at this stage
+ * and not shown if they were not required.
+ *
+ * Note: with the addition of required properties, I am not sure that
+ * this method still works for kABGroupRecordType (since the required
+ * properties are all for kABPersonRecordType).
+ *
+ * Note: required properties are constructed in the method
+ * bootstrap_requiredProperties() (above).
+ */
+ CFArrayRef allProperties = ABCopyArrayOfPropertiesForRecordType(addressBook, _recordType);
+ CFStringRef *nonRequiredProperties;
+ sal_Int32 numRecords = static_cast<sal_Int32>(CFArrayGetCount(_records));
+ sal_Int32 numProperties = static_cast<sal_Int32>(CFArrayGetCount(allProperties));
+ sal_Int32 numNonRequiredProperties = numProperties - requiredProperties.size();
+
+ /* While searching through the properties for required properties, these
+ * sal_Bools will keep track of what we have found.
+ */
+ auto const bFoundRequiredProperties = std::make_unique<bool[]>(requiredProperties.size());
+
+
+ /* We have three MacabHeaders: headerDataForProperty is where we
+ * store the result of createHeaderForProperty(), which return a
+ * MacabHeader for a single property. lcl_header is where we store
+ * the MacabHeader that we are constructing. And, nonRequiredHeader
+ * is where we construct the MacabHeader for non-required properties,
+ * so that we can sort them before adding them to lcl_header.
+ */
+ MacabHeader *headerDataForProperty;
+ MacabHeader *lcl_header = new MacabHeader();
+ MacabHeader *nonRequiredHeader = new MacabHeader();
+
+ /* Other variables... */
+ sal_Int32 k;
+ ABRecordRef record;
+ CFStringRef property;
+
+
+ /* Allocate and initialize... */
+ nonRequiredProperties = new CFStringRef[numNonRequiredProperties];
+ k = 0;
+ for(std::vector<CFStringRef>::size_type i = 0; i < requiredProperties.size(); i++)
+ bFoundRequiredProperties[i] = false;
+
+ /* Determine the non-required properties... */
+ for(sal_Int32 i = 0; i < numProperties; i++)
+ {
+ bool bFoundProperty = false;
+ property = static_cast<CFStringRef>(CFArrayGetValueAtIndex(allProperties, i));
+ for(std::vector<CFStringRef>::size_type j = 0; j < requiredProperties.size(); j++)
+ {
+ if(CFEqual(property, requiredProperties[j]))
+ {
+ bFoundProperty = true;
+ bFoundRequiredProperties[j] = true;
+ break;
+ }
+ }
+
+ if(!bFoundProperty)
+ {
+ /* If we have found too many non-required properties */
+ if(k == numNonRequiredProperties)
+ {
+ k++; // so that the OSL_ENSURE below fails
+ break;
+ }
+ nonRequiredProperties[k] = property;
+ k++;
+ }
+ }
+
+ // Somehow, we got too many or too few non-required properties...
+ // Most likely, one of the required properties no longer exists, which
+ // we also test later.
+ OSL_ENSURE(k == numNonRequiredProperties, "MacabRecords::createHeaderForRecordType: Found an unexpected number of non-required properties");
+
+ /* Fill the header with required properties first... */
+ for(std::vector<CFStringRef>::size_type i = 0; i < requiredProperties.size(); i++)
+ {
+ if(bFoundRequiredProperties[i])
+ {
+ /* The order of these matters (we want all address properties
+ * before any phone properties, or else things will look weird),
+ * so we get all possibilities for each property, going through
+ * each record, and then go onto the next property.
+ * (Note: the reason that we have to go through all records
+ * in the first place is that properties like address, phone, and
+ * e-mail are multi-value properties with an unknown number of
+ * values. A user could specify thirteen different kinds of
+ * e-mail addresses for one of her or his contacts, and we need to
+ * get all of them.
+ */
+ for(sal_Int32 j = 0; j < numRecords; j++)
+ {
+ record = const_cast<ABRecordRef>(CFArrayGetValueAtIndex(_records, j));
+ headerDataForProperty = createHeaderForProperty(record,requiredProperties[i],_recordType,true);
+ if(headerDataForProperty != nullptr)
+ {
+ (*lcl_header) += headerDataForProperty;
+ delete headerDataForProperty;
+ }
+ }
+ }
+ else
+ {
+ // Couldn't find a required property...
+ OSL_FAIL(OString("MacabRecords::createHeaderForRecordType: could not find required property: " +
+ OUStringToOString(CFStringToOUString(requiredProperties[i]), RTL_TEXTENCODING_ASCII_US)).getStr());
+ }
+ }
+
+ /* And now, non-required properties... */
+ for(sal_Int32 i = 0; i < numRecords; i++)
+ {
+ record = const_cast<ABRecordRef>(CFArrayGetValueAtIndex(_records, i));
+
+ for(sal_Int32 j = 0; j < numNonRequiredProperties; j++)
+ {
+ property = nonRequiredProperties[j];
+ headerDataForProperty = createHeaderForProperty(record,property,_recordType,false);
+ if(headerDataForProperty != nullptr)
+ {
+ (*nonRequiredHeader) += headerDataForProperty;
+ delete headerDataForProperty;
+ }
+ }
+
+ }
+ nonRequiredHeader->sortRecord();
+
+ (*lcl_header) += nonRequiredHeader;
+ delete nonRequiredHeader;
+
+ CFRelease(allProperties);
+ delete [] nonRequiredProperties;
+
+ return lcl_header;
+}
+
+
+/* Create a header for a single property. Basically, this method gets
+ * the property's value and type and then calls another method of
+ * the same name to do the dirty work.
+ */
+MacabHeader *MacabRecords::createHeaderForProperty(const ABRecordRef _record, const CFStringRef _propertyName, const CFStringRef _recordType, const bool _isPropertyRequired) const
+{
+ // local variables
+ CFStringRef localizedPropertyName;
+ CFTypeRef propertyValue;
+ ABPropertyType propertyType;
+ MacabHeader *result;
+
+ /* Get the property's value */
+ propertyValue = ABRecordCopyValue(_record,_propertyName);
+ if(propertyValue == nullptr && !_isPropertyRequired)
+ return nullptr;
+
+ propertyType = ABTypeOfProperty(addressBook, _recordType, _propertyName);
+ localizedPropertyName = ABCopyLocalizedPropertyOrLabel(_propertyName);
+
+ result = createHeaderForProperty(propertyType, propertyValue, localizedPropertyName);
+
+ if(propertyValue != nullptr)
+ CFRelease(propertyValue);
+
+ return result;
+}
+
+
+/* Create a header for a single property. This method is recursive
+ * because a single property might contain several sub-properties that
+ * we also want to treat singly.
+ */
+MacabHeader *MacabRecords::createHeaderForProperty(const ABPropertyType _propertyType, const CFTypeRef _propertyValue, const CFStringRef _propertyName) const
+{
+ macabfield **headerNames = nullptr;
+ sal_Int32 length = 0;
+
+ switch(_propertyType)
+ {
+ /* Scalars */
+ case kABStringProperty:
+ case kABRealProperty:
+ case kABIntegerProperty:
+ case kABDateProperty:
+ length = 1;
+ headerNames = new macabfield *[1];
+ headerNames[0] = new macabfield;
+ headerNames[0]->value = _propertyName;
+ headerNames[0]->type = _propertyType;
+ break;
+
+ /* Multi-scalars */
+ case kABMultiIntegerProperty:
+ case kABMultiDateProperty:
+ case kABMultiStringProperty:
+ case kABMultiRealProperty:
+ case kABMultiDataProperty:
+ /* For non-scalars, we can only get more information if the property
+ * actually exists.
+ */
+ if(_propertyValue != nullptr)
+ {
+ sal_Int32 i;
+
+ sal_Int32 multiLength = ABMultiValueCount(static_cast<ABMutableMultiValueRef>(const_cast<void *>(_propertyValue)));
+ CFStringRef multiLabel, localizedMultiLabel;
+ OUString multiLabelString;
+ OUString multiPropertyString;
+ OUString headerNameString;
+ ABPropertyType multiType = static_cast<ABPropertyType>(ABMultiValuePropertyType(static_cast<ABMutableMultiValueRef>(const_cast<void *>(_propertyValue))) - 0x100);
+
+ length = multiLength;
+ headerNames = new macabfield *[multiLength];
+ multiPropertyString = CFStringToOUString(_propertyName);
+
+ /* Go through each element, and - since each element is a scalar -
+ * just create a new macabfield for it.
+ */
+ for(i = 0; i < multiLength; i++)
+ {
+ multiLabel = ABMultiValueCopyLabelAtIndex(static_cast<ABMutableMultiValueRef>(const_cast<void *>(_propertyValue)), i);
+ localizedMultiLabel = ABCopyLocalizedPropertyOrLabel(multiLabel);
+ multiLabelString = CFStringToOUString(localizedMultiLabel);
+ CFRelease(multiLabel);
+ CFRelease(localizedMultiLabel);
+ headerNameString = multiPropertyString + ": " + fixLabel(multiLabelString);
+ headerNames[i] = new macabfield;
+ headerNames[i]->value = OUStringToCFString(headerNameString);
+ headerNames[i]->type = multiType;
+ }
+ }
+ break;
+
+ /* Multi-array or dictionary */
+ case kABMultiArrayProperty:
+ case kABMultiDictionaryProperty:
+ /* For non-scalars, we can only get more information if the property
+ * actually exists.
+ */
+ if(_propertyValue != nullptr)
+ {
+ sal_Int32 i,j,k;
+
+ // Total number of multi-array or multi-dictionary elements.
+ sal_Int32 multiLengthFirstLevel = ABMultiValueCount(static_cast<ABMutableMultiValueRef>(const_cast<void *>(_propertyValue)));
+
+ /* Total length, including the length of each element (e.g., if
+ * this multi-dictionary contains three dictionaries, and each
+ * dictionary has four elements, this variable will be twelve,
+ * whereas multiLengthFirstLevel will be three.
+ */
+ sal_Int32 multiLengthSecondLevel = 0;
+
+ CFStringRef multiLabel, localizedMultiLabel;
+ CFTypeRef multiValue;
+ OUString multiLabelString;
+ OUString multiPropertyString;
+ std::vector<std::unique_ptr<MacabHeader>> multiHeaders;
+ ABPropertyType multiType = static_cast<ABPropertyType>(ABMultiValuePropertyType(static_cast<ABMutableMultiValueRef>(const_cast<void *>(_propertyValue))) - 0x100);
+
+ multiPropertyString = CFStringToOUString(_propertyName);
+
+ /* Go through each element - since each element can really
+ * contain anything, we run this method again on each element
+ * and store the resulting MacabHeader (in the multiHeaders
+ * array). Then, all we'll have to do is combine the MacabHeaders
+ * into a single one.
+ */
+ for(i = 0; i < multiLengthFirstLevel; i++)
+ {
+ /* label */
+ multiLabel = ABMultiValueCopyLabelAtIndex(static_cast<ABMutableMultiValueRef>(const_cast<void *>(_propertyValue)), i);
+ multiValue = ABMultiValueCopyValueAtIndex(static_cast<ABMutableMultiValueRef>(const_cast<void *>(_propertyValue)), i);
+ std::unique_ptr<MacabHeader> hdr;
+ if(multiValue && multiLabel)
+ {
+ localizedMultiLabel = ABCopyLocalizedPropertyOrLabel(multiLabel);
+ multiLabelString = multiPropertyString + ": " + fixLabel(CFStringToOUString(localizedMultiLabel));
+ CFRelease(multiLabel);
+ CFRelease(localizedMultiLabel);
+ multiLabel = OUStringToCFString(multiLabelString);
+ hdr.reset(createHeaderForProperty(multiType, multiValue, multiLabel));
+ if (!hdr)
+ hdr = std::make_unique<MacabHeader>();
+ multiLengthSecondLevel += hdr->getSize();
+ }
+ else
+ {
+ hdr = std::make_unique<MacabHeader>();
+ }
+ if(multiValue)
+ CFRelease(multiValue);
+ if(multiLabel)
+ CFRelease(multiLabel);
+ multiHeaders.push_back(std::move(hdr));
+ }
+
+ /* We now have enough information to create our final MacabHeader.
+ * We go through each field of each header and add it to the
+ * headerNames array (which is what is used below to construct
+ * the MacabHeader we return).
+ */
+ length = multiLengthSecondLevel;
+ headerNames = new macabfield *[multiLengthSecondLevel];
+
+ for(i = 0, j = 0, k = 0; i < multiLengthSecondLevel; i++,k++)
+ {
+ while(multiHeaders[j]->getSize() == k)
+ {
+ j++;
+ k = 0;
+ }
+
+ headerNames[i] = multiHeaders[j]->copy(k);
+ }
+ }
+ break;
+
+ /* Dictionary */
+ case kABDictionaryProperty:
+ /* For non-scalars, we can only get more information if the property
+ * actually exists.
+ */
+ if(_propertyValue != nullptr)
+ {
+ /* Assume all keys are strings */
+ sal_Int32 numRecords = static_cast<sal_Int32>(CFDictionaryGetCount(static_cast<CFDictionaryRef>(_propertyValue)));
+
+ /* The only method for getting info out of a CFDictionary, of both
+ * keys and values, is to all of them all at once, so these
+ * variables will hold them.
+ */
+ CFStringRef *dictKeys;
+ CFTypeRef *dictValues;
+
+ sal_Int32 i,j,k;
+ OUString dictKeyString, propertyNameString;
+ ABPropertyType dictType;
+ MacabHeader **dictHeaders = new MacabHeader *[numRecords];
+ OUString dictLabelString;
+ CFStringRef dictLabel, localizedDictKey;
+
+ /* Get the keys and values */
+ dictKeys = static_cast<CFStringRef *>(malloc(sizeof(CFStringRef)*numRecords));
+ dictValues = static_cast<CFTypeRef *>(malloc(sizeof(CFTypeRef)*numRecords));
+ CFDictionaryGetKeysAndValues(static_cast<CFDictionaryRef>(_propertyValue), reinterpret_cast<const void **>(dictKeys), dictValues);
+
+ propertyNameString = CFStringToOUString(_propertyName);
+
+ length = 0;
+ /* Go through each element - assuming that the key is a string but
+ * that the value could be anything. Since the value could be
+ * anything, we can't assume that it is scalar (it could even be
+ * another dictionary), so we attempt to get its type using
+ * the method getABTypeFromCFType and then run this method
+ * recursively on that element, storing the MacabHeader that
+ * results. Then, we just combine all of the MacabHeaders into
+ * one.
+ */
+ for(i = 0; i < numRecords; i++)
+ {
+ dictType = getABTypeFromCFType( CFGetTypeID(dictValues[i]) );
+ localizedDictKey = ABCopyLocalizedPropertyOrLabel(dictKeys[i]);
+ dictKeyString = CFStringToOUString(localizedDictKey);
+ dictLabelString = propertyNameString + ": " + fixLabel(dictKeyString);
+ dictLabel = OUStringToCFString(dictLabelString);
+ dictHeaders[i] = createHeaderForProperty(dictType, dictValues[i], dictLabel);
+ if (!dictHeaders[i])
+ dictHeaders[i] = new MacabHeader();
+ length += dictHeaders[i]->getSize();
+ CFRelease(dictLabel);
+ CFRelease(localizedDictKey);
+ }
+
+ /* Combine all of the macabfields in each MacabHeader into the
+ * headerNames array, which (at the end of this method) is used
+ * to create the MacabHeader that is returned.
+ */
+ headerNames = new macabfield *[length];
+ for(i = 0, j = 0, k = 0; i < length; i++,k++)
+ {
+ while(dictHeaders[j]->getSize() == k)
+ {
+ j++;
+ k = 0;
+ }
+
+ headerNames[i] = dictHeaders[j]->copy(k);
+ }
+
+ for(i = 0; i < numRecords; i++)
+ delete dictHeaders[i];
+
+ delete [] dictHeaders;
+ free(dictKeys);
+ free(dictValues);
+ }
+ break;
+
+ /* Array */
+ case kABArrayProperty:
+ /* For non-scalars, we can only get more information if the property
+ * actually exists.
+ */
+ if(_propertyValue != nullptr)
+ {
+ sal_Int32 arrLength = static_cast<sal_Int32>(CFArrayGetCount(static_cast<CFArrayRef>(_propertyValue)));
+ sal_Int32 i,j,k;
+ CFTypeRef arrValue;
+ ABPropertyType arrType;
+ std::vector<std::unique_ptr<MacabHeader>> arrHeaders;
+ OUString propertyNameString = CFStringToOUString(_propertyName);
+ OUString arrLabelString;
+ CFStringRef arrLabel;
+
+ length = 0;
+ /* Go through each element - since the elements here do not have
+ * unique keys like the ones in dictionaries, we create a unique
+ * key out of the id of the element in the array (the first
+ * element gets a 0 plopped onto the end of it, the second a 1...
+ * As with dictionaries, the elements could be anything, including
+ * another array, so we have to run this method recursively on
+ * each element, storing the resulting MacabHeader into an array,
+ * which we then combine into one MacabHeader that is returned.
+ */
+ for(i = 0; i < arrLength; i++)
+ {
+ arrValue = CFArrayGetValueAtIndex(static_cast<CFArrayRef>(_propertyValue), i);
+ arrType = getABTypeFromCFType( CFGetTypeID(arrValue) );
+ arrLabelString = propertyNameString + OUString::number(i);
+ arrLabel = OUStringToCFString(arrLabelString);
+ auto hdr = std::unique_ptr<MacabHeader>(createHeaderForProperty(arrType, arrValue, arrLabel));
+ if (!hdr)
+ hdr = std::make_unique<MacabHeader>();
+ length += hdr->getSize();
+ CFRelease(arrLabel);
+ arrHeaders.push_back(std::move(hdr));
+ }
+
+ headerNames = new macabfield *[length];
+ for(i = 0, j = 0, k = 0; i < length; i++,k++)
+ {
+ while(arrHeaders[j]->getSize() == k)
+ {
+ j++;
+ k = 0;
+ }
+
+ headerNames[i] = arrHeaders[j]->copy(k);
+ }
+ }
+ break;
+
+ default:
+ break;
+
+ }
+
+ /* If we succeeded at adding elements to the headerNames array, then
+ * length will no longer be 0. If it is, create a new MacabHeader
+ * out of the headerNames (after weeding out duplicate headers), and
+ * then return the result. If the length is still 0, return NULL: we
+ * failed to create a MacabHeader out of this property.
+ */
+ if(length != 0)
+ {
+ manageDuplicateHeaders(headerNames, length);
+ MacabHeader *headerResult = new MacabHeader(length, headerNames);
+ for(sal_Int32 i = 0; i < length; ++i)
+ delete headerNames[i];
+ delete [] headerNames;
+ return headerResult;
+ }
+ else
+ return nullptr;
+}
+
+
+/* Create a MacabRecord out of an ABRecord, using a given MacabHeader and
+ * the record's type. We go through each property for this record type
+ * then process it much like we processed the header (above), with two
+ * exceptions: if we come upon something not in the header, we ignore it
+ * (it's something we don't want to add), and once we find a corresponding
+ * location in the header, we store the property and the property type in
+ * a macabfield. (For the header, we stored the property type and the name
+ * of the property as a CFString.)
+ */
+MacabRecord *MacabRecords::createMacabRecord(const ABRecordRef _abrecord, const MacabHeader *_header, const CFStringRef _recordType) const
+{
+ /* The new record that we will create... */
+ MacabRecord *macabRecord = new MacabRecord(_header->getSize());
+
+ CFArrayRef recordProperties = ABCopyArrayOfPropertiesForRecordType(addressBook, _recordType);
+ sal_Int32 numProperties = static_cast<sal_Int32>(CFArrayGetCount(recordProperties));
+
+ sal_Int32 i;
+
+ CFTypeRef propertyValue;
+ ABPropertyType propertyType;
+
+ CFStringRef propertyName, localizedPropertyName;
+ OUString propertyNameString;
+ for(i = 0; i < numProperties; i++)
+ {
+ propertyName = static_cast<CFStringRef>(CFArrayGetValueAtIndex(recordProperties, i));
+ localizedPropertyName = ABCopyLocalizedPropertyOrLabel(propertyName);
+ propertyNameString = CFStringToOUString(localizedPropertyName);
+ CFRelease(localizedPropertyName);
+
+ /* Get the property's value */
+ propertyValue = ABRecordCopyValue(_abrecord,propertyName);
+ if(propertyValue != nullptr)
+ {
+ propertyType = ABTypeOfProperty(addressBook, _recordType, propertyName);
+ if(propertyType != kABErrorInProperty)
+ insertPropertyIntoMacabRecord(propertyType, macabRecord, _header, propertyNameString, propertyValue);
+
+ CFRelease(propertyValue);
+ }
+ }
+ CFRelease(recordProperties);
+ return macabRecord;
+}
+
+
+/* Inserts a given property into a MacabRecord. This method calls another
+ * method by the same name after getting the property type (it only
+ * receives the property value). It is called when we aren't given the
+ * property's type already.
+ */
+void MacabRecords::insertPropertyIntoMacabRecord(MacabRecord *_abrecord, const MacabHeader *_header, const OUString& _propertyName, const CFTypeRef _propertyValue) const
+{
+ CFTypeID cf_type = CFGetTypeID(_propertyValue);
+ ABPropertyType ab_type = getABTypeFromCFType( cf_type );
+
+ if(ab_type != kABErrorInProperty)
+ insertPropertyIntoMacabRecord(ab_type, _abrecord, _header, _propertyName, _propertyValue);
+}
+
+
+/* Inserts a given property into a MacabRecord. This method is recursive
+ * because properties can contain many sub-properties.
+ */
+void MacabRecords::insertPropertyIntoMacabRecord(const ABPropertyType _propertyType, MacabRecord *_abrecord, const MacabHeader *_header, const OUString& _propertyName, const CFTypeRef _propertyValue) const
+{
+ /* If there is no value, return */
+ if(_propertyValue == nullptr)
+ return;
+
+ /* The main switch statement */
+ switch(_propertyType)
+ {
+ /* Scalars */
+ case kABStringProperty:
+ case kABRealProperty:
+ case kABIntegerProperty:
+ case kABDateProperty:
+ {
+ /* Only scalars actually insert a property into the MacabRecord.
+ * In all other cases, this method is called recursively until a
+ * scalar type, an error, or an unknown type are found.
+ * Because of that, the following checks only occur for this type.
+ * We store whether we have successfully placed this property
+ * into the MacabRecord (or whether an unrecoverable error occurred).
+ * Then, we try over and over again to place the property into the
+ * record. There are three possible results:
+ * 1) Success!
+ * 2) There is already a property stored at the column of this name,
+ * in which case we have a duplicate header (see the method
+ * manageDuplicateHeaders()). If that is the case, we add an ID
+ * to the end of the column name in the same format as we do in
+ * manageDuplicateHeaders() and try again.
+ * 3) No column of this name exists in the header. In this case,
+ * there is nothing we can do: we have failed to place this
+ * property into the record.
+ */
+ bool bPlaced = false;
+ OUString columnName = _propertyName;
+ sal_Int32 i = 1;
+
+ // A big safeguard to prevent two fields from having the same name.
+ while(!bPlaced)
+ {
+ sal_Int32 columnNumber = _header->getColumnNumber(columnName);
+ bPlaced = true;
+ if(columnNumber != -1)
+ {
+ // collision! A property already exists here!
+ if(_abrecord->get(columnNumber) != nullptr)
+ {
+ bPlaced = false;
+ i++;
+ columnName = _propertyName + " (" + OUString::number(i) + ")";
+ }
+
+ // success!
+ else
+ {
+ _abrecord->insertAtColumn(_propertyValue, _propertyType, columnNumber);
+ }
+ }
+ }
+ }
+ break;
+
+ /* Array */
+ case kABArrayProperty:
+ {
+ /* An array is basically just a list of anything, so all we do
+ * is go through the array, and rerun this method recursively
+ * on each element.
+ */
+ sal_Int32 arrLength = static_cast<sal_Int32>(CFArrayGetCount(static_cast<CFArrayRef>(_propertyValue)));
+ sal_Int32 i;
+ OUString newPropertyName;
+
+ /* Going through each element... */
+ for(i = 0; i < arrLength; i++)
+ {
+ const void *arrValue = CFArrayGetValueAtIndex(static_cast<CFArrayRef>(_propertyValue), i);
+ newPropertyName = _propertyName + OUString::number(i);
+ insertPropertyIntoMacabRecord(_abrecord, _header, newPropertyName, arrValue);
+ CFRelease(arrValue);
+ }
+
+ }
+ break;
+
+ /* Dictionary */
+ case kABDictionaryProperty:
+ {
+ /* A dictionary is basically a hashmap. Technically, it can
+ * hold any object as a key and any object as a value.
+ * For our case, we assume that the key is a string (so that
+ * we can use the key to get the column name and match it against
+ * the header), but we don't assume anything about the value, so
+ * we run this method recursively (or, rather, we run the version
+ * of this method for when we don't know the object's type) until
+ * we hit a scalar value.
+ */
+
+ sal_Int32 numRecords = static_cast<sal_Int32>(CFDictionaryGetCount(static_cast<CFDictionaryRef>(_propertyValue)));
+ OUString dictKeyString;
+ sal_Int32 i;
+ OUString newPropertyName;
+
+ /* Unfortunately, the only way to get both keys and values out
+ * of a dictionary in Carbon is to get them all at once, so we
+ * do that.
+ */
+ CFStringRef *dictKeys;
+ CFStringRef localizedDictKey;
+ CFTypeRef *dictValues;
+ dictKeys = static_cast<CFStringRef *>(malloc(sizeof(CFStringRef)*numRecords));
+ dictValues = static_cast<CFTypeRef *>(malloc(sizeof(CFTypeRef)*numRecords));
+ CFDictionaryGetKeysAndValues(static_cast<CFDictionaryRef>(_propertyValue), reinterpret_cast<const void **>(dictKeys), dictValues);
+
+ /* Going through each element... */
+ for(i = 0; i < numRecords; i++)
+ {
+ localizedDictKey = ABCopyLocalizedPropertyOrLabel(dictKeys[i]);
+ dictKeyString = CFStringToOUString(localizedDictKey);
+ CFRelease(localizedDictKey);
+ newPropertyName = _propertyName + ": " + fixLabel(dictKeyString);
+ insertPropertyIntoMacabRecord(_abrecord, _header, newPropertyName, dictValues[i]);
+ }
+
+ free(dictKeys);
+ free(dictValues);
+ }
+ break;
+
+ /* Multivalue */
+ case kABMultiIntegerProperty:
+ case kABMultiDateProperty:
+ case kABMultiStringProperty:
+ case kABMultiRealProperty:
+ case kABMultiDataProperty:
+ case kABMultiDictionaryProperty:
+ case kABMultiArrayProperty:
+ {
+ /* All scalar multivalues are handled in the same way. Each element
+ * is a label and a value. All labels are strings
+ * (kABStringProperty), and all values have the same type
+ * (which is the type of the multivalue minus 255, or as
+ * Carbon's list of property types has it, minus 0x100.
+ * We just get the correct type, then go through each element
+ * and get the label and value and print them in a list.
+ */
+
+ sal_Int32 i;
+ sal_Int32 multiLength = ABMultiValueCount(static_cast<ABMutableMultiValueRef>(const_cast<void *>(_propertyValue)));
+ CFStringRef multiLabel, localizedMultiLabel;
+ CFTypeRef multiValue;
+ OUString multiLabelString, newPropertyName;
+ ABPropertyType multiType = static_cast<ABPropertyType>(ABMultiValuePropertyType(static_cast<ABMutableMultiValueRef>(const_cast<void *>(_propertyValue))) - 0x100);
+
+ /* Go through each element... */
+ for(i = 0; i < multiLength; i++)
+ {
+ /* Label and value */
+ multiLabel = ABMultiValueCopyLabelAtIndex(static_cast<ABMutableMultiValueRef>(const_cast<void *>(_propertyValue)), i);
+ multiValue = ABMultiValueCopyValueAtIndex(static_cast<ABMutableMultiValueRef>(const_cast<void *>(_propertyValue)), i);
+
+ localizedMultiLabel = ABCopyLocalizedPropertyOrLabel(multiLabel);
+ multiLabelString = CFStringToOUString(localizedMultiLabel);
+ newPropertyName = _propertyName + ": " + fixLabel(multiLabelString);
+ insertPropertyIntoMacabRecord(multiType, _abrecord, _header, newPropertyName, multiValue);
+
+ /* free our variables */
+ CFRelease(multiLabel);
+ CFRelease(localizedMultiLabel);
+ CFRelease(multiValue);
+ }
+ }
+ break;
+
+ /* Unhandled types */
+ case kABErrorInProperty:
+ case kABDataProperty:
+ default:
+ /* An error, as far as I have seen, only shows up as a type
+ * returned by a function for dictionaries when the dictionary
+ * holds many types of values. Since we do not use that function,
+ * it shouldn't come up. I have yet to see the kABDataProperty,
+ * and I am not sure how to represent it as a string anyway,
+ * since it appears to just be a bunch of bytes. Assumably, if
+ * these bytes made up a string, the type would be
+ * kABStringProperty. I think that this is used when we are not
+ * sure what the type is (e.g., it could be a string or a number).
+ * That being the case, I still don't know how to represent it.
+ * And, default should never come up, since we've exhausted all
+ * of the possible types for ABPropertyType, but... just in case.
+ */
+ break;
+ }
+
+}
+
+
+ABPropertyType MacabRecords::getABTypeFromCFType(const CFTypeID cf_type ) const
+{
+ for(auto const & i: lcl_CFTypes)
+ {
+ /* A match! */
+ if(i.cf == cf_type)
+ {
+ return static_cast<ABPropertyType>(i.ab);
+ }
+ }
+ return kABErrorInProperty;
+}
+
+
+sal_Int32 MacabRecords::size() const
+{
+ return currentRecord;
+}
+
+
+MacabRecords *MacabRecords::begin()
+{
+ return this;
+}
+
+
+MacabRecords::iterator::iterator ()
+{
+}
+
+
+MacabRecords::iterator& MacabRecords::iterator::operator= (MacabRecords *_records)
+{
+ id = 0;
+ records = _records;
+ return *this;
+}
+
+
+void MacabRecords::iterator::operator++ ()
+{
+ id++;
+}
+
+
+bool MacabRecords::iterator::operator!= (const sal_Int32 i) const
+{
+ return(id != i);
+}
+
+
+bool MacabRecords::iterator::operator== (const sal_Int32 i) const
+{
+ return(id == i);
+}
+
+
+MacabRecord *MacabRecords::iterator::operator* () const
+{
+ return records->getRecord(id);
+}
+
+
+sal_Int32 MacabRecords::end() const
+{
+ return currentRecord;
+}
+
+
+void MacabRecords::swap(const sal_Int32 _id1, const sal_Int32 _id2)
+{
+ MacabRecord *swapRecord = records[_id1];
+
+ records[_id1] = records[_id2];
+ records[_id2] = swapRecord;
+}
+
+
+void MacabRecords::setName(const OUString& _sName)
+{
+ m_sName = _sName;
+}
+
+
+OUString const & MacabRecords::getName() const
+{
+ return m_sName;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/macab/MacabRecords.hxx b/connectivity/source/drivers/macab/MacabRecords.hxx
new file mode 100644
index 0000000000..8d0d5cf6f7
--- /dev/null
+++ b/connectivity/source/drivers/macab/MacabRecords.hxx
@@ -0,0 +1,125 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <string_view>
+#include <vector>
+
+#include "MacabRecord.hxx"
+#include "MacabHeader.hxx"
+
+#include <premac.h>
+#include <Carbon/Carbon.h>
+#include <AddressBook/ABAddressBookC.h>
+#include <postmac.h>
+#include <com/sun/star/util/DateTime.hpp>
+
+namespace connectivity::macab
+{
+ /* This struct is for converting CF types to AB types (Core Foundation
+ * types to Address Book types).
+ */
+ struct lcl_CFType {
+ CFTypeID cf;
+ sal_Int32 ab;
+ };
+
+ class MacabRecords{
+ protected:
+ /* MacabRecords is, at its core, a table of macabfields, in the
+ * form of a header and a list of objects of type MacabRecord.
+ * It also has a unique name that refers to the name of the table.
+ */
+ sal_Int32 recordsSize;
+ sal_Int32 currentRecord;
+ CFStringRef recordType;
+ MacabHeader *header;
+ MacabRecord **records;
+ ABAddressBookRef addressBook;
+ OUString m_sName;
+
+ /* For converting CF types to AB types */
+ std::vector<lcl_CFType> lcl_CFTypes;
+
+ /* For required properties */
+ std::vector<CFStringRef> requiredProperties;
+
+ private:
+ /* All of the private methods are for creating a MacabHeader or a
+ * MacabRecord. They are used by the initialize method that goes
+ * about filling a MacabRecords using all of the records in the
+ * macOS Address Book.
+ */
+ void bootstrap_CF_types();
+ void bootstrap_requiredProperties();
+ MacabHeader *createHeaderForProperty(const ABRecordRef _record, const CFStringRef _propertyName, const CFStringRef _recordType, const bool _isPropertyRequired) const;
+ MacabHeader *createHeaderForProperty(const ABPropertyType _propertyType, const CFTypeRef _propertyValue, const CFStringRef _propertyName) const;
+ ABPropertyType getABTypeFromCFType(const CFTypeID cf_type ) const;
+ void insertPropertyIntoMacabRecord(MacabRecord *_abrecord, const MacabHeader *_header, const OUString& _propertyName, const CFTypeRef _propertyValue) const;
+ void insertPropertyIntoMacabRecord(const ABPropertyType _propertyType, MacabRecord *_abrecord, const MacabHeader *_header, const OUString& _propertyName, const CFTypeRef _propertyValue) const;
+ public:
+ MacabRecords(const ABAddressBookRef _addressBook, MacabHeader *_header, MacabRecord **_records, sal_Int32 _numRecords);
+ explicit MacabRecords(const MacabRecords *_copy);
+ explicit MacabRecords(const ABAddressBookRef _addressBook);
+ ~MacabRecords();
+
+ void initialize();
+
+ void setHeader(MacabHeader *_header);
+ MacabHeader *getHeader() const;
+
+ void setName(const OUString& _sName);
+ OUString const & getName() const;
+
+ MacabRecord *insertRecord(MacabRecord *_newRecord, const sal_Int32 _location);
+ void insertRecord(MacabRecord *_newRecord);
+ MacabRecord *getRecord(const sal_Int32 _location) const;
+ void swap(const sal_Int32 _id1, const sal_Int32 _id2);
+
+ macabfield *getField(const sal_Int32 _recordNumber, const sal_Int32 _columnNumber) const;
+ macabfield *getField(const sal_Int32 _recordNumber, std::u16string_view _columnName) const;
+ sal_Int32 getFieldNumber(std::u16string_view _columnName) const;
+
+ sal_Int32 size() const;
+
+ MacabHeader *createHeaderForRecordType(const CFArrayRef _records, const CFStringRef _recordType) const;
+ MacabRecord *createMacabRecord(const ABRecordRef _abrecord, const MacabHeader *_header, const CFStringRef _recordType) const;
+
+ MacabRecords *begin();
+ sal_Int32 end() const;
+ class iterator{
+ protected:
+ MacabRecords *records;
+ public:
+ sal_Int32 id;
+ iterator& operator= (MacabRecords *_records);
+ iterator();
+ void operator++ ();
+ bool operator!= (const sal_Int32 i) const;
+ bool operator== (const sal_Int32 i) const;
+ MacabRecord *operator* () const;
+ };
+
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/macab/MacabResultSet.cxx b/connectivity/source/drivers/macab/MacabResultSet.cxx
new file mode 100644
index 0000000000..4142fcb6cc
--- /dev/null
+++ b/connectivity/source/drivers/macab/MacabResultSet.cxx
@@ -0,0 +1,1094 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include "MacabResultSet.hxx"
+#include "MacabAddressBook.hxx"
+#include "MacabRecords.hxx"
+#include "macabutilities.hxx"
+#include "MacabResultSetMetaData.hxx"
+#include "MacabConnection.hxx"
+#include "macabcondition.hxx"
+#include "macaborder.hxx"
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/sdbcx/CompareBookmark.hpp>
+#include <TConnection.hxx>
+#include <cppuhelper/typeprovider.hxx>
+#include <comphelper/types.hxx>
+#include <connectivity/dbexception.hxx>
+#include <resource/sharedresources.hxx>
+#include <rtl/ref.hxx>
+#include <strings.hrc>
+
+using namespace connectivity::macab;
+using namespace cppu;
+using namespace css::uno;
+using namespace css::lang;
+using namespace css::beans;
+using namespace css::sdbc;
+using namespace css::sdbcx;
+using namespace css::io;
+using namespace css::util;
+
+IMPLEMENT_SERVICE_INFO(MacabResultSet, "com.sun.star.sdbc.drivers.MacabResultSet", "com.sun.star.sdbc.ResultSet");
+
+MacabResultSet::MacabResultSet(MacabCommonStatement* pStmt)
+ : MacabResultSet_BASE(m_aMutex),
+ OPropertySetHelper(MacabResultSet_BASE::rBHelper),
+ m_xStatement(pStmt),
+ m_aMacabRecords(),
+ m_nRowPos(-1),
+ m_bWasNull(true),
+ m_sTableName(MacabAddressBook::getDefaultTableName())
+{
+}
+
+MacabResultSet::~MacabResultSet()
+{
+}
+
+void MacabResultSet::allMacabRecords()
+{
+ rtl::Reference<MacabConnection> pConnection = static_cast< MacabConnection *>(m_xStatement->getConnection().get());
+
+ m_aMacabRecords = pConnection->getAddressBook()->getMacabRecords(m_sTableName);
+}
+
+void MacabResultSet::someMacabRecords(const MacabCondition *pCondition)
+{
+ rtl::Reference<MacabConnection> pConnection = static_cast< MacabConnection *>(m_xStatement->getConnection().get());
+ MacabRecords* allRecords;
+
+ allRecords = pConnection->getAddressBook()->getMacabRecords(m_sTableName);
+
+ // Bad table!! Throw exception?
+ if(allRecords == nullptr)
+ return;
+
+ if(m_aMacabRecords != nullptr && m_aMacabRecords != allRecords)
+ delete m_aMacabRecords;
+
+ // The copy constructor copies everything but records (including the
+ // maximum allocated size, which means that we'll never have to resize)
+ m_aMacabRecords = new MacabRecords(allRecords);
+
+ if(pCondition->isAlwaysFalse())
+ {
+ return;
+ }
+
+ MacabRecords::iterator iterator;
+
+ for (iterator = allRecords->begin();
+ iterator != allRecords->end();
+ ++iterator)
+ {
+ if (pCondition->eval(*iterator))
+ m_aMacabRecords->insertRecord(*iterator);
+ }
+}
+
+void MacabResultSet::sortMacabRecords(const MacabOrder *pOrder)
+{
+ // I do this with ints rather than an iterator because the ids will
+ // be changing when we change the order and ints are easier to deal
+ // with (for me).
+ sal_Int32 i, j, size, smallest;
+ size = m_aMacabRecords->size();
+
+ for(i = 0; i < size; i++)
+ {
+ smallest = i;
+ for( j = i + 1; j < size; j++)
+ {
+ // if smallest > j
+ if(pOrder->compare(m_aMacabRecords->getRecord(smallest),
+ m_aMacabRecords->getRecord(j) ) > 0)
+ {
+ smallest = j;
+ }
+
+ }
+
+ if(smallest != i)
+ {
+ m_aMacabRecords->swap(i,smallest);
+ }
+ }
+
+}
+
+void MacabResultSet::setTableName(OUString const & _sTableName)
+{
+ m_sTableName = _sTableName;
+}
+
+void MacabResultSet::disposing()
+{
+ OPropertySetHelper::disposing();
+
+ ::osl::MutexGuard aGuard(m_aMutex);
+
+ m_xStatement.clear();
+ m_xMetaData.clear();
+}
+
+Any SAL_CALL MacabResultSet::queryInterface(const Type & rType)
+{
+ Any aRet = OPropertySetHelper::queryInterface(rType);
+ if (!aRet.hasValue())
+ aRet = MacabResultSet_BASE::queryInterface(rType);
+ return aRet;
+}
+
+void SAL_CALL MacabResultSet::acquire() noexcept
+{
+ MacabResultSet_BASE::acquire();
+}
+
+void SAL_CALL MacabResultSet::release() noexcept
+{
+ MacabResultSet_BASE::release();
+}
+
+Sequence< Type > SAL_CALL MacabResultSet::getTypes()
+{
+ OTypeCollection aTypes(
+ cppu::UnoType<css::beans::XMultiPropertySet>::get(),
+ cppu::UnoType<css::beans::XFastPropertySet>::get(),
+ cppu::UnoType<css::beans::XPropertySet>::get());
+
+ return comphelper::concatSequences(aTypes.getTypes(), MacabResultSet_BASE::getTypes());
+}
+
+css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL MacabResultSet::getPropertySetInfo( )
+{
+ return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper());
+}
+
+sal_Int32 SAL_CALL MacabResultSet::findColumn(const OUString& columnName)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+
+ // find the first column with the name columnName
+ Reference< XResultSetMetaData > xMeta = getMetaData();
+ sal_Int32 nLen = xMeta->getColumnCount();
+
+ for (sal_Int32 i = 1; i <= nLen; ++i)
+ {
+ if (xMeta->isCaseSensitive(i) ?
+ columnName == xMeta->getColumnName(i) :
+ columnName.equalsIgnoreAsciiCase(xMeta->getColumnName(i)))
+ return i;
+ }
+
+ ::dbtools::throwInvalidColumnException( columnName, *this );
+ assert(false);
+ return 0; // Never reached
+}
+
+OUString SAL_CALL MacabResultSet::getString(sal_Int32 columnIndex)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+
+ OUString aRet;
+ sal_Int32 nRecords = m_aMacabRecords->size();
+ m_bWasNull = true;
+
+ if (m_nRowPos != -1 && m_nRowPos != nRecords && m_xMetaData.is())
+ {
+ sal_Int32 nFieldNumber = m_xMetaData->fieldAtColumn(columnIndex);
+ macabfield *aField = m_aMacabRecords->getField(m_nRowPos,nFieldNumber);
+ if(aField != nullptr)
+ {
+ if(aField->type == kABStringProperty)
+ {
+ aRet = CFStringToOUString(static_cast<CFStringRef>(aField->value));
+ m_bWasNull = false;
+ }
+ }
+ }
+
+// Trigger an exception if m_bWasNull is true?
+ return aRet;
+}
+
+sal_Bool SAL_CALL MacabResultSet::getBoolean(sal_Int32)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+
+ ::dbtools::throwFunctionNotSupportedSQLException("getBoolean", nullptr);
+
+ return false;
+}
+
+sal_Int8 SAL_CALL MacabResultSet::getByte(sal_Int32)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+
+ ::dbtools::throwFunctionNotSupportedSQLException("getByte", nullptr);
+
+ return 0;
+}
+
+sal_Int16 SAL_CALL MacabResultSet::getShort(sal_Int32)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+
+ ::dbtools::throwFunctionNotSupportedSQLException("getShort", nullptr);
+
+ return 0;
+}
+
+sal_Int32 SAL_CALL MacabResultSet::getInt(sal_Int32 columnIndex)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+
+ sal_Int32 nRet = 0;
+ sal_Int32 nRecords = m_aMacabRecords->size();
+ m_bWasNull = true;
+
+ if (m_nRowPos != -1 && m_nRowPos != nRecords && m_xMetaData.is())
+ {
+ sal_Int32 nFieldNumber = m_xMetaData->fieldAtColumn(columnIndex);
+ macabfield *aField = m_aMacabRecords->getField(m_nRowPos,nFieldNumber);
+ if(aField != nullptr)
+ {
+ if(aField->type == kABIntegerProperty)
+ {
+ CFNumberType numberType = CFNumberGetType( static_cast<CFNumberRef>(aField->value) );
+ // m_bWasNull now becomes whether getting the value was successful
+ // Should we check for the wrong type here, e.g., a float or a 64 bit int?
+ m_bWasNull = !CFNumberGetValue(static_cast<CFNumberRef>(aField->value), numberType, &nRet);
+ }
+ }
+ }
+
+// Trigger an exception if m_bWasNull is true?
+ return nRet;
+}
+
+sal_Int64 SAL_CALL MacabResultSet::getLong(sal_Int32 columnIndex)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+
+ sal_Int64 nRet = 0;
+ sal_Int32 nRecords = m_aMacabRecords->size();
+ m_bWasNull = true;
+
+ if (m_nRowPos != -1 && m_nRowPos != nRecords && m_xMetaData.is())
+ {
+ sal_Int32 nFieldNumber = m_xMetaData->fieldAtColumn(columnIndex);
+ macabfield *aField = m_aMacabRecords->getField(m_nRowPos,nFieldNumber);
+ if(aField != nullptr)
+ {
+ if(aField->type == kABIntegerProperty)
+ {
+ CFNumberType numberType = CFNumberGetType( static_cast<CFNumberRef>(aField->value) );
+ // m_bWasNull now becomes whether getting the value was successful
+ // Should we check for the wrong type here, e.g., a float or a 32 bit int?
+ m_bWasNull = !CFNumberGetValue(static_cast<CFNumberRef>(aField->value), numberType, &nRet);
+ }
+ }
+ }
+
+// Trigger an exception if m_bWasNull is true?
+ return nRet;
+}
+
+float SAL_CALL MacabResultSet::getFloat(sal_Int32 columnIndex)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+
+ float nVal = 0;
+ sal_Int32 nRecords = m_aMacabRecords->size();
+ m_bWasNull = true;
+
+ if (m_nRowPos != -1 && m_nRowPos != nRecords && m_xMetaData.is())
+ {
+ sal_Int32 nFieldNumber = m_xMetaData->fieldAtColumn(columnIndex);
+ macabfield *aField = m_aMacabRecords->getField(m_nRowPos,nFieldNumber);
+ if(aField != nullptr)
+ {
+ if(aField->type == kABRealProperty)
+ {
+ CFNumberType numberType = CFNumberGetType( static_cast<CFNumberRef>(aField->value) );
+ // m_bWasNull now becomes whether getting the value was successful
+ // Should we check for the wrong type here, e.g., an int or a double?
+ m_bWasNull = !CFNumberGetValue(static_cast<CFNumberRef>(aField->value), numberType, &nVal);
+ }
+ }
+ }
+
+// Trigger an exception if m_bWasNull is true?
+ return nVal;
+}
+
+double SAL_CALL MacabResultSet::getDouble(sal_Int32 columnIndex)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+
+ double nVal = 0;
+ sal_Int32 nRecords = m_aMacabRecords->size();
+ m_bWasNull = true;
+
+ if (m_nRowPos != -1 && m_nRowPos != nRecords && m_xMetaData.is())
+ {
+ sal_Int32 nFieldNumber = m_xMetaData->fieldAtColumn(columnIndex);
+ macabfield *aField = m_aMacabRecords->getField(m_nRowPos,nFieldNumber);
+ if(aField != nullptr)
+ {
+ if(aField->type == kABRealProperty)
+ {
+ CFNumberType numberType = CFNumberGetType( static_cast<CFNumberRef>(aField->value) );
+ // m_bWasNull now becomes whether getting the value was successful
+ // Should we check for the wrong type here, e.g., an int or a float?
+ m_bWasNull = !CFNumberGetValue(static_cast<CFNumberRef>(aField->value), numberType, &nVal);
+ }
+ }
+ }
+
+// Trigger an exception if m_bWasNull is true?
+ return nVal;
+}
+
+Sequence< sal_Int8 > SAL_CALL MacabResultSet::getBytes(sal_Int32)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+
+ ::dbtools::throwFunctionNotSupportedSQLException("getBytes", nullptr);
+
+ return Sequence< sal_Int8 >();
+}
+
+Date SAL_CALL MacabResultSet::getDate(sal_Int32)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+
+ ::dbtools::throwFunctionNotSupportedSQLException("getDate", nullptr);
+
+ Date aRet;
+ return aRet;
+}
+
+Time SAL_CALL MacabResultSet::getTime(sal_Int32)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+
+ ::dbtools::throwFunctionNotSupportedSQLException("getTime", nullptr);
+
+ css::util::Time nRet;
+ return nRet;
+}
+
+DateTime SAL_CALL MacabResultSet::getTimestamp(sal_Int32 columnIndex)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+
+ DateTime nRet;
+ sal_Int32 nRecords = m_aMacabRecords->size();
+ m_bWasNull = true;
+
+ if (m_nRowPos != -1 && m_nRowPos != nRecords && m_xMetaData.is())
+ {
+ sal_Int32 nFieldNumber = m_xMetaData->fieldAtColumn(columnIndex);
+ macabfield *aField = m_aMacabRecords->getField(m_nRowPos,nFieldNumber);
+ if(aField != nullptr)
+ {
+ if(aField->type == kABDateProperty)
+ {
+ nRet = CFDateToDateTime(static_cast<CFDateRef>(aField->value));
+ m_bWasNull = false;
+ }
+ }
+ }
+
+// Trigger an exception if m_bWasNull is true?
+ return nRet;
+}
+
+Reference< XInputStream > SAL_CALL MacabResultSet::getBinaryStream(sal_Int32)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+
+ ::dbtools::throwFunctionNotSupportedSQLException("getBinaryStream", nullptr);
+
+ return nullptr;
+}
+
+Reference< XInputStream > SAL_CALL MacabResultSet::getCharacterStream(sal_Int32)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+
+ ::dbtools::throwFunctionNotSupportedSQLException("getCharacterStream", nullptr);
+
+ return nullptr;
+}
+
+Any SAL_CALL MacabResultSet::getObject(sal_Int32, const Reference< css::container::XNameAccess >&)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+
+ ::dbtools::throwFunctionNotSupportedSQLException("getObject", nullptr);
+
+ return Any();
+}
+
+Reference< XRef > SAL_CALL MacabResultSet::getRef(sal_Int32)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+
+ ::dbtools::throwFunctionNotSupportedSQLException("getRef", nullptr);
+
+ return nullptr;
+}
+
+Reference< XBlob > SAL_CALL MacabResultSet::getBlob(sal_Int32)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+
+ ::dbtools::throwFunctionNotSupportedSQLException("getBlob", nullptr);
+
+ return nullptr;
+}
+
+Reference< XClob > SAL_CALL MacabResultSet::getClob(sal_Int32)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+
+ ::dbtools::throwFunctionNotSupportedSQLException("getClob", nullptr);
+
+ return nullptr;
+}
+
+Reference< XArray > SAL_CALL MacabResultSet::getArray(sal_Int32)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+
+ ::dbtools::throwFunctionNotSupportedSQLException("getArray", nullptr);
+
+ return nullptr;
+}
+
+Reference< XResultSetMetaData > SAL_CALL MacabResultSet::getMetaData()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+
+ if (!m_xMetaData.is())
+ m_xMetaData = new MacabResultSetMetaData(m_xStatement->getOwnConnection(), m_sTableName);
+
+ Reference< XResultSetMetaData > xMetaData = m_xMetaData;
+ return xMetaData;
+}
+
+sal_Bool SAL_CALL MacabResultSet::isBeforeFirst()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+
+ if (m_nRowPos == -1)
+ return true;
+
+ return false;
+}
+
+sal_Bool SAL_CALL MacabResultSet::isAfterLast()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+
+ sal_Int32 nRecords = m_aMacabRecords->size();
+ if (m_nRowPos == nRecords)
+ return true;
+
+ return false;
+}
+
+sal_Bool SAL_CALL MacabResultSet::isFirst()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+
+ if (m_nRowPos == 0)
+ return true;
+
+ return false;
+}
+
+sal_Bool SAL_CALL MacabResultSet::isLast()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+
+ sal_Int32 nRecords = m_aMacabRecords->size();
+ if (m_nRowPos == nRecords - 1)
+ return true;
+
+ return false;
+}
+
+void SAL_CALL MacabResultSet::beforeFirst()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+
+ // move before the first row
+ m_nRowPos = -1;
+}
+
+void SAL_CALL MacabResultSet::afterLast()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+
+ // move after the last row
+ sal_Int32 nRecords = m_aMacabRecords->size();
+ m_nRowPos = nRecords;
+}
+
+void SAL_CALL MacabResultSet::close()
+{
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+ }
+ dispose();
+}
+
+sal_Bool SAL_CALL MacabResultSet::first()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+
+ sal_Int32 nRecords = m_aMacabRecords->size();
+ if (nRecords == 0)
+ return false;
+
+ m_nRowPos = 0;
+ return true;
+}
+
+sal_Bool SAL_CALL MacabResultSet::last()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+
+ sal_Int32 nRecords = m_aMacabRecords->size();
+ if (nRecords == 0)
+ return false;
+
+ m_nRowPos = nRecords - 1;
+ return true;
+}
+
+sal_Int32 SAL_CALL MacabResultSet::getRow()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+
+ return m_nRowPos;
+}
+
+sal_Bool SAL_CALL MacabResultSet::absolute(sal_Int32 row)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+
+ sal_Int32 nRecords = m_aMacabRecords->size();
+ if (row <= -1 ||
+ row >= nRecords)
+ return false;
+
+ m_nRowPos = row;
+ return true;
+}
+
+sal_Bool SAL_CALL MacabResultSet::relative(sal_Int32 row)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+
+ return absolute(m_nRowPos + row);
+}
+
+sal_Bool SAL_CALL MacabResultSet::next()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+
+ return absolute(m_nRowPos + 1);
+}
+
+sal_Bool SAL_CALL MacabResultSet::previous()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+
+ return absolute(m_nRowPos - 1);
+}
+
+Reference< XInterface > SAL_CALL MacabResultSet::getStatement()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+
+ Reference< XStatement > xStatement = m_xStatement;
+ return xStatement;
+}
+
+sal_Bool SAL_CALL MacabResultSet::rowDeleted()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+
+ return false;
+}
+
+sal_Bool SAL_CALL MacabResultSet::rowInserted()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+
+ return false;
+}
+
+sal_Bool SAL_CALL MacabResultSet::rowUpdated()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+
+ return false;
+}
+
+sal_Bool SAL_CALL MacabResultSet::wasNull()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+
+ return m_bWasNull;
+}
+
+void SAL_CALL MacabResultSet::cancel()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+}
+
+void SAL_CALL MacabResultSet::clearWarnings()
+{
+}
+
+Any SAL_CALL MacabResultSet::getWarnings()
+{
+ return Any();
+}
+
+void SAL_CALL MacabResultSet::insertRow()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+
+ // you only have to implement this if you want to insert new rows
+}
+
+void SAL_CALL MacabResultSet::updateRow()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+
+ // only when you allow updates
+}
+
+void SAL_CALL MacabResultSet::deleteRow()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+}
+
+void SAL_CALL MacabResultSet::cancelRowUpdates()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+}
+
+void SAL_CALL MacabResultSet::moveToInsertRow()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+
+ // only when you allow inserts
+}
+
+void SAL_CALL MacabResultSet::moveToCurrentRow()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+}
+
+void SAL_CALL MacabResultSet::updateNull(sal_Int32)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+}
+
+void SAL_CALL MacabResultSet::updateBoolean(sal_Int32, sal_Bool)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+}
+
+void SAL_CALL MacabResultSet::updateByte(sal_Int32, sal_Int8)
+{
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+ ::osl::MutexGuard aGuard( m_aMutex );
+}
+
+void SAL_CALL MacabResultSet::updateShort(sal_Int32, sal_Int16)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+}
+
+void SAL_CALL MacabResultSet::updateInt(sal_Int32, sal_Int32)
+{
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+ ::osl::MutexGuard aGuard( m_aMutex );
+}
+
+void SAL_CALL MacabResultSet::updateLong(sal_Int32, sal_Int64)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+}
+
+void SAL_CALL MacabResultSet::updateFloat(sal_Int32, float)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+}
+
+void SAL_CALL MacabResultSet::updateDouble(sal_Int32, double)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+}
+
+void SAL_CALL MacabResultSet::updateString(sal_Int32, const OUString&)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+}
+
+void SAL_CALL MacabResultSet::updateBytes(sal_Int32, const Sequence< sal_Int8 >&)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+}
+
+void SAL_CALL MacabResultSet::updateDate(sal_Int32, const Date&)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+}
+
+void SAL_CALL MacabResultSet::updateTime(sal_Int32, const css::util::Time&)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+}
+
+void SAL_CALL MacabResultSet::updateTimestamp(sal_Int32, const DateTime&)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+}
+
+void SAL_CALL MacabResultSet::updateBinaryStream(sal_Int32, const Reference< XInputStream >&, sal_Int32)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+}
+
+void SAL_CALL MacabResultSet::updateCharacterStream(sal_Int32, const Reference< XInputStream >&, sal_Int32)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+}
+
+void SAL_CALL MacabResultSet::refreshRow()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+}
+
+void SAL_CALL MacabResultSet::updateObject(sal_Int32, const Any&)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+}
+
+void SAL_CALL MacabResultSet::updateNumericObject(sal_Int32, const Any&, sal_Int32)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+}
+
+// XRowLocate
+Any SAL_CALL MacabResultSet::getBookmark()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+
+ sal_Int32 nRecords = m_aMacabRecords->size();
+
+ if (m_nRowPos != -1 && m_nRowPos != nRecords)
+ {
+ macabfield *uidField = m_aMacabRecords->getField(m_nRowPos,u"UID");
+ if(uidField != nullptr)
+ {
+ if(uidField->type == kABStringProperty)
+ {
+ return Any(CFStringToOUString( static_cast<CFStringRef>(uidField->value) ));
+ }
+ }
+ }
+ return Any();
+}
+
+sal_Bool SAL_CALL MacabResultSet::moveToBookmark(const Any& bookmark)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+
+ OUString sBookmark = comphelper::getString(bookmark);
+ sal_Int32 nRecords = m_aMacabRecords->size();
+
+ for (sal_Int32 nRow = 0; nRow < nRecords; nRow++)
+ {
+ macabfield *uidField = m_aMacabRecords->getField(m_nRowPos,u"UID");
+ if(uidField != nullptr)
+ {
+ if(uidField->type == kABStringProperty)
+ {
+ OUString sUniqueIdentifier = CFStringToOUString( static_cast<CFStringRef>(uidField->value) );
+ if (sUniqueIdentifier == sBookmark)
+ {
+ m_nRowPos = nRow;
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
+
+sal_Bool SAL_CALL MacabResultSet::moveRelativeToBookmark(const Any& bookmark, sal_Int32 rows)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+
+ sal_Int32 nRowSave = m_nRowPos;
+
+ if (moveToBookmark(bookmark))
+ {
+ sal_Int32 nRecords = m_aMacabRecords->size();
+
+ m_nRowPos += rows;
+
+ if (-1 < m_nRowPos && m_nRowPos < nRecords)
+ return true;
+ }
+
+ m_nRowPos = nRowSave;
+ return false;
+}
+
+sal_Int32 SAL_CALL MacabResultSet::compareBookmarks(const Any& firstItem, const Any& secondItem)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+
+ OUString sFirst = comphelper::getString(firstItem);
+ OUString sSecond = comphelper::getString(secondItem);
+
+ if (sFirst < sSecond)
+ return CompareBookmark::LESS;
+ if (sFirst > sSecond)
+ return CompareBookmark::GREATER;
+ return CompareBookmark::EQUAL;
+}
+
+sal_Bool SAL_CALL MacabResultSet::hasOrderedBookmarks()
+{
+ return false;
+}
+
+sal_Int32 SAL_CALL MacabResultSet::hashBookmark(const Any& bookmark)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+
+ OUString sBookmark = comphelper::getString(bookmark);
+
+ return sBookmark.hashCode();
+}
+
+// XDeleteRows
+Sequence< sal_Int32 > SAL_CALL MacabResultSet::deleteRows(const Sequence< Any >&)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+
+ return Sequence< sal_Int32 >();
+}
+
+IPropertyArrayHelper* MacabResultSet::createArrayHelper() const
+{
+ return new OPropertyArrayHelper
+ {
+ {
+ {
+ ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_CURSORNAME),
+ PROPERTY_ID_CURSORNAME,
+ cppu::UnoType<OUString>::get(),
+ PropertyAttribute::READONLY
+ },
+ {
+ ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHDIRECTION),
+ PROPERTY_ID_FETCHDIRECTION,
+ cppu::UnoType<sal_Int32>::get(),
+ 0
+ },
+ {
+ ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHSIZE),
+ PROPERTY_ID_FETCHSIZE,
+ cppu::UnoType<sal_Int32>::get(),
+ 0
+ },
+ {
+ ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISBOOKMARKABLE),
+ PROPERTY_ID_ISBOOKMARKABLE,
+ cppu::UnoType<bool>::get(),
+ PropertyAttribute::READONLY
+ },
+ {
+ ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETCONCURRENCY),
+ PROPERTY_ID_RESULTSETCONCURRENCY,
+ cppu::UnoType<sal_Int32>::get(),
+ PropertyAttribute::READONLY
+ },
+ {
+ ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETTYPE),
+ PROPERTY_ID_RESULTSETTYPE,
+ cppu::UnoType<sal_Int32>::get(),
+ PropertyAttribute::READONLY
+ }
+ }
+ };
+}
+
+IPropertyArrayHelper & MacabResultSet::getInfoHelper()
+{
+ return *getArrayHelper();
+}
+
+sal_Bool MacabResultSet::convertFastPropertyValue(
+ Any &,
+ Any &,
+ sal_Int32 nHandle,
+ const Any& )
+{
+ switch (nHandle)
+ {
+ case PROPERTY_ID_ISBOOKMARKABLE:
+ case PROPERTY_ID_CURSORNAME:
+ case PROPERTY_ID_RESULTSETCONCURRENCY:
+ case PROPERTY_ID_RESULTSETTYPE:
+ throw css::lang::IllegalArgumentException();
+ break;
+ case PROPERTY_ID_FETCHDIRECTION:
+ case PROPERTY_ID_FETCHSIZE:
+ default:
+ ;
+ }
+ return false;
+}
+
+void MacabResultSet::setFastPropertyValue_NoBroadcast(
+ sal_Int32 nHandle,
+ const Any& )
+{
+ switch (nHandle)
+ {
+ case PROPERTY_ID_ISBOOKMARKABLE:
+ case PROPERTY_ID_CURSORNAME:
+ case PROPERTY_ID_RESULTSETCONCURRENCY:
+ case PROPERTY_ID_RESULTSETTYPE:
+ throw Exception("cannot set prop " + OUString::number(nHandle), nullptr);
+ break;
+ case PROPERTY_ID_FETCHDIRECTION:
+ break;
+ case PROPERTY_ID_FETCHSIZE:
+ break;
+ default:
+ ;
+ }
+}
+
+void MacabResultSet::getFastPropertyValue(
+ Any& _rValue,
+ sal_Int32 nHandle) const
+{
+ switch (nHandle)
+ {
+ case PROPERTY_ID_ISBOOKMARKABLE:
+ _rValue <<= false;
+ break;
+ case PROPERTY_ID_CURSORNAME:
+ case PROPERTY_ID_RESULTSETCONCURRENCY:
+ case PROPERTY_ID_RESULTSETTYPE:
+ case PROPERTY_ID_FETCHDIRECTION:
+ case PROPERTY_ID_FETCHSIZE:
+ ;
+ }
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/macab/MacabResultSet.hxx b/connectivity/source/drivers/macab/MacabResultSet.hxx
new file mode 100644
index 0000000000..306ef562d3
--- /dev/null
+++ b/connectivity/source/drivers/macab/MacabResultSet.hxx
@@ -0,0 +1,213 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "MacabStatement.hxx"
+#include "MacabResultSetMetaData.hxx"
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
+#include <com/sun/star/sdbc/XColumnLocate.hpp>
+#include <com/sun/star/sdbc/XResultSetUpdate.hpp>
+#include <com/sun/star/sdbc/XRowUpdate.hpp>
+#include <com/sun/star/sdbcx/XRowLocate.hpp>
+#include <com/sun/star/sdbcx/XDeleteRows.hpp>
+#include <cppuhelper/compbase.hxx>
+#include <cppuhelper/basemutex.hxx>
+
+namespace connectivity::macab
+{
+ /*
+ ** MacabResultSet
+ */
+ typedef ::cppu::WeakComponentImplHelper< css::sdbc::XResultSet,
+ css::sdbc::XRow,
+ css::sdbc::XResultSetMetaDataSupplier,
+ css::util::XCancellable,
+ css::sdbc::XWarningsSupplier,
+ css::sdbc::XResultSetUpdate,
+ css::sdbc::XRowUpdate,
+ css::sdbcx::XRowLocate,
+ css::sdbcx::XDeleteRows,
+ css::sdbc::XCloseable,
+ css::sdbc::XColumnLocate,
+ css::lang::XServiceInfo> MacabResultSet_BASE;
+ class MacabRecords;
+
+ class MacabResultSet : public cppu::BaseMutex,
+ public MacabResultSet_BASE,
+ public ::cppu::OPropertySetHelper,
+ public comphelper::OPropertyArrayUsageHelper<MacabResultSet>
+ {
+ protected:
+ ::rtl::Reference< MacabCommonStatement > m_xStatement; // the statement that has created this result set
+ ::rtl::Reference< MacabResultSetMetaData > m_xMetaData; // the description of the columns in this result set
+ MacabRecords * m_aMacabRecords; // address book entries matching the query
+ sal_Int32 m_nRowPos; // the current row within the result set
+ bool m_bWasNull; // last entry retrieved from this result set was NULL
+ OUString m_sTableName;
+
+ // OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override;
+
+ // OPropertySetHelper
+ virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override;
+
+ virtual sal_Bool SAL_CALL convertFastPropertyValue(
+ css::uno::Any & rConvertedValue,
+ css::uno::Any & rOldValue,
+ sal_Int32 nHandle,
+ const css::uno::Any& rValue) override;
+ virtual void SAL_CALL setFastPropertyValue_NoBroadcast(
+ sal_Int32 nHandle,
+ const css::uno::Any& rValue) override;
+ virtual void SAL_CALL getFastPropertyValue(
+ css::uno::Any& rValue,
+ sal_Int32 nHandle) const override;
+
+ // you can't delete objects of this type
+ virtual ~MacabResultSet() override;
+
+ public:
+ DECLARE_SERVICE_INFO();
+
+ explicit MacabResultSet(MacabCommonStatement *pStmt);
+
+ css::uno::Reference< css::uno::XInterface > operator *()
+ {
+ return css::uno::Reference< css::uno::XInterface >(*static_cast<MacabResultSet_BASE*>(this));
+ }
+
+ void allMacabRecords();
+ void someMacabRecords(const class MacabCondition *pCondition);
+ void sortMacabRecords(const class MacabOrder *pOrder);
+ void setTableName(const OUString& _sTableName);
+
+ // ::cppu::OComponentHelper
+ virtual void SAL_CALL disposing() override;
+
+ // XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+
+ // XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override;
+
+ // XPropertySet
+ virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override;
+
+ // XResultSet
+ virtual sal_Bool SAL_CALL isBeforeFirst( ) override;
+ virtual sal_Bool SAL_CALL isAfterLast( ) override;
+ virtual sal_Bool SAL_CALL isFirst( ) override;
+ virtual sal_Bool SAL_CALL isLast( ) override;
+ virtual void SAL_CALL beforeFirst( ) override;
+ virtual void SAL_CALL afterLast( ) override;
+ virtual sal_Bool SAL_CALL first( ) override;
+ virtual sal_Bool SAL_CALL last( ) override;
+ virtual sal_Int32 SAL_CALL getRow( ) override;
+ virtual sal_Bool SAL_CALL absolute( sal_Int32 row ) override;
+ virtual sal_Bool SAL_CALL relative( sal_Int32 rows ) override;
+ virtual sal_Bool SAL_CALL next( ) override;
+ virtual sal_Bool SAL_CALL previous( ) override;
+ virtual void SAL_CALL refreshRow( ) override;
+ virtual sal_Bool SAL_CALL rowUpdated( ) override;
+ virtual sal_Bool SAL_CALL rowInserted( ) override;
+ virtual sal_Bool SAL_CALL rowDeleted( ) override;
+ virtual css::uno::Reference< css::uno::XInterface > SAL_CALL getStatement( ) override;
+
+ // XRow
+ virtual sal_Bool SAL_CALL wasNull( ) override;
+ virtual OUString SAL_CALL getString( sal_Int32 columnIndex ) override;
+ virtual sal_Bool SAL_CALL getBoolean( sal_Int32 columnIndex ) override;
+ virtual sal_Int8 SAL_CALL getByte( sal_Int32 columnIndex ) override;
+ virtual sal_Int16 SAL_CALL getShort( sal_Int32 columnIndex ) override;
+ virtual sal_Int32 SAL_CALL getInt( sal_Int32 columnIndex ) override;
+ virtual sal_Int64 SAL_CALL getLong( sal_Int32 columnIndex ) override;
+ virtual float SAL_CALL getFloat( sal_Int32 columnIndex ) override;
+ virtual double SAL_CALL getDouble( sal_Int32 columnIndex ) override;
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getBytes( sal_Int32 columnIndex ) override;
+ virtual css::util::Date SAL_CALL getDate( sal_Int32 columnIndex ) override;
+ virtual css::util::Time SAL_CALL getTime( sal_Int32 columnIndex ) override;
+ virtual css::util::DateTime SAL_CALL getTimestamp( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getBinaryStream( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getCharacterStream( sal_Int32 columnIndex ) override;
+ virtual css::uno::Any SAL_CALL getObject( sal_Int32 columnIndex, const css::uno::Reference< css::container::XNameAccess >& typeMap ) override;
+ virtual css::uno::Reference< css::sdbc::XRef > SAL_CALL getRef( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XBlob > SAL_CALL getBlob( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XClob > SAL_CALL getClob( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XArray > SAL_CALL getArray( sal_Int32 columnIndex ) override;
+
+ // XResultSetMetaDataSupplier
+ virtual css::uno::Reference< css::sdbc::XResultSetMetaData > SAL_CALL getMetaData( ) override;
+
+ // XCancellable
+ virtual void SAL_CALL cancel( ) override;
+
+ // XCloseable
+ virtual void SAL_CALL close( ) override;
+
+ // XWarningsSupplier
+ virtual css::uno::Any SAL_CALL getWarnings( ) override;
+ virtual void SAL_CALL clearWarnings( ) override;
+
+ // XResultSetUpdate
+ virtual void SAL_CALL insertRow( ) override;
+ virtual void SAL_CALL updateRow( ) override;
+ virtual void SAL_CALL deleteRow( ) override;
+ virtual void SAL_CALL cancelRowUpdates( ) override;
+ virtual void SAL_CALL moveToInsertRow( ) override;
+ virtual void SAL_CALL moveToCurrentRow( ) override;
+ // XRowUpdate
+ virtual void SAL_CALL updateNull( sal_Int32 columnIndex ) override;
+ virtual void SAL_CALL updateBoolean( sal_Int32 columnIndex, sal_Bool x ) override;
+ virtual void SAL_CALL updateByte( sal_Int32 columnIndex, sal_Int8 x ) override;
+ virtual void SAL_CALL updateShort( sal_Int32 columnIndex, sal_Int16 x ) override;
+ virtual void SAL_CALL updateInt( sal_Int32 columnIndex, sal_Int32 x ) override;
+ virtual void SAL_CALL updateLong( sal_Int32 columnIndex, sal_Int64 x ) override;
+ virtual void SAL_CALL updateFloat( sal_Int32 columnIndex, float x ) override;
+ virtual void SAL_CALL updateDouble( sal_Int32 columnIndex, double x ) override;
+ virtual void SAL_CALL updateString( sal_Int32 columnIndex, const OUString& x ) override;
+ virtual void SAL_CALL updateBytes( sal_Int32 columnIndex, const css::uno::Sequence< sal_Int8 >& x ) override;
+ virtual void SAL_CALL updateDate( sal_Int32 columnIndex, const css::util::Date& x ) override;
+ virtual void SAL_CALL updateTime( sal_Int32 columnIndex, const css::util::Time& x ) override;
+ virtual void SAL_CALL updateTimestamp( sal_Int32 columnIndex, const css::util::DateTime& x ) override;
+ virtual void SAL_CALL updateBinaryStream( sal_Int32 columnIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override;
+ virtual void SAL_CALL updateCharacterStream( sal_Int32 columnIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override;
+ virtual void SAL_CALL updateObject( sal_Int32 columnIndex, const css::uno::Any& x ) override;
+ virtual void SAL_CALL updateNumericObject( sal_Int32 columnIndex, const css::uno::Any& x, sal_Int32 scale ) override;
+
+ // XColumnLocate
+ virtual sal_Int32 SAL_CALL findColumn( const OUString& columnName ) override;
+
+ // XRowLocate
+ virtual css::uno::Any SAL_CALL getBookmark( ) override;
+ virtual sal_Bool SAL_CALL moveToBookmark( const css::uno::Any& bookmark ) override;
+ virtual sal_Bool SAL_CALL moveRelativeToBookmark( const css::uno::Any& bookmark, sal_Int32 rows ) override;
+ virtual sal_Int32 SAL_CALL compareBookmarks( const css::uno::Any& firstItem, const css::uno::Any& secondItem ) override;
+ virtual sal_Bool SAL_CALL hasOrderedBookmarks( ) override;
+ virtual sal_Int32 SAL_CALL hashBookmark( const css::uno::Any& bookmark ) override;
+
+ // XDeleteRows
+ virtual css::uno::Sequence< sal_Int32 > SAL_CALL deleteRows( const css::uno::Sequence< css::uno::Any >& rows ) override;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/macab/MacabResultSetMetaData.cxx b/connectivity/source/drivers/macab/MacabResultSetMetaData.cxx
new file mode 100644
index 0000000000..e08d92cfce
--- /dev/null
+++ b/connectivity/source/drivers/macab/MacabResultSetMetaData.cxx
@@ -0,0 +1,216 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include "MacabResultSetMetaData.hxx"
+#include "MacabHeader.hxx"
+#include "MacabRecords.hxx"
+#include "MacabAddressBook.hxx"
+#include "macabutilities.hxx"
+#include <connectivity/dbexception.hxx>
+#include <strings.hrc>
+
+using namespace connectivity::macab;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::sdbc;
+
+MacabResultSetMetaData::MacabResultSetMetaData(MacabConnection* _pConnection, OUString const & _sTableName)
+ : m_pConnection(_pConnection),
+ m_sTableName(_sTableName),
+ m_aMacabFields()
+{
+}
+
+MacabResultSetMetaData::~MacabResultSetMetaData()
+{
+}
+
+void MacabResultSetMetaData::setMacabFields(const ::rtl::Reference<connectivity::OSQLColumns> &xColumns)
+{
+ static constexpr OUStringLiteral aName = u"Name";
+ MacabRecords *aRecords;
+ MacabHeader *aHeader;
+
+ aRecords = m_pConnection->getAddressBook()->getMacabRecords(m_sTableName);
+
+ // In case, somehow, we don't have anything with the name m_sTableName
+ if(aRecords == nullptr)
+ {
+ impl_throwError(STR_NO_TABLE);
+ }
+
+ aHeader = aRecords->getHeader();
+
+ for (const auto& rxColumn : *xColumns)
+ {
+ OUString aFieldName;
+ sal_uInt32 nFieldNumber;
+
+ rxColumn->getPropertyValue(aName) >>= aFieldName;
+ nFieldNumber = aHeader->getColumnNumber(aFieldName);
+ m_aMacabFields.push_back(nFieldNumber);
+ }
+
+}
+
+sal_Int32 SAL_CALL MacabResultSetMetaData::getColumnDisplaySize(sal_Int32 /* column */)
+{
+ // For now, all columns are the same size.
+ return 50;
+}
+
+sal_Int32 SAL_CALL MacabResultSetMetaData::getColumnType(sal_Int32 column)
+{
+ MacabRecords *aRecords;
+ MacabHeader *aHeader;
+ macabfield *aField;
+
+ aRecords = m_pConnection->getAddressBook()->getMacabRecords(m_sTableName);
+
+ // In case, somehow, we don't have anything with the name m_sTableName
+ if(aRecords == nullptr)
+ {
+ impl_throwError(STR_NO_TABLE);
+ }
+
+ aHeader = aRecords->getHeader();
+ aField = aHeader->get(column-1);
+
+ if(aField == nullptr)
+ {
+ ::dbtools::throwInvalidIndexException(*this);
+ return -1;
+ }
+
+ return ABTypeToDataType(aField->type);
+}
+
+sal_Int32 SAL_CALL MacabResultSetMetaData::getColumnCount()
+{
+ return m_aMacabFields.size();
+}
+
+sal_Bool SAL_CALL MacabResultSetMetaData::isCaseSensitive(sal_Int32)
+{
+ return true;
+}
+
+OUString SAL_CALL MacabResultSetMetaData::getSchemaName(sal_Int32)
+{
+ return OUString();
+}
+
+OUString SAL_CALL MacabResultSetMetaData::getColumnName(sal_Int32 column)
+{
+ sal_uInt32 nFieldNumber = m_aMacabFields[column - 1];
+ MacabRecords *aRecords;
+ MacabHeader *aHeader;
+
+ aRecords = m_pConnection->getAddressBook()->getMacabRecords(m_sTableName);
+
+ // In case, somehow, we don't have anything with the name m_sTableName
+ if(aRecords == nullptr)
+ {
+ impl_throwError(STR_NO_TABLE);
+ }
+
+ aHeader = aRecords->getHeader();
+ OUString aName = aHeader->getString(nFieldNumber);
+
+ return aName;
+}
+
+OUString SAL_CALL MacabResultSetMetaData::getTableName(sal_Int32)
+{
+ return m_sTableName;
+}
+
+OUString SAL_CALL MacabResultSetMetaData::getCatalogName(sal_Int32)
+{
+ return OUString();
+}
+
+OUString SAL_CALL MacabResultSetMetaData::getColumnTypeName(sal_Int32)
+{
+ return OUString();
+}
+
+OUString SAL_CALL MacabResultSetMetaData::getColumnLabel(sal_Int32)
+{
+ return OUString();
+}
+
+OUString SAL_CALL MacabResultSetMetaData::getColumnServiceName(sal_Int32)
+{
+ return OUString();
+}
+
+sal_Bool SAL_CALL MacabResultSetMetaData::isCurrency(sal_Int32)
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabResultSetMetaData::isAutoIncrement(sal_Int32)
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabResultSetMetaData::isSigned(sal_Int32)
+{
+ return false;
+}
+
+sal_Int32 SAL_CALL MacabResultSetMetaData::getPrecision(sal_Int32)
+{
+ return 0;
+}
+
+sal_Int32 SAL_CALL MacabResultSetMetaData::getScale(sal_Int32)
+{
+ return 0;
+}
+
+sal_Int32 SAL_CALL MacabResultSetMetaData::isNullable(sal_Int32)
+{
+ return sal_Int32(true);
+}
+
+sal_Bool SAL_CALL MacabResultSetMetaData::isSearchable(sal_Int32)
+{
+ return true;
+}
+
+sal_Bool SAL_CALL MacabResultSetMetaData::isReadOnly(sal_Int32)
+{
+ return true;
+}
+
+sal_Bool SAL_CALL MacabResultSetMetaData::isDefinitelyWritable(sal_Int32)
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabResultSetMetaData::isWritable(sal_Int32)
+{
+ return false;
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/macab/MacabResultSetMetaData.hxx b/connectivity/source/drivers/macab/MacabResultSetMetaData.hxx
new file mode 100644
index 0000000000..b82088154c
--- /dev/null
+++ b/connectivity/source/drivers/macab/MacabResultSetMetaData.hxx
@@ -0,0 +1,80 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "MacabConnection.hxx"
+#include <connectivity/CommonTools.hxx>
+#include <com/sun/star/sdbc/XResultSetMetaData.hpp>
+#include <cppuhelper/implbase.hxx>
+#include <rtl/ref.hxx>
+
+namespace connectivity::macab
+{
+ /*
+ ** MacabResultSetMetaData
+ */
+ class MacabResultSetMetaData : public ::cppu::WeakImplHelper< css::sdbc::XResultSetMetaData>
+ {
+ MacabConnection* m_pConnection;
+ OUString m_sTableName;
+ std::vector<sal_Int32> m_aMacabFields; // for each selected column, contains the number
+ // of the corresponding AddressBook field
+
+ protected:
+ virtual ~MacabResultSetMetaData() override;
+
+ public:
+ MacabResultSetMetaData(MacabConnection* _pConnection, OUString const & _sTableName);
+
+ // avoid ambiguous cast error from the compiler
+ operator css::uno::Reference< css::sdbc::XResultSetMetaData > () noexcept
+ { return this; }
+
+ /// @throws css::sdbc::SQLException
+ void setMacabFields(
+ const ::rtl::Reference<connectivity::OSQLColumns> &xColumns);
+ sal_uInt32 fieldAtColumn(sal_Int32 columnIndex) const
+ { return m_aMacabFields[columnIndex - 1]; }
+
+ virtual sal_Int32 SAL_CALL getColumnCount( ) override;
+ virtual sal_Bool SAL_CALL isAutoIncrement( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isCaseSensitive( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isSearchable( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isCurrency( sal_Int32 column ) override;
+ virtual sal_Int32 SAL_CALL isNullable( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isSigned( sal_Int32 column ) override;
+ virtual sal_Int32 SAL_CALL getColumnDisplaySize( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getColumnLabel( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getColumnName( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getSchemaName( sal_Int32 column ) override;
+ virtual sal_Int32 SAL_CALL getPrecision( sal_Int32 column ) override;
+ virtual sal_Int32 SAL_CALL getScale( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getTableName( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getCatalogName( sal_Int32 column ) override;
+ virtual sal_Int32 SAL_CALL getColumnType( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getColumnTypeName( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isReadOnly( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isWritable( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isDefinitelyWritable( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getColumnServiceName( sal_Int32 column ) override;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/macab/MacabStatement.cxx b/connectivity/source/drivers/macab/MacabStatement.cxx
new file mode 100644
index 0000000000..95b922ce6b
--- /dev/null
+++ b/connectivity/source/drivers/macab/MacabStatement.cxx
@@ -0,0 +1,631 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include "MacabStatement.hxx"
+#include <sqlbison.hxx>
+#include "MacabConnection.hxx"
+#include "MacabAddressBook.hxx"
+#include "MacabDriver.hxx"
+#include "MacabResultSet.hxx"
+#include "MacabResultSetMetaData.hxx"
+#include "macabcondition.hxx"
+#include "macaborder.hxx"
+#include "macabutilities.hxx"
+#include <TConnection.hxx>
+#include <cppuhelper/typeprovider.hxx>
+#include <connectivity/dbexception.hxx>
+#include <resource/sharedresources.hxx>
+#include <rtl/ref.hxx>
+#include <strings.hrc>
+
+using namespace connectivity::macab;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::sdbc;
+using namespace com::sun::star::sdbcx;
+using namespace com::sun::star::container;
+using namespace com::sun::star::io;
+using namespace com::sun::star::util;
+
+namespace connectivity::macab
+{
+ void impl_throwError(TranslateId pErrorId)
+ {
+ ::connectivity::SharedResources aResources;
+ const OUString sError( aResources.getResourceString(pErrorId) );
+ ::dbtools::throwGenericSQLException(sError,nullptr);
+ }
+}
+
+IMPLEMENT_SERVICE_INFO(MacabStatement, "com.sun.star.sdbc.drivers.MacabStatement", "com.sun.star.sdbc.Statement");
+
+MacabCommonStatement::MacabCommonStatement(MacabConnection* _pConnection )
+ : MacabCommonStatement_BASE(m_aMutex),
+ OPropertySetHelper(rBHelper),
+ m_aParser(_pConnection->getDriver()->getComponentContext()),
+ m_aSQLIterator(_pConnection, _pConnection->createCatalog()->getTables(), m_aParser ),
+ m_pParseTree(nullptr),
+ m_pConnection(_pConnection)
+{
+ m_pConnection->acquire();
+}
+
+MacabCommonStatement::~MacabCommonStatement()
+{
+}
+
+void MacabCommonStatement::resetParameters() const
+{
+}
+
+void MacabCommonStatement::getNextParameter(OUString &) const
+{
+ impl_throwError(STR_PARA_ONLY_PREPARED);
+}
+
+MacabCondition *MacabCommonStatement::analyseWhereClause(const OSQLParseNode *pParseNode) const
+{
+ if (pParseNode->count() == 3)
+ {
+ const OSQLParseNode *pLeft = pParseNode->getChild(0),
+ *pMiddle = pParseNode->getChild(1),
+ *pRight = pParseNode->getChild(2);
+
+ // WHERE ( ... ) ?
+ if (SQL_ISPUNCTUATION(pLeft, "(") && SQL_ISPUNCTUATION(pRight, ")"))
+ {
+ return analyseWhereClause(pMiddle);
+ }
+ else if (SQL_ISRULE(pParseNode, comparison_predicate))
+ {
+ if (pLeft->isToken() && pRight->isToken())
+ {
+ switch (pMiddle->getNodeType())
+ {
+ case SQLNodeType::Equal:
+ // WHERE 0 = 1
+ return new MacabConditionConstant(pLeft->getTokenValue() == pRight->getTokenValue());
+
+ case SQLNodeType::NotEqual:
+ // WHERE 0 <> 1
+ // (might not be correct SQL... don't care, handling anyway)
+ return new MacabConditionConstant(pLeft->getTokenValue() != pRight->getTokenValue());
+
+ default:
+ break;
+ }
+ }
+ else if (SQL_ISRULE(pLeft, column_ref))
+ {
+ OUString sColumnName,
+ sTableRange;
+
+ m_aSQLIterator.getColumnRange(pLeft, sColumnName, sTableRange);
+
+ if (pRight->isToken() || SQL_ISRULE(pRight, parameter))
+ {
+ OUString sMatchString;
+
+ if (pRight->isToken()) // WHERE Name = 'Doe'
+ sMatchString = pRight->getTokenValue();
+ else if (SQL_ISRULE(pRight, parameter)) // WHERE Name = ?
+ getNextParameter(sMatchString);
+
+ switch (pMiddle->getNodeType())
+ {
+ case SQLNodeType::Equal:
+ // WHERE Name = 'Smith'
+ return new MacabConditionEqual(m_pHeader, sColumnName, sMatchString);
+
+ case SQLNodeType::NotEqual:
+ // WHERE Name <> 'Jones'
+ return new MacabConditionDifferent(m_pHeader, sColumnName, sMatchString);
+
+ default:
+ break;
+ }
+ }
+ }
+ }
+ else if (SQL_ISRULE(pParseNode, search_condition))
+ {
+ if (SQL_ISTOKEN(pMiddle, OR))
+ {
+ // WHERE Name = 'Smith' OR Name = 'Jones'
+ return new MacabConditionOr(
+ analyseWhereClause(pLeft),
+ analyseWhereClause(pRight));
+ }
+ }
+ else if (SQL_ISRULE(pParseNode, boolean_term))
+ {
+ if (SQL_ISTOKEN(pMiddle, AND))
+ {
+ // WHERE Name = 'Smith' AND "Given Name" = 'Peter'
+ return new MacabConditionAnd(
+ analyseWhereClause(pLeft),
+ analyseWhereClause(pRight));
+ }
+ }
+ }
+ else if (SQL_ISRULE(pParseNode, test_for_null) || SQL_ISRULE(pParseNode, like_predicate))
+ {
+ const OSQLParseNode *pLeft = pParseNode->getChild(0);
+ const OSQLParseNode* pPart2 = pParseNode->getChild(1);
+ const OSQLParseNode *pMiddleLeft = pPart2->getChild(0),
+ *pMiddleRight = pPart2->getChild(1),
+ *pRight = pPart2->getChild(2);
+
+ if (SQL_ISRULE(pParseNode, test_for_null))
+ {
+ if (SQL_ISRULE(pLeft, column_ref) &&
+ SQL_ISTOKEN(pMiddleLeft, IS) &&
+ SQL_ISTOKEN(pRight, NULL))
+ {
+ OUString sColumnName,
+ sTableRange;
+
+ m_aSQLIterator.getColumnRange(pLeft, sColumnName, sTableRange);
+
+ if (SQL_ISTOKEN(pMiddleRight, NOT))
+ {
+ // WHERE "Mobile Phone" IS NOT NULL
+ return new MacabConditionNotNull(m_pHeader, sColumnName);
+ }
+ else
+ {
+ // WHERE "Mobile Phone" IS NULL
+ return new MacabConditionNull(m_pHeader, sColumnName);
+ }
+ }
+ }
+ else if (SQL_ISRULE(pParseNode, like_predicate))
+ {
+ if (SQL_ISRULE(pLeft, column_ref))
+ {
+ OUString sColumnName,
+ sTableRange;
+
+ m_aSQLIterator.getColumnRange(pLeft, sColumnName, sTableRange);
+
+ if (pMiddleRight->isToken() || SQL_ISRULE(pMiddleRight, parameter))
+ {
+ OUString sMatchString;
+
+ if (pMiddleRight->isToken()) // WHERE Name LIKE 'Sm%'
+ sMatchString = pMiddleRight->getTokenValue();
+ else if (SQL_ISRULE(pMiddleRight, parameter)) // WHERE Name LIKE ?
+ getNextParameter(sMatchString);
+
+ return new MacabConditionSimilar(m_pHeader, sColumnName, sMatchString);
+ }
+ }
+ }
+ }
+ impl_throwError(STR_QUERY_TOO_COMPLEX);
+ // Unreachable:
+ OSL_ASSERT(false);
+ return nullptr;
+}
+
+MacabOrder *MacabCommonStatement::analyseOrderByClause(const OSQLParseNode *pParseNode) const
+{
+ if (SQL_ISRULE(pParseNode, ordering_spec_commalist))
+ {
+ MacabComplexOrder *list = new MacabComplexOrder();
+ sal_uInt32 n = pParseNode->count();
+
+ // Iterate through the ordering columns
+ for (sal_uInt32 i = 0; i < n; i++)
+ {
+ list->addOrder
+ (analyseOrderByClause(pParseNode->getChild(i)));
+ }
+
+ return list;
+ }
+ else if (SQL_ISRULE(pParseNode, ordering_spec))
+ {
+ if (pParseNode->count() == 2)
+ {
+ OSQLParseNode* pColumnRef = pParseNode->getChild(0);
+ OSQLParseNode* pAscendingDescending = pParseNode->getChild(1);
+
+ if (SQL_ISRULE(pColumnRef, column_ref))
+ {
+ if (pColumnRef->count() == 3)
+ pColumnRef = pColumnRef->getChild(2);
+
+ if (pColumnRef->count() == 1)
+ {
+ OUString sColumnName =
+ pColumnRef->getChild(0)->getTokenValue();
+ bool bAscending =
+ !SQL_ISTOKEN(pAscendingDescending, DESC);
+
+ return new MacabSimpleOrder(m_pHeader, sColumnName, bAscending);
+ }
+ }
+ }
+ }
+ impl_throwError(STR_QUERY_TOO_COMPLEX);
+ // Unreachable:
+ OSL_ASSERT(false);
+ return nullptr;
+}
+
+OUString MacabCommonStatement::getTableName() const
+{
+ const OSQLTables& xTabs = m_aSQLIterator.getTables();
+
+ if( xTabs.empty() )
+ return OUString();
+
+ // can only deal with one table at a time
+ if(xTabs.size() > 1 || m_aSQLIterator.hasErrors() )
+ return OUString();
+
+ return xTabs.begin()->first;
+}
+
+void MacabCommonStatement::setMacabFields(MacabResultSet *pResult) const
+{
+ ::rtl::Reference<connectivity::OSQLColumns> xColumns; // selected columns
+ rtl::Reference<MacabResultSetMetaData> pMeta; // meta information - holds the list of AddressBook fields
+
+ xColumns = m_aSQLIterator.getSelectColumns();
+ if (!xColumns.is())
+ {
+ ::connectivity::SharedResources aResources;
+ const OUString sError( aResources.getResourceString(
+ STR_INVALID_COLUMN_SELECTION
+ ) );
+ ::dbtools::throwGenericSQLException(sError,nullptr);
+ }
+ pMeta = static_cast<MacabResultSetMetaData *>(pResult->getMetaData().get());
+ pMeta->setMacabFields(xColumns);
+}
+
+void MacabCommonStatement::selectRecords(MacabResultSet *pResult) const
+{
+ const OSQLParseNode *pParseNode;
+
+ pParseNode = m_aSQLIterator.getWhereTree();
+ if (pParseNode != nullptr)
+ {
+ if (SQL_ISRULE(pParseNode, where_clause))
+ {
+ resetParameters();
+ pParseNode = pParseNode->getChild(1);
+ MacabCondition *pCondition = analyseWhereClause(pParseNode);
+ if (pCondition->isAlwaysTrue())
+ pResult->allMacabRecords();
+ else
+ pResult->someMacabRecords(pCondition);
+ delete pCondition;
+ return;
+ }
+ }
+
+ // no WHERE clause: get all rows
+ pResult->allMacabRecords();
+}
+
+void MacabCommonStatement::sortRecords(MacabResultSet *pResult) const
+{
+ const OSQLParseNode *pParseNode;
+
+ pParseNode = m_aSQLIterator.getOrderTree();
+ if (pParseNode != nullptr)
+ {
+ if (SQL_ISRULE(pParseNode, opt_order_by_clause))
+ {
+ pParseNode = pParseNode->getChild(2);
+ MacabOrder *pOrder = analyseOrderByClause(pParseNode);
+ pResult->sortMacabRecords(pOrder);
+ delete pOrder;
+ }
+ }
+}
+
+Any SAL_CALL MacabCommonStatement::queryInterface( const Type & rType )
+{
+ Any aRet = MacabCommonStatement_BASE::queryInterface(rType);
+ if (!aRet.hasValue())
+ aRet = OPropertySetHelper::queryInterface(rType);
+ return aRet;
+}
+
+Sequence< Type > SAL_CALL MacabCommonStatement::getTypes( )
+{
+ ::cppu::OTypeCollection aTypes( cppu::UnoType<XMultiPropertySet>::get(),
+ cppu::UnoType<XFastPropertySet>::get(),
+ cppu::UnoType<XPropertySet>::get());
+
+ return comphelper::concatSequences(aTypes.getTypes(),MacabCommonStatement_BASE::getTypes());
+}
+
+void SAL_CALL MacabCommonStatement::cancel( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ checkDisposed(rBHelper.bDisposed);
+ // cancel the current sql statement
+}
+
+void SAL_CALL MacabCommonStatement::close( )
+{
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(rBHelper.bDisposed);
+
+ }
+ dispose();
+}
+
+sal_Bool SAL_CALL MacabCommonStatement::execute(
+ const OUString& sql )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(rBHelper.bDisposed);
+
+ Reference< XResultSet > xRS = executeQuery(sql);
+
+ return xRS.is();
+}
+
+Reference< XResultSet > SAL_CALL MacabCommonStatement::executeQuery(
+ const OUString& sql )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(rBHelper.bDisposed);
+
+ rtl::Reference<MacabResultSet> pResult = new MacabResultSet(this);
+ OUString aErr;
+
+ m_pParseTree = m_aParser.parseTree(aErr, sql).release();
+ if (m_pParseTree == nullptr)
+ throw SQLException(aErr, *this, aErr, 0, Any());
+
+ m_aSQLIterator.setParseTree(m_pParseTree);
+ m_aSQLIterator.traverseAll();
+ switch (m_aSQLIterator.getStatementType())
+ {
+ case OSQLStatementType::Select:
+ {
+ OUString sTableName = getTableName(); // FROM which table ?
+ if (sTableName.getLength() != 0) // a match
+ {
+ MacabRecords *aRecords;
+ aRecords = m_pConnection->getAddressBook()->getMacabRecords(sTableName);
+
+ // In case, somehow, we don't have anything with the name m_sTableName
+ if(aRecords == nullptr)
+ {
+ impl_throwError(STR_NO_TABLE);
+ }
+ else
+ {
+ m_pHeader = aRecords->getHeader();
+
+ pResult->setTableName(sTableName);
+
+ setMacabFields(pResult.get()); // SELECT which columns ?
+ selectRecords(pResult.get()); // WHERE which condition ?
+ sortRecords(pResult.get()); // ORDER BY which columns ?
+ }
+// To be continued: DISTINCT
+// etc...
+ }
+ }
+ break;
+
+ default:
+// To be continued: UPDATE
+// DELETE
+// etc...
+ impl_throwError(STR_QUERY_TOO_COMPLEX);
+ }
+
+ m_xResultSet = Reference<XResultSet>(pResult);
+ return pResult;
+}
+
+Reference< XConnection > SAL_CALL MacabCommonStatement::getConnection( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(rBHelper.bDisposed);
+
+ // just return our connection here
+ return m_pConnection;
+}
+
+sal_Int32 SAL_CALL MacabCommonStatement::executeUpdate( const OUString& )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(rBHelper.bDisposed);
+
+ // the return values gives information about how many rows are affected by executing the sql statement
+ return 0;
+}
+
+Any SAL_CALL MacabCommonStatement::getWarnings( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(rBHelper.bDisposed);
+
+ return Any(m_aLastWarning);
+}
+
+void SAL_CALL MacabCommonStatement::clearWarnings( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(rBHelper.bDisposed);
+
+ m_aLastWarning = SQLWarning();
+}
+
+::cppu::IPropertyArrayHelper* MacabCommonStatement::createArrayHelper( ) const
+{
+ // this properties are defined by the service statement
+ // they must be in alphabetic order
+ return new ::cppu::OPropertyArrayHelper
+ {
+ {
+ {
+ ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_CURSORNAME),
+ PROPERTY_ID_CURSORNAME,
+ cppu::UnoType<OUString>::get(),
+ 0
+ },
+ {
+ ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ESCAPEPROCESSING),
+ PROPERTY_ID_ESCAPEPROCESSING,
+ cppu::UnoType<bool>::get(),
+ 0
+ },
+ {
+ ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHDIRECTION),
+ PROPERTY_ID_FETCHDIRECTION,
+ cppu::UnoType<sal_Int32>::get(),
+ 0
+ },
+ {
+ ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHSIZE),
+ PROPERTY_ID_FETCHSIZE,
+ cppu::UnoType<sal_Int32>::get(),
+ 0
+ },
+ {
+ ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_MAXFIELDSIZE),
+ PROPERTY_ID_MAXFIELDSIZE,
+ cppu::UnoType<sal_Int32>::get(),
+ 0
+ },
+ {
+ ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_MAXROWS),
+ PROPERTY_ID_MAXROWS,
+ cppu::UnoType<sal_Int32>::get(),
+ 0
+ },
+ {
+ ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_QUERYTIMEOUT),
+ PROPERTY_ID_QUERYTIMEOUT,
+ cppu::UnoType<sal_Int32>::get(),
+ 0
+ },
+ {
+ ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETCONCURRENCY),
+ PROPERTY_ID_RESULTSETCONCURRENCY,
+ cppu::UnoType<sal_Int32>::get(),
+ 0
+ },
+ {
+ ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETTYPE),
+ PROPERTY_ID_RESULTSETTYPE,
+ cppu::UnoType<sal_Int32>::get(),
+ 0
+ },
+ {
+ ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_USEBOOKMARKS),
+ PROPERTY_ID_USEBOOKMARKS,
+ cppu::UnoType<bool>::get(),
+ 0
+ }
+ }
+ };
+}
+
+::cppu::IPropertyArrayHelper & MacabCommonStatement::getInfoHelper()
+{
+ return *getArrayHelper();
+}
+
+sal_Bool MacabCommonStatement::convertFastPropertyValue(
+ Any &,
+ Any &,
+ sal_Int32,
+ const Any&)
+{
+ // here we have to try to convert
+ return false;
+}
+
+void MacabCommonStatement::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,const Any&)
+{
+ // set the value to whatever is necessary
+ switch (nHandle)
+ {
+ case PROPERTY_ID_QUERYTIMEOUT:
+ case PROPERTY_ID_MAXFIELDSIZE:
+ case PROPERTY_ID_MAXROWS:
+ case PROPERTY_ID_CURSORNAME:
+ case PROPERTY_ID_RESULTSETCONCURRENCY:
+ case PROPERTY_ID_RESULTSETTYPE:
+ case PROPERTY_ID_FETCHDIRECTION:
+ case PROPERTY_ID_FETCHSIZE:
+ case PROPERTY_ID_ESCAPEPROCESSING:
+ case PROPERTY_ID_USEBOOKMARKS:
+ default:
+ ;
+ }
+}
+
+void MacabCommonStatement::getFastPropertyValue(Any&,sal_Int32 nHandle) const
+{
+ switch (nHandle)
+ {
+ case PROPERTY_ID_QUERYTIMEOUT:
+ case PROPERTY_ID_MAXFIELDSIZE:
+ case PROPERTY_ID_MAXROWS:
+ case PROPERTY_ID_CURSORNAME:
+ case PROPERTY_ID_RESULTSETCONCURRENCY:
+ case PROPERTY_ID_RESULTSETTYPE:
+ case PROPERTY_ID_FETCHDIRECTION:
+ case PROPERTY_ID_FETCHSIZE:
+ case PROPERTY_ID_ESCAPEPROCESSING:
+ case PROPERTY_ID_USEBOOKMARKS:
+ default:
+ ;
+ }
+}
+
+void SAL_CALL MacabCommonStatement::acquire() noexcept
+{
+ MacabCommonStatement_BASE::acquire();
+}
+
+void SAL_CALL MacabCommonStatement::release() noexcept
+{
+ MacabCommonStatement_BASE::release();
+}
+
+Reference< css::beans::XPropertySetInfo > SAL_CALL MacabCommonStatement::getPropertySetInfo( )
+{
+ return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper());
+}
+
+MacabStatement::MacabStatement(MacabConnection* _pConnection)
+ : MacabStatement_BASE(_pConnection)
+{
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/macab/MacabStatement.hxx b/connectivity/source/drivers/macab/MacabStatement.hxx
new file mode 100644
index 0000000000..700a895c0a
--- /dev/null
+++ b/connectivity/source/drivers/macab/MacabStatement.hxx
@@ -0,0 +1,169 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "MacabConnection.hxx"
+#include "MacabHeader.hxx"
+#include <connectivity/sqliterator.hxx>
+#include <connectivity/sqlparse.hxx>
+#include <com/sun/star/sdbc/XStatement.hpp>
+#include <com/sun/star/sdbc/SQLWarning.hpp>
+#include <com/sun/star/util/XCancellable.hpp>
+#include <cppuhelper/compbase.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/basemutex.hxx>
+#include <comphelper/proparrhlp.hxx>
+
+namespace connectivity::macab
+{
+ typedef ::cppu::WeakComponentImplHelper< css::sdbc::XStatement,
+ css::sdbc::XWarningsSupplier,
+ css::util::XCancellable,
+ css::sdbc::XCloseable> MacabCommonStatement_BASE;
+
+
+ // Class MacabCommonStatement
+ // is a base class for the normal statement and for the prepared statement
+
+ class MacabCommonStatement : public cppu::BaseMutex,
+ public MacabCommonStatement_BASE,
+ public ::cppu::OPropertySetHelper,
+ public comphelper::OPropertyArrayUsageHelper<MacabCommonStatement>
+
+ {
+ css::sdbc::SQLWarning m_aLastWarning;
+
+ protected:
+ connectivity::OSQLParser m_aParser;
+ connectivity::OSQLParseTreeIterator m_aSQLIterator;
+ connectivity::OSQLParseNode* m_pParseTree;
+ MacabConnection* m_pConnection; // The owning Connection object
+ MacabHeader* m_pHeader; // The header of the address book on which to run queries (provided by m_pConnection)
+ css::uno::WeakReference< css::sdbc::XResultSet> m_xResultSet; // The last ResultSet created
+
+
+ protected:
+ /// @throws css::sdbc::SQLException
+ class MacabCondition *analyseWhereClause(
+ const OSQLParseNode *pParseNode) const;
+ /// @throws css::sdbc::SQLException
+ class MacabOrder *analyseOrderByClause(
+ const OSQLParseNode *pParseNode) const;
+ OUString getTableName( ) const;
+ /// @throws css::sdbc::SQLException
+ void setMacabFields(class MacabResultSet *pResult) const;
+ /// @throws css::sdbc::SQLException
+ void selectRecords(MacabResultSet *pResult) const;
+ /// @throws css::sdbc::SQLException
+ void sortRecords(MacabResultSet *pResult) const;
+
+ // OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper() const override;
+
+ // OPropertySetHelper
+ virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override;
+ virtual sal_Bool SAL_CALL convertFastPropertyValue(
+ css::uno::Any & rConvertedValue,
+ css::uno::Any & rOldValue,
+ sal_Int32 nHandle,
+ const css::uno::Any& rValue) override;
+ virtual void SAL_CALL setFastPropertyValue_NoBroadcast(
+ sal_Int32 nHandle,
+ const css::uno::Any& rValue) override;
+ virtual void SAL_CALL getFastPropertyValue(
+ css::uno::Any& rValue,
+ sal_Int32 nHandle) const override;
+
+ /// @throws css::sdbc::SQLException
+ virtual void resetParameters() const;
+ /// @throws css::sdbc::SQLException
+ virtual void getNextParameter(OUString &rParameter) const;
+ virtual ~MacabCommonStatement() override;
+
+ public:
+ using MacabCommonStatement_BASE::rBHelper;
+
+ explicit MacabCommonStatement(MacabConnection *_pConnection);
+ using MacabCommonStatement_BASE::operator css::uno::Reference< css::uno::XInterface >;
+
+ // OComponentHelper
+ using MacabCommonStatement_BASE::disposing;
+
+ // XInterface
+ virtual void SAL_CALL release() noexcept override;
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual css::uno::Any SAL_CALL queryInterface(
+ const css::uno::Type & rType
+ ) override;
+
+ // XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes(
+ ) override;
+
+ // XPropertySet
+ virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo(
+ ) override;
+
+ // XStatement
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL executeQuery(
+ const OUString& sql ) override;
+ virtual sal_Int32 SAL_CALL executeUpdate(
+ const OUString& sql ) override;
+ virtual sal_Bool SAL_CALL execute(
+ const OUString& sql ) override;
+ virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL getConnection(
+ ) override;
+
+ // XWarningsSupplier
+ virtual css::uno::Any SAL_CALL getWarnings(
+ ) override;
+ virtual void SAL_CALL clearWarnings(
+ ) override;
+
+ // XCancellable
+ virtual void SAL_CALL cancel(
+ ) override;
+
+ // XCloseable
+ virtual void SAL_CALL close(
+ ) override;
+
+ // other methods
+ MacabConnection* getOwnConnection() const { return m_pConnection; }
+ };
+
+
+ // Class MacabStatement
+
+ typedef ::cppu::ImplInheritanceHelper<
+ MacabCommonStatement, css::lang::XServiceInfo > MacabStatement_BASE;
+
+ class MacabStatement : public MacabStatement_BASE
+ {
+ protected:
+ virtual ~MacabStatement() override { }
+
+ public:
+ explicit MacabStatement(MacabConnection* _pConnection);
+ DECLARE_SERVICE_INFO();
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/macab/MacabTable.cxx b/connectivity/source/drivers/macab/MacabTable.cxx
new file mode 100644
index 0000000000..1628cd297b
--- /dev/null
+++ b/connectivity/source/drivers/macab/MacabTable.cxx
@@ -0,0 +1,86 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include "MacabTable.hxx"
+#include "MacabTables.hxx"
+#include "MacabColumns.hxx"
+#include "MacabCatalog.hxx"
+#include <com/sun/star/sdbc/XRow.hpp>
+
+using namespace connectivity::macab;
+using namespace connectivity;
+using namespace ::comphelper;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+
+
+MacabTable::MacabTable( sdbcx::OCollection* _pTables, MacabConnection* _pConnection)
+ : MacabTable_TYPEDEF(_pTables, true),
+ m_pConnection(_pConnection)
+{
+ construct();
+}
+
+MacabTable::MacabTable( sdbcx::OCollection* _pTables,
+ MacabConnection* _pConnection,
+ const OUString& Name,
+ const OUString& Type,
+ const OUString& Description ,
+ const OUString& SchemaName,
+ const OUString& CatalogName
+ ) : MacabTable_TYPEDEF(_pTables,true,
+ Name,
+ Type,
+ Description,
+ SchemaName,
+ CatalogName),
+ m_pConnection(_pConnection)
+{
+ construct();
+}
+
+void MacabTable::refreshColumns()
+{
+ ::std::vector< OUString> aVector;
+
+ if (!isNew())
+ {
+ Reference< XResultSet > xResult = m_pConnection->getMetaData()->getColumns(
+ Any(), m_SchemaName, m_Name, "%");
+
+ if (xResult.is())
+ {
+ Reference< XRow > xRow(xResult, UNO_QUERY);
+ while (xResult->next())
+ aVector.push_back(xRow->getString(4));
+ }
+ }
+
+ if (m_xColumns)
+ m_xColumns->reFill(aVector);
+ else
+ m_xColumns.reset(new MacabColumns(this, m_aMutex, aVector));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/macab/MacabTable.hxx b/connectivity/source/drivers/macab/MacabTable.hxx
new file mode 100644
index 0000000000..897d589cc6
--- /dev/null
+++ b/connectivity/source/drivers/macab/MacabTable.hxx
@@ -0,0 +1,54 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "MacabConnection.hxx"
+#include <connectivity/sdbcx/VTable.hxx>
+
+namespace connectivity::macab
+{
+ typedef connectivity::sdbcx::OTable MacabTable_TYPEDEF;
+
+ class MacabTable : public MacabTable_TYPEDEF
+ {
+ css::uno::Reference< css::sdbc::XDatabaseMetaData > m_xMetaData;
+ MacabConnection* m_pConnection;
+
+ public:
+ MacabTable( sdbcx::OCollection* _pTables, MacabConnection* _pConnection);
+ MacabTable( sdbcx::OCollection* _pTables,
+ MacabConnection* _pConnection,
+ const OUString& Name,
+ const OUString& Type,
+ const OUString& Description = OUString(),
+ const OUString& SchemaName = OUString(),
+ const OUString& CatalogName = OUString()
+ );
+
+ MacabConnection* getConnection() { return m_pConnection;}
+
+ virtual void refreshColumns() override;
+
+ OUString const & getTableName() const { return m_Name; }
+ OUString const & getSchema() const { return m_SchemaName; }
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/macab/MacabTables.cxx b/connectivity/source/drivers/macab/MacabTables.cxx
new file mode 100644
index 0000000000..e7149d2646
--- /dev/null
+++ b/connectivity/source/drivers/macab/MacabTables.cxx
@@ -0,0 +1,80 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include "MacabTables.hxx"
+#include "MacabTable.hxx"
+#include "MacabCatalog.hxx"
+#include "MacabConnection.hxx"
+#include <comphelper/types.hxx>
+#include <com/sun/star/sdbc/XRow.hpp>
+
+using namespace connectivity::macab;
+using namespace connectivity;
+using namespace ::comphelper;
+using namespace ::cppu;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+
+sdbcx::ObjectType MacabTables::createObject(const OUString& _rName)
+{
+ OUString aName,aSchema;
+ aSchema = "%";
+ aName = _rName;
+
+ Sequence< OUString > aTypes { "%" };
+
+ Reference< XResultSet > xResult = m_xMetaData->getTables(Any(), aSchema, aName, aTypes);
+
+ sdbcx::ObjectType xRet;
+ if (xResult.is())
+ {
+ Reference< XRow > xRow(xResult, UNO_QUERY);
+ if (xResult->next()) // there can be only one table with this name
+ {
+ xRet = new MacabTable(
+ this,
+ static_cast<MacabCatalog&>(m_rParent).getConnection(),
+ aName,
+ xRow->getString(4),
+ xRow->getString(5),
+ "");
+ }
+ }
+ ::comphelper::disposeComponent(xResult);
+
+ return xRet;
+}
+
+void MacabTables::impl_refresh( )
+{
+ static_cast<MacabCatalog&>(m_rParent).refreshTables();
+}
+
+void MacabTables::disposing()
+{
+ m_xMetaData.clear();
+ OCollection::disposing();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/macab/MacabTables.hxx b/connectivity/source/drivers/macab/MacabTables.hxx
new file mode 100644
index 0000000000..0b0d841b7a
--- /dev/null
+++ b/connectivity/source/drivers/macab/MacabTables.hxx
@@ -0,0 +1,49 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <connectivity/sdbcx/VCollection.hxx>
+#include <com/sun/star/sdbc/XDatabaseMetaData.hpp>
+
+namespace connectivity::macab
+{
+ class MacabTables : public sdbcx::OCollection
+ {
+ css::uno::Reference< css::sdbc::XDatabaseMetaData > m_xMetaData;
+
+ protected:
+ virtual sdbcx::ObjectType createObject(const OUString& _rName) override;
+ virtual void impl_refresh() override;
+
+ public:
+ MacabTables(
+ const css::uno::Reference< css::sdbc::XDatabaseMetaData >& _rMetaData,
+ ::cppu::OWeakObject& _rParent,
+ ::osl::Mutex& _rMutex,
+ const ::std::vector< OUString> &_rVector)
+ : sdbcx::OCollection(_rParent,true,_rMutex,_rVector),
+ m_xMetaData(_rMetaData)
+ { }
+
+ virtual void disposing() override;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/macab/macab1.component b/connectivity/source/drivers/macab/macab1.component
new file mode 100644
index 0000000000..7cbc0d9c87
--- /dev/null
+++ b/connectivity/source/drivers/macab/macab1.component
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ -->
+
+<component loader="com.sun.star.loader.SharedLibrary" environment="@CPPU_ENV@"
+ xmlns="http://openoffice.org/2010/uno-components">
+ <implementation name="com.sun.star.comp.sdbc.macab.Driver"
+ constructor="connectivity_MacabDriver_get_implementation">
+ <service name="com.sun.star.sdbc.Driver"/>
+ </implementation>
+</component>
diff --git a/connectivity/source/drivers/macab/macabcondition.cxx b/connectivity/source/drivers/macab/macabcondition.cxx
new file mode 100644
index 0000000000..41e087b2c4
--- /dev/null
+++ b/connectivity/source/drivers/macab/macabcondition.cxx
@@ -0,0 +1,244 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include "macabcondition.hxx"
+#include "MacabHeader.hxx"
+#include "MacabRecord.hxx"
+#include <connectivity/CommonTools.hxx>
+
+using namespace ::connectivity::macab;
+using namespace ::com::sun::star::sdbc;
+
+MacabCondition::~MacabCondition()
+{
+}
+
+MacabConditionConstant::MacabConditionConstant(const bool bValue)
+ : MacabCondition(),
+ m_bValue(bValue)
+{
+}
+
+bool MacabConditionConstant::isAlwaysTrue() const
+{
+ return m_bValue;
+}
+
+bool MacabConditionConstant::isAlwaysFalse() const
+{
+ return !m_bValue;
+}
+
+bool MacabConditionConstant::eval(const MacabRecord *) const
+{
+ return m_bValue;
+}
+
+MacabConditionColumn::MacabConditionColumn(
+ const MacabHeader *header, std::u16string_view sColumnName)
+ : MacabCondition(),
+ m_nFieldNumber(header->getColumnNumber(sColumnName))
+{
+}
+
+bool MacabConditionColumn::isAlwaysTrue() const
+{
+ // Sometimes true, sometimes false
+ return false;
+}
+
+bool MacabConditionColumn::isAlwaysFalse() const
+{
+ // Sometimes true, sometimes false
+ return false;
+}
+
+MacabConditionNull::MacabConditionNull(const MacabHeader *header, std::u16string_view sColumnName)
+ : MacabConditionColumn(header, sColumnName)
+{
+}
+
+bool MacabConditionNull::eval(const MacabRecord *aRecord) const
+{
+ macabfield *aValue = aRecord->get(m_nFieldNumber);
+
+ if(aValue == nullptr)
+ return true;
+ else if(aValue->value == nullptr)
+ return true;
+ else
+ return false;
+}
+
+MacabConditionNotNull::MacabConditionNotNull(
+ const MacabHeader *header, std::u16string_view sColumnName)
+ : MacabConditionColumn(header, sColumnName)
+{
+}
+
+bool MacabConditionNotNull::eval(const MacabRecord *aRecord) const
+{
+ macabfield *aValue = aRecord->get(m_nFieldNumber);
+
+ if(aValue == nullptr)
+ return false;
+ else if(aValue->value == nullptr)
+ return false;
+ else
+ return true;
+}
+
+MacabConditionCompare::MacabConditionCompare(const MacabHeader *header, std::u16string_view sColumnName, const OUString &sMatchString)
+ : MacabConditionColumn(header, sColumnName),
+ m_sMatchString(sMatchString)
+{
+}
+
+MacabConditionEqual::MacabConditionEqual(const MacabHeader *header, std::u16string_view sColumnName, const OUString &sMatchString)
+ : MacabConditionCompare(header, sColumnName, sMatchString)
+{
+}
+
+bool MacabConditionEqual::eval(const MacabRecord *aRecord) const
+{
+ macabfield *aValue = aRecord->get(m_nFieldNumber);
+
+ if(aValue == nullptr)
+ return false;
+
+ macabfield *aValue2 = MacabRecord::createMacabField(m_sMatchString,aValue->type);
+
+ if(aValue2 == nullptr)
+ return false;
+
+ sal_Int32 nReturn = MacabRecord::compareFields(aValue, aValue2);
+
+ delete aValue2;
+ return nReturn == 0;
+}
+
+MacabConditionDifferent::MacabConditionDifferent(const MacabHeader *header, std::u16string_view sColumnName, const OUString &sMatchString)
+ : MacabConditionCompare(header, sColumnName, sMatchString)
+{
+}
+
+bool MacabConditionDifferent::eval(const MacabRecord *aRecord) const
+{
+ macabfield *aValue = aRecord->get(m_nFieldNumber);
+
+ if(aValue == nullptr)
+ return false;
+
+ macabfield *aValue2 = MacabRecord::createMacabField(m_sMatchString,aValue->type);
+
+ if(aValue2 == nullptr)
+ return false;
+
+ sal_Int32 nReturn = MacabRecord::compareFields(aValue, aValue2);
+
+ delete aValue2;
+ return nReturn != 0;
+}
+
+MacabConditionSimilar::MacabConditionSimilar(const MacabHeader *header, std::u16string_view sColumnName, const OUString &sMatchString)
+ : MacabConditionCompare(header, sColumnName, sMatchString)
+{
+}
+
+bool MacabConditionSimilar::eval(const MacabRecord *aRecord) const
+{
+ macabfield *aValue = aRecord->get(m_nFieldNumber);
+
+ if(aValue == nullptr)
+ return false;
+
+ OUString sName = MacabRecord::fieldToString(aValue);
+
+ return match(m_sMatchString, sName, '\0');
+}
+
+MacabConditionBoolean::MacabConditionBoolean(MacabCondition *pLeft, MacabCondition *pRight)
+ : MacabCondition(),
+ m_pLeft(pLeft),
+ m_pRight(pRight)
+{
+}
+
+MacabConditionBoolean::~MacabConditionBoolean()
+{
+ delete m_pLeft;
+ delete m_pRight;
+}
+
+MacabConditionOr::MacabConditionOr(MacabCondition *pLeft, MacabCondition *pRight)
+ : MacabConditionBoolean(pLeft, pRight)
+{
+}
+
+bool MacabConditionOr::isAlwaysTrue() const
+{
+ return m_pLeft->isAlwaysTrue() || m_pRight->isAlwaysTrue();
+}
+
+bool MacabConditionOr::isAlwaysFalse() const
+{
+ return m_pLeft->isAlwaysFalse() && m_pRight->isAlwaysFalse();
+}
+
+bool MacabConditionOr::eval(const MacabRecord *aRecord) const
+{
+ // We avoid evaluating terms as much as we can
+ if (m_pLeft->isAlwaysTrue() || m_pRight->isAlwaysTrue()) return true;
+ if (m_pLeft->isAlwaysFalse() && m_pRight->isAlwaysFalse()) return false;
+
+ if (m_pLeft->eval(aRecord)) return true;
+ if (m_pRight->eval(aRecord)) return true;
+
+ return false;
+}
+
+MacabConditionAnd::MacabConditionAnd(MacabCondition *pLeft, MacabCondition *pRight)
+ : MacabConditionBoolean(pLeft, pRight)
+{
+}
+
+bool MacabConditionAnd::isAlwaysTrue() const
+{
+ return m_pLeft->isAlwaysTrue() && m_pRight->isAlwaysTrue();
+}
+
+bool MacabConditionAnd::isAlwaysFalse() const
+{
+ return m_pLeft->isAlwaysFalse() || m_pRight->isAlwaysFalse();
+}
+
+bool MacabConditionAnd::eval(const MacabRecord *aRecord) const
+{
+ // We avoid evaluating terms as much as we can
+ if (m_pLeft->isAlwaysFalse() || m_pRight->isAlwaysFalse()) return false;
+ if (m_pLeft->isAlwaysTrue() && m_pRight->isAlwaysTrue()) return true;
+
+ if (!m_pLeft->eval(aRecord)) return false;
+ if (!m_pRight->eval(aRecord)) return false;
+
+ return true;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/macab/macabcondition.hxx b/connectivity/source/drivers/macab/macabcondition.hxx
new file mode 100644
index 0000000000..32e7b7071c
--- /dev/null
+++ b/connectivity/source/drivers/macab/macabcondition.hxx
@@ -0,0 +1,165 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <string_view>
+
+#include "MacabHeader.hxx"
+#include "MacabRecord.hxx"
+
+#include <connectivity/dbexception.hxx>
+
+namespace connectivity::macab
+{
+
+class MacabCondition
+{
+ public:
+ virtual ~MacabCondition();
+ virtual bool isAlwaysTrue() const = 0;
+ virtual bool isAlwaysFalse() const = 0;
+ virtual bool eval(const MacabRecord *aRecord) const = 0;
+};
+
+class MacabConditionConstant : public MacabCondition
+{
+ protected:
+ bool m_bValue;
+
+ public:
+ explicit MacabConditionConstant(const bool bValue);
+ virtual bool isAlwaysTrue() const override;
+ virtual bool isAlwaysFalse() const override;
+ virtual bool eval(const MacabRecord *aRecord) const override;
+};
+
+class MacabConditionColumn : public MacabCondition
+{
+ protected:
+ sal_Int32 m_nFieldNumber;
+
+ public:
+ /// @throws css::sdbc::SQLException
+ MacabConditionColumn(
+ const MacabHeader *header,
+ std::u16string_view sColumnName);
+ virtual bool isAlwaysTrue() const override;
+ virtual bool isAlwaysFalse() const override;
+};
+
+class MacabConditionNull : public MacabConditionColumn
+{
+ public:
+ /// @throws css::sdbc::SQLException
+ MacabConditionNull(
+ const MacabHeader *header,
+ std::u16string_view sColumnName);
+ virtual bool eval(const MacabRecord *aRecord) const override;
+};
+
+class MacabConditionNotNull : public MacabConditionColumn
+{
+ public:
+ /// @throws css::sdbc::SQLException
+ MacabConditionNotNull(
+ const MacabHeader *header,
+ std::u16string_view sColumnName);
+ virtual bool eval(const MacabRecord *aRecord) const override;
+};
+
+class MacabConditionCompare : public MacabConditionColumn
+{
+ protected:
+ const OUString m_sMatchString;
+
+ public:
+ /// @throws css::sdbc::SQLException
+ MacabConditionCompare(
+ const MacabHeader *header,
+ std::u16string_view sColumnName,
+ const OUString &sMatchString);
+};
+
+class MacabConditionEqual : public MacabConditionCompare
+{
+ public:
+ /// @throws css::sdbc::SQLException
+ MacabConditionEqual(
+ const MacabHeader *header,
+ std::u16string_view sColumnName,
+ const OUString &sMatchString);
+ virtual bool eval(const MacabRecord *aRecord) const override;
+};
+
+class MacabConditionDifferent : public MacabConditionCompare
+{
+ public:
+ /// @throws css::sdbc::SQLException
+ MacabConditionDifferent(
+ const MacabHeader *header,
+ std::u16string_view sColumnName,
+ const OUString &sMatchString);
+ virtual bool eval(const MacabRecord *aRecord) const override;
+};
+
+class MacabConditionSimilar : public MacabConditionCompare
+{
+ public:
+ /// @throws css::sdbc::SQLException
+ MacabConditionSimilar(
+ const MacabHeader *header,
+ std::u16string_view sColumnName,
+ const OUString &sMatchString);
+ virtual bool eval(const MacabRecord *aRecord) const override;
+};
+
+class MacabConditionBoolean : public MacabCondition
+{
+ protected:
+ MacabCondition *m_pLeft, *m_pRight;
+
+ public:
+ MacabConditionBoolean(MacabCondition *pLeft, MacabCondition *pRight);
+ virtual ~MacabConditionBoolean() override;
+};
+
+class MacabConditionOr : public MacabConditionBoolean
+{
+ public:
+ MacabConditionOr(MacabCondition *pLeft, MacabCondition *pRight);
+ virtual bool isAlwaysTrue() const override;
+ virtual bool isAlwaysFalse() const override;
+ virtual bool eval(const MacabRecord *aRecord) const override;
+};
+
+class MacabConditionAnd : public MacabConditionBoolean
+{
+ public:
+ MacabConditionAnd(MacabCondition *pLeft, MacabCondition *pRight);
+ virtual bool isAlwaysTrue() const override;
+ virtual bool isAlwaysFalse() const override;
+ virtual bool eval(const MacabRecord *aRecord) const override;
+};
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/macab/macaborder.cxx b/connectivity/source/drivers/macab/macaborder.cxx
new file mode 100644
index 0000000000..133e5d5991
--- /dev/null
+++ b/connectivity/source/drivers/macab/macaborder.cxx
@@ -0,0 +1,75 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include "macaborder.hxx"
+#include "MacabHeader.hxx"
+#include "MacabRecord.hxx"
+
+using namespace ::connectivity::macab;
+
+MacabOrder::~MacabOrder()
+{
+}
+
+MacabSimpleOrder::MacabSimpleOrder(MacabHeader const *header, std::u16string_view sColumnName, bool bAscending)
+ : MacabOrder(),
+ m_nFieldNumber(header->getColumnNumber(sColumnName)),
+ m_bAscending(bAscending)
+{
+}
+
+sal_Int32 MacabSimpleOrder::compare(const MacabRecord *record1, const MacabRecord *record2) const
+{
+ sal_Int32 result;
+
+ result = MacabRecord::compareFields(record1->get(m_nFieldNumber), record2->get(m_nFieldNumber));
+
+ if (!m_bAscending) result = -result;
+
+ return result;
+}
+
+MacabComplexOrder::MacabComplexOrder()
+ : MacabOrder(),
+ m_aOrders()
+{
+}
+
+MacabComplexOrder::~MacabComplexOrder()
+{
+}
+
+void MacabComplexOrder::addOrder(MacabOrder *pOrder)
+{
+ m_aOrders.emplace_back(pOrder);
+}
+
+sal_Int32 MacabComplexOrder::compare(const MacabRecord *record1, const MacabRecord *record2) const
+{
+ for (auto const & p: m_aOrders)
+ {
+ sal_Int32 result = p->compare(record1, record2);
+
+ if (result) return result;
+ }
+ return 0;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/macab/macaborder.hxx b/connectivity/source/drivers/macab/macaborder.hxx
new file mode 100644
index 0000000000..e5eb6c987c
--- /dev/null
+++ b/connectivity/source/drivers/macab/macaborder.hxx
@@ -0,0 +1,64 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <rtl/ustring.hxx>
+#include "MacabHeader.hxx"
+#include "MacabRecord.hxx"
+
+#include <memory>
+#include <string_view>
+#include <vector>
+
+namespace connectivity::macab
+{
+ class MacabOrder
+ {
+ public:
+ virtual ~MacabOrder();
+
+ virtual sal_Int32 compare(const MacabRecord *record1, const MacabRecord *record2) const = 0;
+ };
+
+ class MacabSimpleOrder : public MacabOrder
+ {
+ sal_Int32 m_nFieldNumber;
+ bool m_bAscending;
+
+ public:
+ MacabSimpleOrder(MacabHeader const *header, std::u16string_view sColumnName, bool bAscending);
+
+ virtual sal_Int32 compare(const MacabRecord *record1, const MacabRecord *record2) const override;
+ };
+
+ class MacabComplexOrder : public MacabOrder
+ {
+ std::vector<std::unique_ptr<MacabOrder>> m_aOrders;
+
+ public:
+ MacabComplexOrder();
+ virtual ~MacabComplexOrder() override;
+
+ void addOrder(MacabOrder *pOrder);
+ virtual sal_Int32 compare(const MacabRecord *record1, const MacabRecord *record2) const override;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/macab/macabutilities.hxx b/connectivity/source/drivers/macab/macabutilities.hxx
new file mode 100644
index 0000000000..7e0f6b0910
--- /dev/null
+++ b/connectivity/source/drivers/macab/macabutilities.hxx
@@ -0,0 +1,142 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <memory>
+
+#include <com/sun/star/util/DateTime.hpp>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <unotools/resmgr.hxx>
+
+#include <time.h>
+#include <premac.h>
+#include <Carbon/Carbon.h>
+#include <AddressBook/ABAddressBookC.h>
+#include <postmac.h>
+
+namespace connectivity::macab
+{
+
+ inline OUString CFStringToOUString(const CFStringRef sOrig)
+ {
+ /* Copied all-but directly from code by Florian Heckl in
+ * cws_src680_aquafilepicker01
+ * File was: fpicker/source/aqua/CFStringUtilities
+ * I only removed commented debugging lines and changed variable
+ * names.
+ */
+ if (nullptr == sOrig) {
+ return OUString();
+ }
+
+ CFRetain(sOrig);
+ CFIndex nStringLength = CFStringGetLength(sOrig);
+
+ auto const unichars = std::make_unique<UniChar[]>(nStringLength+1);
+
+ //'close' the string buffer correctly
+ unichars[nStringLength] = '\0';
+
+ CFStringGetCharacters (sOrig, CFRangeMake(0,nStringLength), unichars.get());
+ CFRelease(sOrig);
+
+ return OUString(reinterpret_cast<sal_Unicode *>(unichars.get()));
+ }
+
+
+ inline CFStringRef OUStringToCFString(const OUString& aString)
+ {
+ /* Copied directly from code by Florian Heckl in
+ * cws_src680_aquafilepicker01
+ * File was: fpicker/source/aqua/CFStringUtilities
+ */
+
+ CFStringRef ref = CFStringCreateWithCharacters(kCFAllocatorDefault, reinterpret_cast<UniChar const *>(aString.getStr()), aString.getLength());
+
+ return ref;
+ }
+
+
+ inline css::util::DateTime CFDateToDateTime(const CFDateRef _cfDate)
+ {
+ /* Carbon can give us the time since 2001 of any CFDateRef,
+ * and it also stores the time since 1970 as a constant,
+ * basically allowing us to get the unixtime of any
+ * CFDateRef. From there, it is just a matter of choosing what
+ * we want to do with it.
+ */
+ css::util::DateTime nRet;
+ double timeSince2001 = CFDateGetAbsoluteTime(_cfDate);
+ time_t unixtime = timeSince2001+kCFAbsoluteTimeIntervalSince1970;
+ struct tm *ptm = localtime(&unixtime);
+ nRet.Year = ptm->tm_year+1900;
+ nRet.Month = ptm->tm_mon+1;
+ nRet.Day = ptm->tm_mday;
+ nRet.Hours = ptm->tm_hour;
+ nRet.Minutes = ptm->tm_min;
+ nRet.Seconds = ptm->tm_sec;
+ nRet.NanoSeconds = 0;
+ return nRet;
+ }
+
+
+ inline OUString fixLabel(const OUString& _originalLabel)
+ {
+ /* Get the length, and make sure that there is actually a string
+ * here.
+ */
+ if(_originalLabel.startsWith("_$!<"))
+ {
+ return _originalLabel.copy(4,_originalLabel.getLength()-8);
+ }
+
+ return _originalLabel;
+ }
+
+
+ inline sal_Int32 ABTypeToDataType(const ABPropertyType _abType)
+ {
+ sal_Int32 dataType;
+ switch(_abType)
+ {
+ case kABStringProperty:
+ dataType = css::sdbc::DataType::CHAR;
+ break;
+ case kABDateProperty:
+ dataType = css::sdbc::DataType::TIMESTAMP;
+ break;
+ case kABIntegerProperty:
+ dataType = css::sdbc::DataType::INTEGER;
+ break;
+ case kABRealProperty:
+ dataType = css::sdbc::DataType::FLOAT;
+ break;
+ default:
+ dataType = -1;
+ }
+ return dataType;
+ }
+
+ void impl_throwError(TranslateId pErrorId);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/mozab/bootstrap/MMozillaBootstrap.cxx b/connectivity/source/drivers/mozab/bootstrap/MMozillaBootstrap.cxx
new file mode 100644
index 0000000000..076a05d3b9
--- /dev/null
+++ b/connectivity/source/drivers/mozab/bootstrap/MMozillaBootstrap.cxx
@@ -0,0 +1,136 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <cppuhelper/factory.hxx>
+#include <com/sun/star/lang/XSingleServiceFactory.hpp>
+#include <cppuhelper/supportsservice.hxx>
+#include <cppuhelper/weak.hxx>
+#include "MMozillaBootstrap.hxx"
+#include "MNSProfileDiscover.hxx"
+
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::mozilla;
+using namespace connectivity::mozab;
+
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::Sequence;
+
+MozillaBootstrap::MozillaBootstrap()
+ : OMozillaBootstrap_BASE(m_aMutex)
+{
+ m_ProfileAccess.reset(new ProfileAccess);
+ bootupProfile(css::mozilla::MozillaProductType_Mozilla,OUString());
+}
+
+MozillaBootstrap::~MozillaBootstrap()
+{
+}
+
+void MozillaBootstrap::disposing()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ OMozillaBootstrap_BASE::disposing();
+}
+
+OUString SAL_CALL MozillaBootstrap::getImplementationName( )
+{
+ return "com.sun.star.comp.mozilla.MozillaBootstrap";
+}
+
+sal_Bool SAL_CALL MozillaBootstrap::supportsService( const OUString& _rServiceName )
+{
+ return cppu::supportsService(this, _rServiceName);
+}
+
+Sequence< OUString > SAL_CALL MozillaBootstrap::getSupportedServiceNames( )
+{
+ // which service is supported
+ // for more information @see com.sun.star.mozilla.MozillaBootstrap
+ return { "com.sun.star.mozilla.MozillaBootstrap" };
+}
+
+
+// XProfileDiscover
+::sal_Int32 SAL_CALL MozillaBootstrap::getProfileCount( css::mozilla::MozillaProductType product)
+{
+ return m_ProfileAccess->getProfileCount(product);
+}
+::sal_Int32 SAL_CALL MozillaBootstrap::getProfileList( css::mozilla::MozillaProductType product, css::uno::Sequence< OUString >& list )
+{
+ return m_ProfileAccess->getProfileList(product,list);
+}
+OUString SAL_CALL MozillaBootstrap::getDefaultProfile( css::mozilla::MozillaProductType product )
+{
+ return m_ProfileAccess->getDefaultProfile(product);
+}
+OUString SAL_CALL MozillaBootstrap::getProfilePath( css::mozilla::MozillaProductType product, const OUString& profileName )
+{
+ return m_ProfileAccess->getProfilePath(product,profileName);
+}
+sal_Bool SAL_CALL MozillaBootstrap::isProfileLocked( css::mozilla::MozillaProductType /*product*/, const OUString& /*profileName*/ )
+{
+ return true;
+}
+sal_Bool SAL_CALL MozillaBootstrap::getProfileExists( css::mozilla::MozillaProductType product, const OUString& profileName )
+{
+ return m_ProfileAccess->getProfileExists(product,profileName);
+}
+
+// XProfileManager
+::sal_Int32 SAL_CALL MozillaBootstrap::bootupProfile( css::mozilla::MozillaProductType, const OUString& )
+{
+ return -1;
+}
+::sal_Int32 SAL_CALL MozillaBootstrap::shutdownProfile( )
+{
+ return -1;
+}
+css::mozilla::MozillaProductType SAL_CALL MozillaBootstrap::getCurrentProduct( )
+{
+ return css::mozilla::MozillaProductType_Default;
+}
+OUString SAL_CALL MozillaBootstrap::getCurrentProfile( )
+{
+ return OUString();
+}
+sal_Bool SAL_CALL MozillaBootstrap::isCurrentProfileLocked( )
+{
+ return true;
+}
+OUString SAL_CALL MozillaBootstrap::setCurrentProfile( css::mozilla::MozillaProductType, const OUString& )
+{
+ return OUString();
+}
+
+// XProxyRunner
+::sal_Int32 SAL_CALL MozillaBootstrap::Run( const css::uno::Reference< css::mozilla::XCodeProxy >& )
+{
+ return -1;
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+connectivity_moz_MozillaBootstrap_get_implementation(
+ css::uno::XComponentContext* , css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new connectivity::mozab::MozillaBootstrap());
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/mozab/bootstrap/MMozillaBootstrap.hxx b/connectivity/source/drivers/mozab/bootstrap/MMozillaBootstrap.hxx
new file mode 100644
index 0000000000..e01a2bb961
--- /dev/null
+++ b/connectivity/source/drivers/mozab/bootstrap/MMozillaBootstrap.hxx
@@ -0,0 +1,78 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <sal/config.h>
+
+#include <memory>
+
+#include <com/sun/star/mozilla/XMozillaBootstrap.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <cppuhelper/compbase.hxx>
+
+
+namespace connectivity::mozab
+{
+ typedef ::cppu::WeakComponentImplHelper< css::mozilla::XMozillaBootstrap,
+ css::lang::XServiceInfo > OMozillaBootstrap_BASE;
+ class ProfileAccess;
+ class ProfileManager;
+ class MozillaBootstrap : public OMozillaBootstrap_BASE
+ {
+ private:
+ ::osl::Mutex m_aMutex; // mutex is need to control member access
+ virtual ~MozillaBootstrap() override;
+ std::unique_ptr<ProfileAccess> m_ProfileAccess;
+ public:
+
+ MozillaBootstrap();
+
+ // OComponentHelper
+ virtual void SAL_CALL disposing() override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+ // XMozillaBootstrap
+
+ // XProfileDiscover
+ virtual ::sal_Int32 SAL_CALL getProfileCount( css::mozilla::MozillaProductType product) override;
+ virtual ::sal_Int32 SAL_CALL getProfileList( css::mozilla::MozillaProductType product, css::uno::Sequence< OUString >& list ) override;
+ virtual OUString SAL_CALL getDefaultProfile( css::mozilla::MozillaProductType product ) override;
+ virtual OUString SAL_CALL getProfilePath( css::mozilla::MozillaProductType product, const OUString& profileName ) override;
+ virtual sal_Bool SAL_CALL isProfileLocked( css::mozilla::MozillaProductType product, const OUString& profileName ) override;
+ virtual sal_Bool SAL_CALL getProfileExists( css::mozilla::MozillaProductType product, const OUString& profileName ) override;
+
+ // XProfileManager
+ virtual ::sal_Int32 SAL_CALL bootupProfile( css::mozilla::MozillaProductType product, const OUString& profileName ) override;
+ virtual ::sal_Int32 SAL_CALL shutdownProfile( ) override;
+ virtual css::mozilla::MozillaProductType SAL_CALL getCurrentProduct( ) override;
+ virtual OUString SAL_CALL getCurrentProfile( ) override;
+ virtual sal_Bool SAL_CALL isCurrentProfileLocked( ) override;
+ virtual OUString SAL_CALL setCurrentProfile( css::mozilla::MozillaProductType product, const OUString& profileName ) override;
+
+ // XProxyRunner
+ virtual ::sal_Int32 SAL_CALL Run( const css::uno::Reference< css::mozilla::XCodeProxy >& aCode ) override;
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/mozab/bootstrap/MNSFolders.cxx b/connectivity/source/drivers/mozab/bootstrap/MNSFolders.cxx
new file mode 100644
index 0000000000..71c70c641b
--- /dev/null
+++ b/connectivity/source/drivers/mozab/bootstrap/MNSFolders.cxx
@@ -0,0 +1,159 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "MNSFolders.hxx"
+
+#ifdef UNIX
+#include <string.h>
+#endif // End UNIX
+
+#ifdef _WIN32
+#if !defined WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN
+#endif
+#include <windows.h>
+#include <stdlib.h>
+#include <shlobj.h>
+#include <objidl.h>
+#endif // End _WIN32
+#include <osl/security.hxx>
+#include <osl/file.hxx>
+#include <osl/thread.h>
+
+using namespace ::com::sun::star::mozilla;
+
+namespace
+{
+
+ OUString lcl_getUserDataDirectory()
+ {
+ ::osl::Security aSecurity;
+ OUString aConfigPath;
+
+ #if defined(_WIN32) || defined(MACOSX)
+ aSecurity.getConfigDir( aConfigPath );
+ #else
+ //This is to find the dir under which .mozilla/.thunderbird is created.
+ //mozilla doesn't honour XDG_CONFIG_HOME, so raw home dir required here
+ //not xdg-config dir
+ aSecurity.getHomeDir( aConfigPath );
+ #endif
+
+ return aConfigPath + "/";
+ }
+
+
+ const size_t NB_PRODUCTS = 3;
+ const size_t NB_CANDIDATES = 4;
+
+ // The order (index) of entries in DefaultProductDir and
+ // ProductRootEnvironmentVariable *must* match the constants
+ // (minus 1) in offapi/com/sun/star/mozilla/MozillaProductType.idl
+ // DO NOT CHANGE THE ORDER; ADD ONLY TO THE END
+ const char* DefaultProductDir[NB_PRODUCTS][NB_CANDIDATES] =
+ {
+ #if defined(_WIN32)
+ { "Mozilla/SeaMonkey/", nullptr, nullptr, nullptr },
+ { "Mozilla/Firefox/", nullptr, nullptr, nullptr },
+ { "Thunderbird/", "Mozilla/Thunderbird/", nullptr, nullptr }
+ #elif defined(MACOSX)
+ { "../Mozilla/SeaMonkey/", nullptr, nullptr, nullptr },
+ { "Firefox/", nullptr, nullptr, nullptr },
+ { "../Thunderbird/", nullptr, nullptr, nullptr }
+ #else
+ { ".mozilla/seamonkey/", nullptr, nullptr, nullptr },
+ { ".mozilla/firefox/", nullptr, nullptr, nullptr },
+ { ".thunderbird/", ".mozilla-thunderbird/", ".mozilla/thunderbird/", ".icedove/" }
+ #endif
+ };
+
+ const char* ProductRootEnvironmentVariable[NB_PRODUCTS] =
+ {
+ "MOZILLA_PROFILE_ROOT",
+ "MOZILLA_FIREFOX_PROFILE_ROOT",
+ "MOZILLA_THUNDERBIRD_PROFILE_ROOT",
+ };
+
+
+ OUString const & lcl_guessProfileRoot( MozillaProductType _product )
+ {
+ size_t productIndex = static_cast<int>(_product) - 1;
+
+ static OUString s_productDirectories[NB_PRODUCTS];
+
+ if ( s_productDirectories[ productIndex ].isEmpty() )
+ {
+ OUString sProductPath;
+
+ // check whether we have an environment variable which help us
+ const char* pProfileByEnv = getenv( ProductRootEnvironmentVariable[ productIndex ] );
+ if ( pProfileByEnv )
+ {
+ sProductPath = OUString( pProfileByEnv, rtl_str_getLength( pProfileByEnv ), osl_getThreadTextEncoding() );
+ // assume that this is fine, no further checks
+ }
+ else
+ {
+ OUString sProductDirCandidate;
+ const char pProfileRegistry[] = "profiles.ini";
+
+ // check all possible candidates
+ for ( size_t i=0; i<NB_CANDIDATES; ++i )
+ {
+ if ( nullptr == DefaultProductDir[ productIndex ][ i ] )
+ break;
+
+ sProductDirCandidate = lcl_getUserDataDirectory() +
+ OUString::createFromAscii( DefaultProductDir[ productIndex ][ i ] );
+
+ // check existence
+ ::osl::DirectoryItem aRegistryItem;
+ ::osl::FileBase::RC result = ::osl::DirectoryItem::get( sProductDirCandidate + pProfileRegistry, aRegistryItem );
+ if ( result == ::osl::FileBase::E_None )
+ {
+ ::osl::FileStatus aStatus( osl_FileStatus_Mask_Validate );
+ result = aRegistryItem.getFileStatus( aStatus );
+ if ( result == ::osl::FileBase::E_None )
+ {
+ // the registry file exists
+ break;
+ }
+ }
+ }
+
+ ::osl::FileBase::getSystemPathFromFileURL( sProductDirCandidate, sProductPath );
+ }
+
+ s_productDirectories[ productIndex ] = sProductPath;
+ }
+
+ return s_productDirectories[ productIndex ];
+ }
+}
+
+
+OUString getRegistryDir(MozillaProductType product)
+{
+ if (product == MozillaProductType_Default)
+ return OUString();
+
+ return lcl_guessProfileRoot( product );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/mozab/bootstrap/MNSFolders.hxx b/connectivity/source/drivers/mozab/bootstrap/MNSFolders.hxx
new file mode 100644
index 0000000000..90674a0f4e
--- /dev/null
+++ b/connectivity/source/drivers/mozab/bootstrap/MNSFolders.hxx
@@ -0,0 +1,28 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/mozilla/MozillaProductType.hpp>
+
+#include <rtl/ustring.hxx>
+
+OUString getRegistryDir(css::mozilla::MozillaProductType product);
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/mozab/bootstrap/MNSINIParser.cxx b/connectivity/source/drivers/mozab/bootstrap/MNSINIParser.cxx
new file mode 100644
index 0000000000..a146d0c096
--- /dev/null
+++ b/connectivity/source/drivers/mozab/bootstrap/MNSINIParser.cxx
@@ -0,0 +1,94 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "MNSINIParser.hxx"
+#include <com/sun/star/io/IOException.hpp>
+#include <osl/file.h>
+#include <rtl/byteseq.hxx>
+#include <sal/log.hxx>
+#include <o3tl/string_view.hxx>
+
+IniParser::IniParser(OUString const & rIniName)
+{
+ OUString iniUrl;
+ if (osl_File_E_None != osl_getFileURLFromSystemPath(rIniName.pData, &iniUrl.pData))
+ return;
+
+
+ oslFileHandle handle=nullptr;
+ oslFileError fileError = osl_File_E_INVAL;
+ try{
+ if (!iniUrl.isEmpty())
+ fileError = osl_openFile(iniUrl.pData, &handle, osl_File_OpenFlag_Read);
+ }
+ catch(const css::io::IOException&)
+ {
+ SAL_WARN("connectivity.mozab", "couldn't open file: " << iniUrl );
+ }
+
+ if (osl_File_E_None == fileError)
+ {
+ rtl::ByteSequence seq;
+ sal_uInt64 nSize = 0;
+
+ osl_getFileSize(handle, &nSize);
+ OUString sectionName( "no name section" );
+ while (true)
+ {
+ sal_uInt64 nPos;
+ if (osl_File_E_None != osl_getFilePos(handle, &nPos) || nPos >= nSize)
+ break;
+ if (osl_File_E_None != osl_readLine(handle, reinterpret_cast<sal_Sequence **>(&seq)))
+ break;
+ OString line(reinterpret_cast<const char *>(seq.getConstArray()), seq.getLength() );
+ sal_Int32 nIndex = line.indexOf('=');
+ if (nIndex >= 1)
+ {
+ ini_Section *aSection = &mAllSection[sectionName];
+ struct ini_NameValue nameValue;
+ nameValue.sName = OStringToOUString(
+ o3tl::trim(line.subView(0,nIndex)), RTL_TEXTENCODING_ASCII_US );
+ nameValue.sValue = OStringToOUString(
+ o3tl::trim(line.subView(nIndex+1)), RTL_TEXTENCODING_UTF8 );
+
+ aSection->vVector.push_back(nameValue);
+
+ }
+ else
+ {
+ sal_Int32 nIndexStart = line.indexOf('[');
+ sal_Int32 nIndexEnd = line.indexOf(']');
+ if ( nIndexEnd > nIndexStart && nIndexStart >=0)
+ {
+ sectionName = OStringToOUString(
+ o3tl::trim(line.subView(nIndexStart + 1,nIndexEnd - nIndexStart -1)), RTL_TEXTENCODING_ASCII_US );
+ if (sectionName.isEmpty())
+ sectionName = "no name section";
+ }
+ }
+ }
+ osl_closeFile(handle);
+ }
+ else
+ {
+ SAL_INFO("connectivity.mozab", "couldn't open file: " << iniUrl );
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/mozab/bootstrap/MNSINIParser.hxx b/connectivity/source/drivers/mozab/bootstrap/MNSINIParser.hxx
new file mode 100644
index 0000000000..27746364a3
--- /dev/null
+++ b/connectivity/source/drivers/mozab/bootstrap/MNSINIParser.hxx
@@ -0,0 +1,54 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <rtl/ustring.hxx>
+
+#include <map>
+#include <vector>
+
+struct ini_NameValue
+{
+ OUString sName;
+ OUString sValue;
+};
+
+typedef std::vector<
+ ini_NameValue
+> NameValueVector;
+
+struct ini_Section
+{
+ NameValueVector vVector;
+};
+typedef std::map<OUString,
+ ini_Section
+ >IniSectionMap;
+
+
+class IniParser
+{
+ IniSectionMap mAllSection;
+public:
+ IniSectionMap& getAllSection() { return mAllSection; }
+ /// @throws css::io::IOException
+ explicit IniParser(OUString const & rIniName);
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/mozab/bootstrap/MNSProfileDiscover.cxx b/connectivity/source/drivers/mozab/bootstrap/MNSProfileDiscover.cxx
new file mode 100644
index 0000000000..804c8ccc66
--- /dev/null
+++ b/connectivity/source/drivers/mozab/bootstrap/MNSProfileDiscover.cxx
@@ -0,0 +1,212 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <utility>
+
+#include "MNSProfileDiscover.hxx"
+#include "MNSFolders.hxx"
+#include "MNSINIParser.hxx"
+
+namespace connectivity::mozab
+{
+ ProfileStruct::ProfileStruct()
+ {
+ }
+
+ ProfileStruct::ProfileStruct(OUString aProfileName,
+ OUString aProfilePath)
+ : profileName(std::move(aProfileName))
+ , profilePath(std::move(aProfilePath))
+ {
+ }
+
+ const OUString& ProfileStruct::getProfilePath() const
+ {
+ return profilePath;
+ }
+
+ ProfileAccess::~ProfileAccess()
+ {
+ }
+
+ ProfileAccess::ProfileAccess()
+ {
+ LoadProductsInfo();
+ }
+
+ void ProfileAccess::LoadProductsInfo()
+ {
+ //tdf#39279: LO should search Thunderbird first then Seamonkey and finally Firefox
+ //load thunderbird profiles to m_ProductProfileList
+ LoadXPToolkitProfiles(MozillaProductType_Thunderbird);
+
+ //load SeaMonkey 2 profiles to m_ProductProfileList
+ LoadXPToolkitProfiles(MozillaProductType_Mozilla);
+
+ //load firefox profiles to m_ProductProfileList
+ //firefox profile does not contain address book, but maybe others need them
+ LoadXPToolkitProfiles(MozillaProductType_Firefox);
+ }
+ //Thunderbird and firefox profiles are saved in profiles.ini
+ void ProfileAccess::LoadXPToolkitProfiles(MozillaProductType product)
+ {
+ sal_Int32 index=static_cast<sal_Int32>(product);
+ ProductStruct &rProduct = m_ProductProfileList[index];
+
+ OUString regDir = getRegistryDir(product);
+ OUString profilesIni = regDir + "profiles.ini";
+ IniParser parser( profilesIni );
+ IniSectionMap &rAllSection = parser.getAllSection();
+
+ for(auto& rSection : rAllSection)
+ {
+ ini_Section *aSection = &rSection.second;
+ OUString profileName;
+ OUString profilePath;
+ OUString sIsRelative;
+ OUString sIsDefault;
+
+ for(auto& rValue : aSection->vVector)
+ {
+ struct ini_NameValue * aValue = &rValue;
+ if ( aValue->sName == "Name" )
+ {
+ profileName = aValue->sValue;
+ }
+ else if ( aValue->sName == "IsRelative" )
+ {
+ sIsRelative = aValue->sValue;
+ }
+ else if ( aValue->sName == "Path" )
+ {
+ profilePath = aValue->sValue;
+ }
+ else if ( aValue->sName == "Default" )
+ {
+ sIsDefault = aValue->sValue;
+ }
+ }
+ if (!(profileName.isEmpty() && profilePath.isEmpty()))
+ {
+ sal_Int32 isRelative = 0;
+ if (!sIsRelative.isEmpty())
+ {
+ isRelative = sIsRelative.toInt32();
+ }
+
+ OUString fullProfilePath;
+ if(isRelative)
+ {
+ fullProfilePath = regDir + profilePath;
+ }
+ else
+ {
+ fullProfilePath = profilePath;
+ }
+
+ rProduct.mProfileList[profileName] = ProfileStruct(profileName,fullProfilePath);
+
+ sal_Int32 isDefault = 0;
+ if (!sIsDefault.isEmpty())
+ {
+ isDefault = sIsDefault.toInt32();
+ }
+ if (isDefault)
+ rProduct.mCurrentProfileName = profileName;
+
+ }
+
+ // Depending on TB versions, some generate "default" profile
+ // others "default-release" profile
+ // See https://support.mozilla.org/gl/questions/1264072
+ // for some background info (the link quotes Firefox but it seems
+ // the same for TB).
+ if (profileName == "default-release")
+ {
+ rProduct.mCurrentProfileName = profileName;
+ break;
+ }
+ }
+ }
+
+ OUString ProfileAccess::getProfilePath( css::mozilla::MozillaProductType product, const OUString& profileName )
+ {
+ sal_Int32 index=static_cast<sal_Int32>(product);
+ ProductStruct &rProduct = m_ProductProfileList[index];
+ if (rProduct.mProfileList.empty() || rProduct.mProfileList.find(profileName) == rProduct.mProfileList.end())
+ {
+ //Profile not found
+ return OUString();
+ }
+ else
+ return rProduct.mProfileList[profileName].getProfilePath();
+ }
+
+ ::sal_Int32 ProfileAccess::getProfileCount( css::mozilla::MozillaProductType product)
+ {
+ sal_Int32 index=static_cast<sal_Int32>(product);
+ ProductStruct &rProduct = m_ProductProfileList[index];
+ return static_cast< ::sal_Int32 >(rProduct.mProfileList.size());
+ }
+ ::sal_Int32 ProfileAccess::getProfileList( css::mozilla::MozillaProductType product, css::uno::Sequence< OUString >& list )
+ {
+ sal_Int32 index=static_cast<sal_Int32>(product);
+ ProductStruct &rProduct = m_ProductProfileList[index];
+ list.realloc(static_cast<sal_Int32>(rProduct.mProfileList.size()));
+ auto listRange = list.getArray();
+ sal_Int32 i=0;
+ for(const auto& rEntry : rProduct.mProfileList)
+ {
+ const ProfileStruct& rProfile = rEntry.second;
+ listRange[i] = rProfile.getProfileName();
+ i++;
+ }
+
+ return static_cast< ::sal_Int32 >(rProduct.mProfileList.size());
+ }
+
+ OUString ProfileAccess::getDefaultProfile( css::mozilla::MozillaProductType product )
+ {
+ sal_Int32 index=static_cast<sal_Int32>(product);
+ ProductStruct &rProduct = m_ProductProfileList[index];
+ if (!rProduct.mCurrentProfileName.isEmpty())
+ {
+ //default profile set in mozilla registry
+ return rProduct.mCurrentProfileName;
+ }
+ if (rProduct.mProfileList.empty())
+ {
+ //there are not any profiles
+ return OUString();
+ }
+ const ProfileStruct& rProfile = (*rProduct.mProfileList.begin()).second;
+ return rProfile.getProfileName();
+ }
+
+ bool ProfileAccess::getProfileExists( css::mozilla::MozillaProductType product, const OUString& profileName )
+ {
+ sal_Int32 index=static_cast<sal_Int32>(product);
+ ProductStruct &rProduct = m_ProductProfileList[index];
+ return rProduct.mProfileList.find(profileName) != rProduct.mProfileList.end();
+ }
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/mozab/bootstrap/MNSProfileDiscover.hxx b/connectivity/source/drivers/mozab/bootstrap/MNSProfileDiscover.hxx
new file mode 100644
index 0000000000..132ac06c00
--- /dev/null
+++ b/connectivity/source/drivers/mozab/bootstrap/MNSProfileDiscover.hxx
@@ -0,0 +1,80 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/types.h>
+#include <com/sun/star/mozilla/MozillaProductType.hpp>
+#include <com/sun/star/uno/Sequence.hxx>
+#include <rtl/ustring.hxx>
+
+#include <vector>
+#include <map>
+
+using namespace com::sun::star::mozilla;
+namespace connectivity::mozab { class ProfileStruct; }
+
+typedef std::map<OUString, ::connectivity::mozab::ProfileStruct> ProfileList;
+namespace connectivity::mozab
+ {
+ class ProfileStruct
+ {
+ public:
+ ProfileStruct();
+ ProfileStruct(OUString aProfileName, OUString aProfilePath);
+ const OUString& getProfileName() const { return profileName;}
+ const OUString& getProfilePath() const;
+ private:
+ OUString profileName;
+ OUString profilePath;
+ };
+
+ class ProductStruct
+ {
+ public:
+ OUString mCurrentProfileName;
+ ProfileList mProfileList;
+ };
+
+ //Used to query profiles information
+ class ProfileAccess final
+ {
+ public:
+ ~ProfileAccess();
+ ProfileAccess();
+ /// @throws css::uno::RuntimeException
+ OUString getProfilePath( css::mozilla::MozillaProductType product, const OUString& profileName );
+ /// @throws css::uno::RuntimeException
+ ::sal_Int32 getProfileCount( css::mozilla::MozillaProductType product );
+ /// @throws css::uno::RuntimeException
+ ::sal_Int32 getProfileList( css::mozilla::MozillaProductType product, css::uno::Sequence< OUString >& list );
+ /// @throws css::uno::RuntimeException
+ OUString getDefaultProfile( css::mozilla::MozillaProductType product );
+ /// @throws css::uno::RuntimeException
+ bool getProfileExists( css::mozilla::MozillaProductType product, const OUString& profileName );
+ private:
+ ProductStruct m_ProductProfileList[4];
+ void LoadProductsInfo();
+ void LoadXPToolkitProfiles(MozillaProductType product);
+ };
+
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/mozab/bootstrap/README b/connectivity/source/drivers/mozab/bootstrap/README
new file mode 100644
index 0000000000..cea68d86cc
--- /dev/null
+++ b/connectivity/source/drivers/mozab/bootstrap/README
@@ -0,0 +1,3 @@
+this provides com.sun.star.mozilla.MozillaBootstrap which is used by at least
+xmlsecurity/source/xmlsec/nss/nssinitializer.cxx to find a user's
+firefox/thunderbird profile to use its certs
diff --git a/connectivity/source/drivers/mozab/bootstrap/mozbootstrap.component b/connectivity/source/drivers/mozab/bootstrap/mozbootstrap.component
new file mode 100644
index 0000000000..bfc0afe389
--- /dev/null
+++ b/connectivity/source/drivers/mozab/bootstrap/mozbootstrap.component
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ -->
+
+<component loader="com.sun.star.loader.SharedLibrary" environment="@CPPU_ENV@"
+ xmlns="http://openoffice.org/2010/uno-components">
+ <implementation name="com.sun.star.comp.mozilla.MozillaBootstrap"
+ constructor="connectivity_moz_MozillaBootstrap_get_implementation" single-instance="true">
+ <service name="com.sun.star.mozilla.MozillaBootstrap"/>
+ </implementation>
+</component>
diff --git a/connectivity/source/drivers/mysql_jdbc/YCatalog.cxx b/connectivity/source/drivers/mysql_jdbc/YCatalog.cxx
new file mode 100644
index 0000000000..9c0afb55ab
--- /dev/null
+++ b/connectivity/source/drivers/mysql_jdbc/YCatalog.cxx
@@ -0,0 +1,132 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <mysql/YCatalog.hxx>
+#include <mysql/YUsers.hxx>
+#include <mysql/YTables.hxx>
+#include <mysql/YViews.hxx>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XResultSet.hpp>
+#include <comphelper/types.hxx>
+
+using namespace connectivity;
+using namespace connectivity::mysql;
+using namespace connectivity::sdbcx;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+
+OMySQLCatalog::OMySQLCatalog(const Reference<XConnection>& _xConnection)
+ : OCatalog(_xConnection)
+ , m_xConnection(_xConnection)
+{
+}
+
+void OMySQLCatalog::refreshObjects(const Sequence<OUString>& _sKindOfObject,
+ ::std::vector<OUString>& _rNames)
+{
+ Reference<XResultSet> xResult = m_xMetaData->getTables(Any(), "%", "%", _sKindOfObject);
+ fillNames(xResult, _rNames);
+}
+
+void OMySQLCatalog::refreshTables()
+{
+ ::std::vector<OUString> aVector;
+
+ Sequence<OUString> sTableTypes{
+ "VIEW", "TABLE", "%"
+ }; // this last one just to be sure to include anything else...
+
+ refreshObjects(sTableTypes, aVector);
+
+ if (m_pTables)
+ m_pTables->reFill(aVector);
+ else
+ m_pTables.reset(new OTables(m_xMetaData, *this, m_aMutex, aVector));
+}
+
+void OMySQLCatalog::refreshViews()
+{
+ Sequence<OUString> aTypes{ "VIEW" };
+
+ // let's simply assume the server is new enough to support views. Current drivers
+ // as of this writing might not return the proper information in getTableTypes, so
+ // don't rely on it.
+
+ ::std::vector<OUString> aVector;
+ refreshObjects(aTypes, aVector);
+
+ if (m_pViews)
+ m_pViews->reFill(aVector);
+ else
+ m_pViews.reset(new OViews(m_xMetaData, *this, m_aMutex, aVector));
+}
+
+void OMySQLCatalog::refreshGroups() {}
+
+void OMySQLCatalog::refreshUsers()
+{
+ ::std::vector<OUString> aVector;
+ Reference<XStatement> xStmt = m_xConnection->createStatement();
+ Reference<XResultSet> xResult = xStmt->executeQuery(
+ "SELECT grantee FROM information_schema.user_privileges GROUP BY grantee");
+ if (xResult.is())
+ {
+ Reference<XRow> xRow(xResult, UNO_QUERY);
+ while (xResult->next())
+ aVector.push_back(xRow->getString(1));
+ ::comphelper::disposeComponent(xResult);
+ }
+ ::comphelper::disposeComponent(xStmt);
+
+ if (m_pUsers)
+ m_pUsers->reFill(aVector);
+ else
+ m_pUsers.reset(new OUsers(*this, m_aMutex, aVector, m_xConnection, this));
+}
+
+Any SAL_CALL OMySQLCatalog::queryInterface(const Type& rType)
+{
+ if (rType == cppu::UnoType<XGroupsSupplier>::get())
+ return Any();
+
+ return OCatalog::queryInterface(rType);
+}
+
+Sequence<Type> SAL_CALL OMySQLCatalog::getTypes()
+{
+ Sequence<Type> aTypes = OCatalog::getTypes();
+ std::vector<Type> aOwnTypes;
+ aOwnTypes.reserve(aTypes.getLength());
+ const Type* pBegin = aTypes.getConstArray();
+ const Type* pEnd = pBegin + aTypes.getLength();
+ for (; pBegin != pEnd; ++pBegin)
+ {
+ if (*pBegin != cppu::UnoType<XGroupsSupplier>::get())
+ {
+ aOwnTypes.push_back(*pBegin);
+ }
+ }
+ return Sequence<Type>(aOwnTypes.data(), aOwnTypes.size());
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/mysql_jdbc/YColumns.cxx b/connectivity/source/drivers/mysql_jdbc/YColumns.cxx
new file mode 100644
index 0000000000..54beb77ca0
--- /dev/null
+++ b/connectivity/source/drivers/mysql_jdbc/YColumns.cxx
@@ -0,0 +1,72 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <mysql/YColumns.hxx>
+#include <TConnection.hxx>
+
+using namespace ::comphelper;
+using namespace connectivity::mysql;
+using namespace connectivity::sdbcx;
+using namespace connectivity;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+
+OMySQLColumns::OMySQLColumns(::cppu::OWeakObject& _rParent, ::osl::Mutex& _rMutex,
+ const ::std::vector<OUString>& _rVector)
+ : OColumnsHelper(_rParent, true /*_bCase*/, _rMutex, _rVector, true /*_bUseHardRef*/)
+{
+}
+
+Reference<XPropertySet> OMySQLColumns::createDescriptor() { return new OMySQLColumn; }
+
+OMySQLColumn::OMySQLColumn()
+ : connectivity::sdbcx::OColumn(true)
+{
+ construct();
+}
+
+void OMySQLColumn::construct()
+{
+ m_sAutoIncrement = "auto_increment";
+ registerProperty(
+ OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_AUTOINCREMENTCREATION),
+ PROPERTY_ID_AUTOINCREMENTCREATION, 0, &m_sAutoIncrement,
+ cppu::UnoType<decltype(m_sAutoIncrement)>::get());
+}
+
+::cppu::IPropertyArrayHelper* OMySQLColumn::createArrayHelper(sal_Int32 /*_nId*/) const
+{
+ return doCreateArrayHelper();
+}
+
+::cppu::IPropertyArrayHelper& SAL_CALL OMySQLColumn::getInfoHelper()
+{
+ return *OMySQLColumn_PROP::getArrayHelper(isNew() ? 1 : 0);
+}
+
+Sequence<OUString> SAL_CALL OMySQLColumn::getSupportedServiceNames()
+{
+ return { "com.sun.star.sdbcx.Column" };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/mysql_jdbc/YDriver.cxx b/connectivity/source/drivers/mysql_jdbc/YDriver.cxx
new file mode 100644
index 0000000000..d62ee1b469
--- /dev/null
+++ b/connectivity/source/drivers/mysql_jdbc/YDriver.cxx
@@ -0,0 +1,416 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <string_view>
+
+#include <mysql/YDriver.hxx>
+#include <mysql/YCatalog.hxx>
+#include <o3tl/string_view.hxx>
+#include <comphelper/namedvaluecollection.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <comphelper/types.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <connectivity/dbexception.hxx>
+#include <connectivity/dbcharset.hxx>
+#include <com/sun/star/sdbc/DriverManager.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <TConnection.hxx>
+#include <strings.hrc>
+#include <resource/sharedresources.hxx>
+
+namespace connectivity
+{
+using namespace mysql;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::lang;
+
+namespace
+{
+OUString getJavaDriverClass(css::uno::Sequence<css::beans::PropertyValue> const& info)
+{
+ return comphelper::NamedValueCollection::getOrDefault(info, u"JavaDriverClass",
+ OUString("com.mysql.jdbc.Driver"));
+}
+}
+
+ODriverDelegator::ODriverDelegator(const Reference<XComponentContext>& _rxContext)
+ : ODriverDelegator_BASE(m_aMutex)
+ , m_xContext(_rxContext)
+{
+}
+
+ODriverDelegator::~ODriverDelegator()
+{
+ try
+ {
+ ::comphelper::disposeComponent(m_xODBCDriver);
+ ::comphelper::disposeComponent(m_xNativeDriver);
+ for (auto& rEntry : m_aJdbcDrivers)
+ ::comphelper::disposeComponent(rEntry.second);
+ }
+ catch (const Exception&)
+ {
+ }
+}
+
+void ODriverDelegator::disposing()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+
+ for (auto const& connection : m_aConnections)
+ {
+ Reference<XInterface> xTemp = connection.first.get();
+ ::comphelper::disposeComponent(xTemp);
+ }
+ m_aConnections.clear();
+ TWeakPairVector().swap(m_aConnections);
+
+ ODriverDelegator_BASE::disposing();
+}
+
+namespace
+{
+enum class T_DRIVERTYPE
+{
+ Odbc,
+ Jdbc,
+ Native
+};
+
+bool isOdbcUrl(std::u16string_view _sUrl) { return o3tl::starts_with(_sUrl, u"sdbc:mysql:odbc:"); }
+
+bool isNativeUrl(std::u16string_view _sUrl)
+{
+ return o3tl::starts_with(_sUrl, u"sdbc:mysql:mysqlc:");
+}
+
+T_DRIVERTYPE lcl_getDriverType(std::u16string_view _sUrl)
+{
+ T_DRIVERTYPE eRet = T_DRIVERTYPE::Jdbc;
+ if (isOdbcUrl(_sUrl))
+ eRet = T_DRIVERTYPE::Odbc;
+ else if (isNativeUrl(_sUrl))
+ eRet = T_DRIVERTYPE::Native;
+ return eRet;
+}
+
+OUString transformUrl(std::u16string_view _sUrl)
+{
+ OUString sNewUrl(_sUrl.substr(11));
+ if (isOdbcUrl(_sUrl))
+ sNewUrl = "sdbc:" + sNewUrl;
+ else if (isNativeUrl(_sUrl))
+ sNewUrl = "sdbc:" + sNewUrl;
+ else
+ {
+ sNewUrl = OUString::Concat("jdbc:mysql://") + sNewUrl.subView(5);
+ }
+ return sNewUrl;
+}
+
+Reference<XDriver> lcl_loadDriver(const Reference<XComponentContext>& _rxContext,
+ const OUString& _sUrl)
+{
+ Reference<XDriverManager2> xDriverAccess = DriverManager::create(_rxContext);
+ Reference<XDriver> xDriver = xDriverAccess->getDriverByURL(_sUrl);
+ return xDriver;
+}
+
+Sequence<PropertyValue> lcl_convertProperties(T_DRIVERTYPE _eType,
+ const Sequence<PropertyValue>& info,
+ const OUString& _sUrl)
+{
+ std::vector<PropertyValue> aProps;
+ const PropertyValue* pSupported = info.getConstArray();
+ const PropertyValue* pEnd = pSupported + info.getLength();
+
+ aProps.reserve(info.getLength() + 5);
+ bool jdc = false;
+ for (; pSupported != pEnd; ++pSupported)
+ {
+ aProps.push_back(*pSupported);
+ if (pSupported->Name == "JavaDriverClass")
+ {
+ jdc = true;
+ }
+ }
+
+ if (_eType == T_DRIVERTYPE::Odbc)
+ {
+ aProps.push_back(PropertyValue("Silent", 0, Any(true), PropertyState_DIRECT_VALUE));
+ aProps.push_back(
+ PropertyValue("PreventGetVersionColumns", 0, Any(true), PropertyState_DIRECT_VALUE));
+ }
+ else if (_eType == T_DRIVERTYPE::Jdbc)
+ {
+ if (!jdc)
+ {
+ aProps.push_back(PropertyValue("JavaDriverClass", 0,
+ Any(OUString("com.mysql.jdbc.Driver")),
+ PropertyState_DIRECT_VALUE));
+ }
+ }
+ else
+ {
+ aProps.push_back(
+ PropertyValue("PublicConnectionURL", 0, Any(_sUrl), PropertyState_DIRECT_VALUE));
+ }
+ aProps.push_back(
+ PropertyValue("IsAutoRetrievingEnabled", 0, Any(true), PropertyState_DIRECT_VALUE));
+ aProps.push_back(PropertyValue("AutoRetrievingStatement", 0,
+ Any(OUString("SELECT LAST_INSERT_ID()")),
+ PropertyState_DIRECT_VALUE));
+ aProps.push_back(
+ PropertyValue("ParameterNameSubstitution", 0, Any(true), PropertyState_DIRECT_VALUE));
+ return Sequence<PropertyValue>(aProps.data(), aProps.size());
+}
+}
+
+Reference<XDriver> ODriverDelegator::loadDriver(std::u16string_view url,
+ const Sequence<PropertyValue>& info)
+{
+ Reference<XDriver> xDriver;
+ const OUString sCuttedUrl = transformUrl(url);
+ const T_DRIVERTYPE eType = lcl_getDriverType(url);
+ if (eType == T_DRIVERTYPE::Odbc)
+ {
+ if (!m_xODBCDriver.is())
+ m_xODBCDriver = lcl_loadDriver(m_xContext, sCuttedUrl);
+ xDriver = m_xODBCDriver;
+ } // if ( bIsODBC )
+ else if (eType == T_DRIVERTYPE::Native)
+ {
+ if (!m_xNativeDriver.is())
+ m_xNativeDriver = lcl_loadDriver(m_xContext, sCuttedUrl);
+ xDriver = m_xNativeDriver;
+ }
+ else
+ {
+ OUString sDriverClass(getJavaDriverClass(info));
+ TJDBCDrivers::iterator aFind = m_aJdbcDrivers.find(sDriverClass);
+ if (aFind == m_aJdbcDrivers.end())
+ aFind = m_aJdbcDrivers.emplace(sDriverClass, lcl_loadDriver(m_xContext, sCuttedUrl))
+ .first;
+ xDriver = aFind->second;
+ }
+
+ return xDriver;
+}
+
+Reference<XConnection> SAL_CALL ODriverDelegator::connect(const OUString& url,
+ const Sequence<PropertyValue>& info)
+{
+ Reference<XConnection> xConnection;
+ if (acceptsURL(url))
+ {
+ Reference<XDriver> xDriver = loadDriver(url, info);
+ if (xDriver.is())
+ {
+ OUString sCuttedUrl = transformUrl(url);
+ const T_DRIVERTYPE eType = lcl_getDriverType(url);
+ Sequence<PropertyValue> aConvertedProperties = lcl_convertProperties(eType, info, url);
+ if (eType == T_DRIVERTYPE::Jdbc)
+ {
+ OUString sIanaName = ::comphelper::NamedValueCollection::getOrDefault(
+ info, u"CharSet", OUString());
+ if (!sIanaName.isEmpty())
+ {
+ ::dbtools::OCharsetMap aLookupIanaName;
+ ::dbtools::OCharsetMap::const_iterator aLookup
+ = aLookupIanaName.findIanaName(sIanaName);
+ if (aLookup != aLookupIanaName.end())
+ {
+ OUString sAdd;
+ if (RTL_TEXTENCODING_UTF8 == (*aLookup).getEncoding())
+ {
+ static constexpr OUString s_sCharSetOp = u"useUnicode=true&"_ustr;
+ if (!sCuttedUrl.matchIgnoreAsciiCase(s_sCharSetOp))
+ {
+ sAdd = s_sCharSetOp;
+ } // if ( !sCuttedUrl.matchIgnoreAsciiCase(s_sCharSetOp) )
+ } // if ( RTL_TEXTENCODING_UTF8 == (*aLookup).getEncoding() )
+ if (sCuttedUrl.indexOf('?') == -1)
+ sCuttedUrl += "?";
+ else
+ sCuttedUrl += "&";
+ sCuttedUrl += sAdd + "characterEncoding=" + sIanaName;
+ }
+ }
+ } // if ( !bIsODBC )
+
+ xConnection = xDriver->connect(sCuttedUrl, aConvertedProperties);
+ if (xConnection.is())
+ {
+ // now we have to set the URL to get the correct answer for metadata()->getURL()
+ auto pMetaConnection = comphelper::getFromUnoTunnel<OMetaConnection>(xConnection);
+ if (pMetaConnection)
+ pMetaConnection->setURL(url);
+ m_aConnections.push_back(
+ TWeakPair(WeakReferenceHelper(xConnection),
+ TWeakConnectionPair(WeakReferenceHelper(), pMetaConnection)));
+ }
+ }
+ }
+ return xConnection;
+}
+
+sal_Bool SAL_CALL ODriverDelegator::acceptsURL(const OUString& url)
+{
+ Sequence<PropertyValue> info;
+
+ bool bOK = url.startsWith("sdbc:mysql:odbc:") || url.startsWith("sdbc:mysql:jdbc:")
+ || (url.startsWith("sdbc:mysql:mysqlc:") && loadDriver(url, info).is());
+ return bOK;
+}
+
+Sequence<DriverPropertyInfo> SAL_CALL
+ODriverDelegator::getPropertyInfo(const OUString& url, const Sequence<PropertyValue>& info)
+{
+ if (!acceptsURL(url))
+ return Sequence<DriverPropertyInfo>();
+
+ Sequence<OUString> aBoolean{ "0", "1" };
+
+ std::vector<DriverPropertyInfo> aDriverInfo{
+ { "CharSet", "CharSet of the database.", false, {}, {} },
+ { "SuppressVersionColumns", "Display version columns (when available).", false, "0",
+ aBoolean }
+ };
+ const T_DRIVERTYPE eType = lcl_getDriverType(url);
+ if (eType == T_DRIVERTYPE::Jdbc)
+ {
+ aDriverInfo.push_back(DriverPropertyInfo("JavaDriverClass", "The JDBC driver class name.",
+ true, getJavaDriverClass(info),
+ Sequence<OUString>()));
+ }
+ else if (eType == T_DRIVERTYPE::Native)
+ {
+ aDriverInfo.push_back(DriverPropertyInfo(
+ "LocalSocket", "The file path of a socket to connect to a local MySQL server.", false,
+ OUString(), Sequence<OUString>()));
+ aDriverInfo.push_back(DriverPropertyInfo(
+ "NamedPipe", "The name of a pipe to connect to a local MySQL server.", false,
+ OUString(), Sequence<OUString>()));
+ }
+
+ return Sequence<DriverPropertyInfo>(aDriverInfo.data(), aDriverInfo.size());
+}
+
+sal_Int32 SAL_CALL ODriverDelegator::getMajorVersion() { return 1; }
+
+sal_Int32 SAL_CALL ODriverDelegator::getMinorVersion() { return 0; }
+
+Reference<XTablesSupplier> SAL_CALL
+ODriverDelegator::getDataDefinitionByConnection(const Reference<XConnection>& connection)
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(ODriverDelegator_BASE::rBHelper.bDisposed);
+
+ Reference<XTablesSupplier> xTab;
+ auto pConnection = comphelper::getFromUnoTunnel<OMetaConnection>(connection);
+ if (pConnection)
+ {
+ TWeakPairVector::iterator i
+ = std::find_if(m_aConnections.begin(), m_aConnections.end(),
+ [&pConnection](const TWeakPairVector::value_type& rConnection) {
+ return rConnection.second.second == pConnection;
+ });
+ if (i != m_aConnections.end())
+ {
+ xTab.set(i->second.first.get(), UNO_QUERY);
+ if (!xTab.is())
+ {
+ xTab = new OMySQLCatalog(connection);
+ i->second.first = WeakReferenceHelper(xTab);
+ }
+ }
+ } // if (pConnection)
+ if (!xTab.is())
+ {
+ TWeakPairVector::iterator i
+ = std::find_if(m_aConnections.begin(), m_aConnections.end(),
+ [&connection](const TWeakPairVector::value_type& rConnection) {
+ Reference<XConnection> xTemp(rConnection.first.get(), UNO_QUERY);
+ return xTemp == connection;
+ });
+ if (i != m_aConnections.end())
+ {
+ xTab.set(i->second.first.get(), UNO_QUERY);
+ if (!xTab.is())
+ {
+ xTab = new OMySQLCatalog(connection);
+ i->second.first = WeakReferenceHelper(xTab);
+ }
+ }
+ }
+ return xTab;
+}
+
+Reference<XTablesSupplier> SAL_CALL
+ODriverDelegator::getDataDefinitionByURL(const OUString& url, const Sequence<PropertyValue>& info)
+{
+ if (!acceptsURL(url))
+ {
+ ::connectivity::SharedResources aResources;
+ const OUString sMessage = aResources.getResourceString(STR_URI_SYNTAX_ERROR);
+ ::dbtools::throwGenericSQLException(sMessage, *this);
+ } // if ( ! acceptsURL(url) )
+
+ return getDataDefinitionByConnection(connect(url, info));
+}
+
+// XServiceInfo
+
+OUString SAL_CALL ODriverDelegator::getImplementationName()
+{
+ return "org.openoffice.comp.drivers.MySQL.Driver";
+}
+
+sal_Bool SAL_CALL ODriverDelegator::supportsService(const OUString& _rServiceName)
+{
+ return cppu::supportsService(this, _rServiceName);
+}
+
+Sequence<OUString> SAL_CALL ODriverDelegator::getSupportedServiceNames()
+{
+ return { "com.sun.star.sdbc.Driver", "com.sun.star.sdbcx.Driver" };
+}
+
+} // namespace connectivity
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+connectivity_mysql_ODriverDelegator_get_implementation(css::uno::XComponentContext* context,
+ css::uno::Sequence<css::uno::Any> const&)
+{
+ try
+ {
+ return cppu::acquire(new connectivity::ODriverDelegator(context));
+ }
+ catch (...)
+ {
+ return nullptr;
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/mysql_jdbc/YTable.cxx b/connectivity/source/drivers/mysql_jdbc/YTable.cxx
new file mode 100644
index 0000000000..b79b3f231b
--- /dev/null
+++ b/connectivity/source/drivers/mysql_jdbc/YTable.cxx
@@ -0,0 +1,313 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <mysql/YTable.hxx>
+#include <mysql/YTables.hxx>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/sdbcx/Privilege.hpp>
+#include <comphelper/property.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <comphelper/types.hxx>
+#include <connectivity/dbtools.hxx>
+#include <connectivity/sdbcx/VColumn.hxx>
+#include <connectivity/TKeys.hxx>
+#include <connectivity/TIndexes.hxx>
+#include <mysql/YColumns.hxx>
+#include <TConnection.hxx>
+
+using namespace ::comphelper;
+using namespace connectivity::mysql;
+using namespace connectivity::sdbcx;
+using namespace connectivity;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+namespace connectivity::mysql
+{
+namespace
+{
+class OMySQLKeysHelper : public OKeysHelper
+{
+protected:
+ virtual OUString getDropForeignKey() const override { return " DROP FOREIGN KEY "; }
+
+public:
+ OMySQLKeysHelper(OTableHelper* _pTable, ::osl::Mutex& _rMutex,
+ const ::std::vector<OUString>& _rVector)
+ : OKeysHelper(_pTable, _rMutex, _rVector)
+ {
+ }
+};
+}
+}
+
+OMySQLTable::OMySQLTable(sdbcx::OCollection* _pTables, const Reference<XConnection>& _xConnection)
+ : OTableHelper(_pTables, _xConnection, true)
+{
+ // we create a new table here, so we should have all the rights or ;-)
+ m_nPrivileges = Privilege::DROP | Privilege::REFERENCE | Privilege::ALTER | Privilege::CREATE
+ | Privilege::READ | Privilege::DELETE | Privilege::UPDATE | Privilege::INSERT
+ | Privilege::SELECT;
+ construct();
+}
+
+OMySQLTable::OMySQLTable(sdbcx::OCollection* _pTables, const Reference<XConnection>& _xConnection,
+ const OUString& Name, const OUString& Type, const OUString& Description,
+ const OUString& SchemaName, const OUString& CatalogName,
+ sal_Int32 _nPrivileges)
+ : OTableHelper(_pTables, _xConnection, true, Name, Type, Description, SchemaName, CatalogName)
+ , m_nPrivileges(_nPrivileges)
+{
+ construct();
+}
+
+void OMySQLTable::construct()
+{
+ OTableHelper::construct();
+ if (!isNew())
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PRIVILEGES),
+ PROPERTY_ID_PRIVILEGES, PropertyAttribute::READONLY, &m_nPrivileges,
+ cppu::UnoType<decltype(m_nPrivileges)>::get());
+}
+
+::cppu::IPropertyArrayHelper* OMySQLTable::createArrayHelper(sal_Int32 /*_nId*/) const
+{
+ return doCreateArrayHelper();
+}
+
+::cppu::IPropertyArrayHelper& OMySQLTable::getInfoHelper()
+{
+ return *static_cast<OMySQLTable_PROP*>(this)->getArrayHelper(isNew() ? 1 : 0);
+}
+
+sdbcx::OCollection* OMySQLTable::createColumns(const ::std::vector<OUString>& _rNames)
+{
+ OMySQLColumns* pColumns = new OMySQLColumns(*this, m_aMutex, _rNames);
+ pColumns->setParent(this);
+ return pColumns;
+}
+
+sdbcx::OCollection* OMySQLTable::createKeys(const ::std::vector<OUString>& _rNames)
+{
+ return new OMySQLKeysHelper(this, m_aMutex, _rNames);
+}
+
+sdbcx::OCollection* OMySQLTable::createIndexes(const ::std::vector<OUString>& _rNames)
+{
+ return new OIndexesHelper(this, m_aMutex, _rNames);
+}
+
+// XAlterTable
+void SAL_CALL OMySQLTable::alterColumnByName(const OUString& colName,
+ const Reference<XPropertySet>& descriptor)
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(
+#ifdef __GNUC__
+ ::connectivity::sdbcx::OTableDescriptor_BASE::rBHelper.bDisposed
+#else
+ rBHelper.bDisposed
+#endif
+ );
+
+ if (!m_xColumns || !m_xColumns->hasByName(colName))
+ throw NoSuchElementException(colName, *this);
+
+ if (!isNew())
+ {
+ // first we have to check what should be altered
+ Reference<XPropertySet> xProp;
+ m_xColumns->getByName(colName) >>= xProp;
+ // first check the types
+ sal_Int32 nOldType = 0, nNewType = 0, nOldPrec = 0, nNewPrec = 0, nOldScale = 0,
+ nNewScale = 0;
+
+ ::dbtools::OPropertyMap& rProp = OMetaConnection::getPropMap();
+ xProp->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_TYPE)) >>= nOldType;
+ descriptor->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_TYPE)) >>= nNewType;
+ // and precisions and scale
+ xProp->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_PRECISION)) >>= nOldPrec;
+ descriptor->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_PRECISION)) >>= nNewPrec;
+ xProp->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_SCALE)) >>= nOldScale;
+ descriptor->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_SCALE)) >>= nNewScale;
+ // second: check the "is nullable" value
+ sal_Int32 nOldNullable = 0, nNewNullable = 0;
+ xProp->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_ISNULLABLE)) >>= nOldNullable;
+ descriptor->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_ISNULLABLE)) >>= nNewNullable;
+
+ // check also the auto_increment
+ bool bOldAutoIncrement = false, bAutoIncrement = false;
+ xProp->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_ISAUTOINCREMENT))
+ >>= bOldAutoIncrement;
+ descriptor->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_ISAUTOINCREMENT))
+ >>= bAutoIncrement;
+ bool bColumnNameChanged = false;
+ OUString sOldDesc, sNewDesc;
+ xProp->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_DESCRIPTION)) >>= sOldDesc;
+ descriptor->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_DESCRIPTION)) >>= sNewDesc;
+
+ if (nOldType != nNewType || nOldPrec != nNewPrec || nOldScale != nNewScale
+ || nNewNullable != nOldNullable || bOldAutoIncrement != bAutoIncrement
+ || sOldDesc != sNewDesc)
+ {
+ // special handling because they changed the type names to distinguish
+ // if a column should be an auto_increment one
+ if (bOldAutoIncrement != bAutoIncrement)
+ {
+ OUString sTypeName;
+ descriptor->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_TYPENAME))
+ >>= sTypeName;
+
+ static const char s_sAutoIncrement[] = "auto_increment";
+ if (bAutoIncrement)
+ {
+ if (sTypeName.indexOf(s_sAutoIncrement) == -1)
+ {
+ sTypeName += OUString::Concat(" ") + s_sAutoIncrement;
+ descriptor->setPropertyValue(rProp.getNameByIndex(PROPERTY_ID_TYPENAME),
+ Any(sTypeName));
+ }
+ }
+ else
+ {
+ if (!sTypeName.isEmpty())
+ {
+ sal_Int32 nIndex = sTypeName.indexOf(s_sAutoIncrement);
+ if (nIndex != -1)
+ {
+ sTypeName = sTypeName.copy(0, nIndex);
+ descriptor->setPropertyValue(rProp.getNameByIndex(PROPERTY_ID_TYPENAME),
+ Any(sTypeName));
+ }
+ }
+ }
+ }
+ alterColumnType(nNewType, colName, descriptor);
+ bColumnNameChanged = true;
+ }
+
+ // third: check the default values
+ OUString sNewDefault, sOldDefault;
+ xProp->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_DEFAULTVALUE)) >>= sOldDefault;
+ descriptor->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_DEFAULTVALUE))
+ >>= sNewDefault;
+
+ if (!sOldDefault.isEmpty())
+ {
+ dropDefaultValue(colName);
+ if (!sNewDefault.isEmpty() && sOldDefault != sNewDefault)
+ alterDefaultValue(sNewDefault, colName);
+ }
+ else if (!sNewDefault.isEmpty())
+ alterDefaultValue(sNewDefault, colName);
+
+ // now we should look if the name of the column changed
+ OUString sNewColumnName;
+ descriptor->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_NAME)) >>= sNewColumnName;
+ if (!sNewColumnName.equalsIgnoreAsciiCase(colName) && !bColumnNameChanged)
+ {
+ const OUString sQuote = getMetaData()->getIdentifierQuoteString();
+ OUString sSql = getAlterTableColumnPart() + " CHANGE "
+ + ::dbtools::quoteName(sQuote, colName) + " "
+ + OTables::adjustSQL(::dbtools::createStandardColumnPart(
+ descriptor, getConnection(), static_cast<OTables*>(m_pTables),
+ getTypeCreatePattern()));
+ executeStatement(sSql);
+ }
+ m_xColumns->refresh();
+ }
+ else
+ {
+ if (m_xColumns)
+ {
+ m_xColumns->dropByName(colName);
+ m_xColumns->appendByDescriptor(descriptor);
+ }
+ }
+}
+
+void OMySQLTable::alterColumnType(sal_Int32 nNewType, const OUString& _rColName,
+ const Reference<XPropertySet>& _xDescriptor)
+{
+ const OUString sQuote = getMetaData()->getIdentifierQuoteString();
+ OUString sSql
+ = getAlterTableColumnPart() + " CHANGE " + ::dbtools::quoteName(sQuote, _rColName) + " ";
+
+ rtl::Reference<OColumn> pColumn = new OColumn(true);
+ ::comphelper::copyProperties(_xDescriptor, pColumn);
+ pColumn->setPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE),
+ Any(nNewType));
+
+ sSql += OTables::adjustSQL(::dbtools::createStandardColumnPart(
+ pColumn, getConnection(), static_cast<OTables*>(m_pTables), getTypeCreatePattern()));
+ executeStatement(sSql);
+}
+
+OUString OMySQLTable::getTypeCreatePattern() const { return "(M,D)"; }
+
+void OMySQLTable::alterDefaultValue(std::u16string_view _sNewDefault, const OUString& _rColName)
+{
+ const OUString sQuote = getMetaData()->getIdentifierQuoteString();
+ OUString sSql = getAlterTableColumnPart() + " ALTER " + ::dbtools::quoteName(sQuote, _rColName)
+ + " SET DEFAULT '" + _sNewDefault + "'";
+
+ executeStatement(sSql);
+}
+
+void OMySQLTable::dropDefaultValue(const OUString& _rColName)
+{
+ const OUString sQuote = getMetaData()->getIdentifierQuoteString();
+ OUString sSql = getAlterTableColumnPart() + " ALTER " + ::dbtools::quoteName(sQuote, _rColName)
+ + " DROP DEFAULT";
+
+ executeStatement(sSql);
+}
+
+OUString OMySQLTable::getAlterTableColumnPart() const
+{
+ OUString sSql("ALTER TABLE ");
+
+ OUString sComposedName(
+ ::dbtools::composeTableName(getMetaData(), m_CatalogName, m_SchemaName, m_Name, true,
+ ::dbtools::EComposeRule::InTableDefinitions));
+ sSql += sComposedName;
+
+ return sSql;
+}
+
+void OMySQLTable::executeStatement(const OUString& _rStatement)
+{
+ OUString sSQL = _rStatement;
+ if (sSQL.endsWith(","))
+ sSQL = sSQL.replaceAt(sSQL.getLength() - 1, 1, u")");
+
+ Reference<XStatement> xStmt = getConnection()->createStatement();
+ if (xStmt.is())
+ {
+ xStmt->execute(sSQL);
+ ::comphelper::disposeComponent(xStmt);
+ }
+}
+
+OUString OMySQLTable::getRenameStart() const { return "RENAME TABLE "; }
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/mysql_jdbc/YTables.cxx b/connectivity/source/drivers/mysql_jdbc/YTables.cxx
new file mode 100644
index 0000000000..0460053192
--- /dev/null
+++ b/connectivity/source/drivers/mysql_jdbc/YTables.cxx
@@ -0,0 +1,208 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <mysql/YTables.hxx>
+#include <mysql/YViews.hxx>
+#include <mysql/YTable.hxx>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XResultSet.hpp>
+#include <com/sun/star/sdbcx/Privilege.hpp>
+#include <mysql/YCatalog.hxx>
+#include <connectivity/dbtools.hxx>
+#include <comphelper/types.hxx>
+#include <TConnection.hxx>
+
+using namespace ::comphelper;
+using namespace connectivity;
+using namespace ::cppu;
+using namespace connectivity::mysql;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+using namespace dbtools;
+
+sdbcx::ObjectType OTables::createObject(const OUString& _rName)
+{
+ OUString sCatalog, sSchema, sTable;
+ ::dbtools::qualifiedNameComponents(m_xMetaData, _rName, sCatalog, sSchema, sTable,
+ ::dbtools::EComposeRule::InDataManipulation);
+
+ Sequence<OUString> sTableTypes{
+ "VIEW", "TABLE", "%"
+ }; // this last one just to be sure to include anything else...
+
+ Any aCatalog;
+ if (!sCatalog.isEmpty())
+ aCatalog <<= sCatalog;
+ Reference<XResultSet> xResult = m_xMetaData->getTables(aCatalog, sSchema, sTable, sTableTypes);
+
+ sdbcx::ObjectType xRet;
+ if (xResult.is())
+ {
+ Reference<XRow> xRow(xResult, UNO_QUERY);
+ if (xResult->next()) // there can be only one table with this name
+ {
+ sal_Int32 const nPrivileges = Privilege::DROP | Privilege::REFERENCE | Privilege::ALTER
+ | Privilege::CREATE | Privilege::READ | Privilege::DELETE
+ | Privilege::UPDATE | Privilege::INSERT
+ | Privilege::SELECT;
+
+ xRet = new OMySQLTable(this, static_cast<OMySQLCatalog&>(m_rParent).getConnection(),
+ sTable, xRow->getString(4), xRow->getString(5), sSchema,
+ sCatalog, nPrivileges);
+ }
+ ::comphelper::disposeComponent(xResult);
+ }
+
+ return xRet;
+}
+
+void OTables::impl_refresh() { static_cast<OMySQLCatalog&>(m_rParent).refreshTables(); }
+
+void OTables::disposing()
+{
+ m_xMetaData.clear();
+ OCollection::disposing();
+}
+
+Reference<XPropertySet> OTables::createDescriptor()
+{
+ return new OMySQLTable(this, static_cast<OMySQLCatalog&>(m_rParent).getConnection());
+}
+
+// XAppend
+sdbcx::ObjectType OTables::appendObject(const OUString& _rForName,
+ const Reference<XPropertySet>& descriptor)
+{
+ createTable(descriptor);
+ return createObject(_rForName);
+}
+
+// XDrop
+void OTables::dropObject(sal_Int32 _nPos, const OUString& _sElementName)
+{
+ Reference<XInterface> xObject(getObject(_nPos));
+ bool bIsNew = connectivity::sdbcx::ODescriptor::isNew(xObject);
+ if (bIsNew)
+ return;
+
+ Reference<XConnection> xConnection = static_cast<OMySQLCatalog&>(m_rParent).getConnection();
+
+ OUString sCatalog, sSchema, sTable;
+ ::dbtools::qualifiedNameComponents(m_xMetaData, _sElementName, sCatalog, sSchema, sTable,
+ ::dbtools::EComposeRule::InDataManipulation);
+
+ OUString aSql("DROP ");
+
+ Reference<XPropertySet> xProp(xObject, UNO_QUERY);
+ bool bIsView = xProp.is()
+ && ::comphelper::getString(xProp->getPropertyValue(
+ OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE)))
+ == "VIEW";
+ if (bIsView) // here we have a view
+ aSql += "VIEW ";
+ else
+ aSql += "TABLE ";
+
+ OUString sComposedName(::dbtools::composeTableName(
+ m_xMetaData, sCatalog, sSchema, sTable, true, ::dbtools::EComposeRule::InDataManipulation));
+ aSql += sComposedName;
+ Reference<XStatement> xStmt = xConnection->createStatement();
+ if (xStmt.is())
+ {
+ xStmt->execute(aSql);
+ ::comphelper::disposeComponent(xStmt);
+ }
+ // if no exception was thrown we must delete it from the views
+ if (bIsView)
+ {
+ OViews* pViews
+ = static_cast<OViews*>(static_cast<OMySQLCatalog&>(m_rParent).getPrivateViews());
+ if (pViews && pViews->hasByName(_sElementName))
+ pViews->dropByNameImpl(_sElementName);
+ }
+}
+
+OUString OTables::adjustSQL(const OUString& _sSql)
+{
+ OUString sSQL = _sSql;
+ static const char s_sUNSIGNED[] = "UNSIGNED";
+ sal_Int32 nIndex = sSQL.indexOf(s_sUNSIGNED);
+ while (nIndex != -1)
+ {
+ sal_Int32 nParen = sSQL.indexOf(')', nIndex);
+ sal_Int32 nPos = nIndex + strlen(s_sUNSIGNED);
+ OUString sNewUnsigned(sSQL.copy(nPos, nParen - nPos + 1));
+ sSQL = sSQL.replaceAt(nIndex, strlen(s_sUNSIGNED) + sNewUnsigned.getLength(),
+ rtl::Concat2View(sNewUnsigned + s_sUNSIGNED));
+ nIndex = sSQL.indexOf(s_sUNSIGNED, nIndex + strlen(s_sUNSIGNED) + sNewUnsigned.getLength());
+ }
+ return sSQL;
+}
+
+void OTables::createTable(const Reference<XPropertySet>& descriptor)
+{
+ const Reference<XConnection> xConnection
+ = static_cast<OMySQLCatalog&>(m_rParent).getConnection();
+ const OUString aSql
+ = adjustSQL(::dbtools::createSqlCreateTableStatement(descriptor, xConnection));
+ Reference<XStatement> xStmt = xConnection->createStatement();
+ if (xStmt.is())
+ {
+ xStmt->execute(aSql);
+ ::comphelper::disposeComponent(xStmt);
+ }
+}
+
+void OTables::appendNew(const OUString& _rsNewTable)
+{
+ insertElement(_rsNewTable, nullptr);
+
+ // notify our container listeners
+ ContainerEvent aEvent(static_cast<XContainer*>(this), Any(_rsNewTable), Any(), Any());
+ OInterfaceIteratorHelper3 aListenerLoop(m_aContainerListeners);
+ while (aListenerLoop.hasMoreElements())
+ aListenerLoop.next()->elementInserted(aEvent);
+}
+
+OUString OTables::getNameForObject(const sdbcx::ObjectType& _xObject)
+{
+ OSL_ENSURE(_xObject.is(), "OTables::getNameForObject: Object is NULL!");
+ return ::dbtools::composeTableName(m_xMetaData, _xObject,
+ ::dbtools::EComposeRule::InDataManipulation, false);
+}
+
+void OTables::addComment(const Reference<XPropertySet>& descriptor, OUStringBuffer& _rOut)
+{
+ OUString sDesc;
+ descriptor->getPropertyValue(
+ OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DESCRIPTION))
+ >>= sDesc;
+ if (!sDesc.isEmpty())
+ {
+ _rOut.append(" COMMENT '");
+ _rOut.append(sDesc);
+ _rOut.append("'");
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/mysql_jdbc/YUser.cxx b/connectivity/source/drivers/mysql_jdbc/YUser.cxx
new file mode 100644
index 0000000000..ec3a626596
--- /dev/null
+++ b/connectivity/source/drivers/mysql_jdbc/YUser.cxx
@@ -0,0 +1,326 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <mysql/YUser.hxx>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XResultSet.hpp>
+#include <connectivity/dbtools.hxx>
+#include <connectivity/dbexception.hxx>
+#include <com/sun/star/sdbcx/Privilege.hpp>
+#include <com/sun/star/sdbcx/PrivilegeObject.hpp>
+#include <TConnection.hxx>
+#include <strings.hrc>
+#include <comphelper/types.hxx>
+#include <utility>
+
+using namespace connectivity;
+using namespace connectivity::mysql;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+
+OMySQLUser::OMySQLUser(css::uno::Reference<css::sdbc::XConnection> _xConnection)
+ : connectivity::sdbcx::OUser(true)
+ , m_xConnection(std::move(_xConnection))
+{
+ construct();
+}
+
+OMySQLUser::OMySQLUser(css::uno::Reference<css::sdbc::XConnection> _xConnection,
+ const OUString& Name)
+ : connectivity::sdbcx::OUser(Name, true)
+ , m_xConnection(std::move(_xConnection))
+{
+ construct();
+}
+
+void OMySQLUser::refreshGroups() {}
+
+OUserExtend::OUserExtend(const css::uno::Reference<css::sdbc::XConnection>& _xConnection)
+ : OMySQLUser(_xConnection)
+{
+ construct();
+}
+
+void OUserExtend::construct()
+{
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PASSWORD),
+ PROPERTY_ID_PASSWORD, 0, &m_Password, ::cppu::UnoType<OUString>::get());
+}
+
+cppu::IPropertyArrayHelper* OUserExtend::createArrayHelper() const
+{
+ Sequence<Property> aProps;
+ describeProperties(aProps);
+ return new cppu::OPropertyArrayHelper(aProps);
+}
+
+cppu::IPropertyArrayHelper& OUserExtend::getInfoHelper()
+{
+ return *OUserExtend_PROP::getArrayHelper();
+}
+typedef connectivity::sdbcx::OUser_BASE OUser_BASE_RBHELPER;
+
+sal_Int32 SAL_CALL OMySQLUser::getPrivileges(const OUString& objName, sal_Int32 objType)
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(OUser_BASE_RBHELPER::rBHelper.bDisposed);
+
+ sal_Int32 nRights, nRightsWithGrant;
+ findPrivilegesAndGrantPrivileges(objName, objType, nRights, nRightsWithGrant);
+ return nRights;
+}
+
+void OMySQLUser::findPrivilegesAndGrantPrivileges(const OUString& objName, sal_Int32 objType,
+ sal_Int32& nRights, sal_Int32& nRightsWithGrant)
+{
+ nRightsWithGrant = nRights = 0;
+ // first we need to create the sql stmt to select the privs
+ Reference<XDatabaseMetaData> xMeta = m_xConnection->getMetaData();
+ OUString sCatalog, sSchema, sTable;
+ ::dbtools::qualifiedNameComponents(xMeta, objName, sCatalog, sSchema, sTable,
+ ::dbtools::EComposeRule::InDataManipulation);
+ Reference<XResultSet> xRes;
+ switch (objType)
+ {
+ case PrivilegeObject::TABLE:
+ case PrivilegeObject::VIEW:
+ {
+ Any aCatalog;
+ if (!sCatalog.isEmpty())
+ aCatalog <<= sCatalog;
+ xRes = xMeta->getTablePrivileges(aCatalog, sSchema, sTable);
+ }
+ break;
+
+ case PrivilegeObject::COLUMN:
+ {
+ Any aCatalog;
+ if (!sCatalog.isEmpty())
+ aCatalog <<= sCatalog;
+ xRes = xMeta->getColumnPrivileges(aCatalog, sSchema, sTable, "%");
+ }
+ break;
+ }
+
+ if (!xRes.is())
+ return;
+
+ static const char sYes[] = "YES";
+
+ nRightsWithGrant = nRights = 0;
+
+ Reference<XRow> xCurrentRow(xRes, UNO_QUERY);
+ while (xCurrentRow.is() && xRes->next())
+ {
+ OUString sGrantee = xCurrentRow->getString(5);
+ OUString sPrivilege = xCurrentRow->getString(6);
+ OUString sGrantable = xCurrentRow->getString(7);
+
+ if (!m_Name.equalsIgnoreAsciiCase(sGrantee))
+ continue;
+
+ if (sPrivilege.equalsIgnoreAsciiCase("SELECT"))
+ {
+ nRights |= Privilege::SELECT;
+ if (sGrantable.equalsIgnoreAsciiCase(sYes))
+ nRightsWithGrant |= Privilege::SELECT;
+ }
+ else if (sPrivilege.equalsIgnoreAsciiCase("INSERT"))
+ {
+ nRights |= Privilege::INSERT;
+ if (sGrantable.equalsIgnoreAsciiCase(sYes))
+ nRightsWithGrant |= Privilege::INSERT;
+ }
+ else if (sPrivilege.equalsIgnoreAsciiCase("UPDATE"))
+ {
+ nRights |= Privilege::UPDATE;
+ if (sGrantable.equalsIgnoreAsciiCase(sYes))
+ nRightsWithGrant |= Privilege::UPDATE;
+ }
+ else if (sPrivilege.equalsIgnoreAsciiCase("DELETE"))
+ {
+ nRights |= Privilege::DELETE;
+ if (sGrantable.equalsIgnoreAsciiCase(sYes))
+ nRightsWithGrant |= Privilege::DELETE;
+ }
+ else if (sPrivilege.equalsIgnoreAsciiCase("READ"))
+ {
+ nRights |= Privilege::READ;
+ if (sGrantable.equalsIgnoreAsciiCase(sYes))
+ nRightsWithGrant |= Privilege::READ;
+ }
+ else if (sPrivilege.equalsIgnoreAsciiCase("CREATE"))
+ {
+ nRights |= Privilege::CREATE;
+ if (sGrantable.equalsIgnoreAsciiCase(sYes))
+ nRightsWithGrant |= Privilege::CREATE;
+ }
+ else if (sPrivilege.equalsIgnoreAsciiCase("ALTER"))
+ {
+ nRights |= Privilege::ALTER;
+ if (sGrantable.equalsIgnoreAsciiCase(sYes))
+ nRightsWithGrant |= Privilege::ALTER;
+ }
+ else if (sPrivilege.equalsIgnoreAsciiCase("REFERENCES"))
+ {
+ nRights |= Privilege::REFERENCE;
+ if (sGrantable.equalsIgnoreAsciiCase(sYes))
+ nRightsWithGrant |= Privilege::REFERENCE;
+ }
+ else if (sPrivilege.equalsIgnoreAsciiCase("DROP"))
+ {
+ nRights |= Privilege::DROP;
+ if (sGrantable.equalsIgnoreAsciiCase(sYes))
+ nRightsWithGrant |= Privilege::DROP;
+ }
+ }
+ ::comphelper::disposeComponent(xRes);
+}
+
+sal_Int32 SAL_CALL OMySQLUser::getGrantablePrivileges(const OUString& objName, sal_Int32 objType)
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(OUser_BASE_RBHELPER::rBHelper.bDisposed);
+
+ sal_Int32 nRights, nRightsWithGrant;
+ findPrivilegesAndGrantPrivileges(objName, objType, nRights, nRightsWithGrant);
+ return nRightsWithGrant;
+}
+
+void SAL_CALL OMySQLUser::grantPrivileges(const OUString& objName, sal_Int32 objType,
+ sal_Int32 objPrivileges)
+{
+ if (objType != PrivilegeObject::TABLE)
+ {
+ ::connectivity::SharedResources aResources;
+ const OUString sError(aResources.getResourceString(STR_PRIVILEGE_NOT_GRANTED));
+ ::dbtools::throwGenericSQLException(sError, *this);
+ } // if ( objType != PrivilegeObject::TABLE )
+
+ ::osl::MutexGuard aGuard(m_aMutex);
+
+ OUString sPrivs = getPrivilegeString(objPrivileges);
+ if (sPrivs.isEmpty())
+ return;
+
+ Reference<XDatabaseMetaData> xMeta = m_xConnection->getMetaData();
+ OUString sGrant
+ = "GRANT " + sPrivs + " ON "
+ + ::dbtools::quoteTableName(xMeta, objName, ::dbtools::EComposeRule::InDataManipulation)
+ + " TO " + m_Name;
+
+ Reference<XStatement> xStmt = m_xConnection->createStatement();
+ if (xStmt.is())
+ xStmt->execute(sGrant);
+ ::comphelper::disposeComponent(xStmt);
+}
+
+void SAL_CALL OMySQLUser::revokePrivileges(const OUString& objName, sal_Int32 objType,
+ sal_Int32 objPrivileges)
+{
+ if (objType != PrivilegeObject::TABLE)
+ {
+ ::connectivity::SharedResources aResources;
+ const OUString sError(aResources.getResourceString(STR_PRIVILEGE_NOT_REVOKED));
+ ::dbtools::throwGenericSQLException(sError, *this);
+ }
+
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(OUser_BASE_RBHELPER::rBHelper.bDisposed);
+ OUString sPrivs = getPrivilegeString(objPrivileges);
+ if (sPrivs.isEmpty())
+ return;
+
+ Reference<XDatabaseMetaData> xMeta = m_xConnection->getMetaData();
+ OUString sGrant
+ = "REVOKE " + sPrivs + " ON "
+ + ::dbtools::quoteTableName(xMeta, objName, ::dbtools::EComposeRule::InDataManipulation)
+ + " FROM " + m_Name;
+
+ Reference<XStatement> xStmt = m_xConnection->createStatement();
+ if (xStmt.is())
+ xStmt->execute(sGrant);
+ ::comphelper::disposeComponent(xStmt);
+}
+
+// XUser
+void SAL_CALL OMySQLUser::changePassword(const OUString& /*oldPassword*/,
+ const OUString& newPassword)
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(OUser_BASE_RBHELPER::rBHelper.bDisposed);
+ OUString sAlterPwd = "SET PASSWORD FOR " + m_Name + "@\"%\" = PASSWORD('" + newPassword + "')";
+
+ Reference<XStatement> xStmt = m_xConnection->createStatement();
+ if (xStmt.is())
+ {
+ xStmt->execute(sAlterPwd);
+ ::comphelper::disposeComponent(xStmt);
+ }
+}
+
+OUString OMySQLUser::getPrivilegeString(sal_Int32 nRights)
+{
+ OUString sPrivs;
+ if ((nRights & Privilege::INSERT) == Privilege::INSERT)
+ sPrivs += "INSERT";
+
+ if ((nRights & Privilege::DELETE) == Privilege::DELETE)
+ {
+ if (!sPrivs.isEmpty())
+ sPrivs += ",";
+ sPrivs += "DELETE";
+ }
+
+ if ((nRights & Privilege::UPDATE) == Privilege::UPDATE)
+ {
+ if (!sPrivs.isEmpty())
+ sPrivs += ",";
+ sPrivs += "UPDATE";
+ }
+
+ if ((nRights & Privilege::ALTER) == Privilege::ALTER)
+ {
+ if (!sPrivs.isEmpty())
+ sPrivs += ",";
+ sPrivs += "ALTER";
+ }
+
+ if ((nRights & Privilege::SELECT) == Privilege::SELECT)
+ {
+ if (!sPrivs.isEmpty())
+ sPrivs += ",";
+ sPrivs += "SELECT";
+ }
+
+ if ((nRights & Privilege::REFERENCE) == Privilege::REFERENCE)
+ {
+ if (!sPrivs.isEmpty())
+ sPrivs += ",";
+ sPrivs += "REFERENCES";
+ }
+
+ return sPrivs;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/mysql_jdbc/YUsers.cxx b/connectivity/source/drivers/mysql_jdbc/YUsers.cxx
new file mode 100644
index 0000000000..eba995a910
--- /dev/null
+++ b/connectivity/source/drivers/mysql_jdbc/YUsers.cxx
@@ -0,0 +1,92 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <mysql/YUsers.hxx>
+#include <mysql/YUser.hxx>
+#include <connectivity/sdbcx/IRefreshable.hxx>
+#include <comphelper/types.hxx>
+#include <connectivity/dbtools.hxx>
+#include <TConnection.hxx>
+#include <utility>
+
+using namespace ::comphelper;
+using namespace connectivity;
+using namespace connectivity::mysql;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+
+OUsers::OUsers(::cppu::OWeakObject& _rParent, ::osl::Mutex& _rMutex,
+ const ::std::vector<OUString>& _rVector,
+ css::uno::Reference<css::sdbc::XConnection> _xConnection,
+ connectivity::sdbcx::IRefreshableUsers* _pParent)
+ : sdbcx::OCollection(_rParent, true, _rMutex, _rVector)
+ , m_xConnection(std::move(_xConnection))
+ , m_pParent(_pParent)
+{
+}
+
+sdbcx::ObjectType OUsers::createObject(const OUString& _rName)
+{
+ return new OMySQLUser(m_xConnection, _rName);
+}
+
+void OUsers::impl_refresh() { m_pParent->refreshUsers(); }
+
+Reference<XPropertySet> OUsers::createDescriptor() { return new OUserExtend(m_xConnection); }
+
+// XAppend
+sdbcx::ObjectType OUsers::appendObject(const OUString& _rForName,
+ const Reference<XPropertySet>& descriptor)
+{
+ OUString aSql("GRANT USAGE ON * TO ");
+ OUString aQuote = m_xConnection->getMetaData()->getIdentifierQuoteString();
+ aSql += ::dbtools::quoteName(aQuote, _rForName) + " @\"%\" ";
+ OUString sPassword;
+ descriptor->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PASSWORD))
+ >>= sPassword;
+ if (!sPassword.isEmpty())
+ {
+ aSql += " IDENTIFIED BY '" + sPassword + "'";
+ }
+
+ Reference<XStatement> xStmt = m_xConnection->createStatement();
+ if (xStmt.is())
+ xStmt->execute(aSql);
+ ::comphelper::disposeComponent(xStmt);
+
+ return createObject(_rForName);
+}
+
+// XDrop
+void OUsers::dropObject(sal_Int32 /*_nPos*/, const OUString& _sElementName)
+{
+ OUString aSql("DROP USER ");
+ OUString aQuote = m_xConnection->getMetaData()->getIdentifierQuoteString();
+ aSql += ::dbtools::quoteName(aQuote, _sElementName);
+
+ Reference<XStatement> xStmt = m_xConnection->createStatement();
+ if (xStmt.is())
+ xStmt->execute(aSql);
+ ::comphelper::disposeComponent(xStmt);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/mysql_jdbc/YViews.cxx b/connectivity/source/drivers/mysql_jdbc/YViews.cxx
new file mode 100644
index 0000000000..3dba721c0c
--- /dev/null
+++ b/connectivity/source/drivers/mysql_jdbc/YViews.cxx
@@ -0,0 +1,138 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <mysql/YViews.hxx>
+#include <mysql/YTables.hxx>
+#include <mysql/YCatalog.hxx>
+#include <connectivity/dbtools.hxx>
+#include <connectivity/sdbcx/VView.hxx>
+#include <comphelper/types.hxx>
+#include <TConnection.hxx>
+
+using namespace ::comphelper;
+
+using namespace ::cppu;
+using namespace connectivity;
+using namespace connectivity::mysql;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+using namespace dbtools;
+typedef connectivity::sdbcx::OCollection OCollection_TYPE;
+
+sdbcx::ObjectType OViews::createObject(const OUString& _rName)
+{
+ OUString sCatalog, sSchema, sTable;
+ ::dbtools::qualifiedNameComponents(m_xMetaData, _rName, sCatalog, sSchema, sTable,
+ ::dbtools::EComposeRule::InDataManipulation);
+ return new ::connectivity::sdbcx::OView(isCaseSensitive(), sTable, m_xMetaData, OUString(),
+ sSchema, sCatalog);
+}
+
+void OViews::impl_refresh() { static_cast<OMySQLCatalog&>(m_rParent).refreshTables(); }
+
+void OViews::disposing()
+{
+ m_xMetaData.clear();
+ OCollection::disposing();
+}
+
+Reference<XPropertySet> OViews::createDescriptor()
+{
+ Reference<XConnection> xConnection = static_cast<OMySQLCatalog&>(m_rParent).getConnection();
+ rtl::Reference<connectivity::sdbcx::OView> pNew
+ = new connectivity::sdbcx::OView(true, xConnection->getMetaData());
+ return pNew;
+}
+
+// XAppend
+sdbcx::ObjectType OViews::appendObject(const OUString& _rForName,
+ const Reference<XPropertySet>& descriptor)
+{
+ createView(descriptor);
+ return createObject(_rForName);
+}
+
+// XDrop
+void OViews::dropObject(sal_Int32 _nPos, const OUString& /*_sElementName*/)
+{
+ if (m_bInDrop)
+ return;
+
+ Reference<XInterface> xObject(getObject(_nPos));
+ bool bIsNew = connectivity::sdbcx::ODescriptor::isNew(xObject);
+ if (bIsNew)
+ return;
+
+ OUString aSql("DROP VIEW");
+
+ Reference<XPropertySet> xProp(xObject, UNO_QUERY);
+ aSql += ::dbtools::composeTableName(m_xMetaData, xProp,
+ ::dbtools::EComposeRule::InTableDefinitions, true);
+
+ Reference<XConnection> xConnection = static_cast<OMySQLCatalog&>(m_rParent).getConnection();
+ Reference<XStatement> xStmt = xConnection->createStatement();
+ xStmt->execute(aSql);
+ ::comphelper::disposeComponent(xStmt);
+}
+
+void OViews::dropByNameImpl(const OUString& elementName)
+{
+ m_bInDrop = true;
+ OCollection_TYPE::dropByName(elementName);
+ m_bInDrop = false;
+}
+
+void OViews::createView(const Reference<XPropertySet>& descriptor)
+{
+ Reference<XConnection> xConnection = static_cast<OMySQLCatalog&>(m_rParent).getConnection();
+
+ OUString aSql("CREATE VIEW ");
+ OUString sCommand;
+
+ aSql += ::dbtools::composeTableName(m_xMetaData, descriptor,
+ ::dbtools::EComposeRule::InTableDefinitions, true)
+ + " AS ";
+
+ descriptor->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_COMMAND))
+ >>= sCommand;
+ aSql += sCommand;
+
+ Reference<XStatement> xStmt = xConnection->createStatement();
+ if (xStmt.is())
+ {
+ xStmt->execute(aSql);
+ ::comphelper::disposeComponent(xStmt);
+ }
+
+ // insert the new view also in the tables collection
+ OTables* pTables
+ = static_cast<OTables*>(static_cast<OMySQLCatalog&>(m_rParent).getPrivateTables());
+ if (pTables)
+ {
+ OUString sName = ::dbtools::composeTableName(
+ m_xMetaData, descriptor, ::dbtools::EComposeRule::InDataManipulation, false);
+ pTables->appendNew(sName);
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/mysql_jdbc/mysql_jdbc.component b/connectivity/source/drivers/mysql_jdbc/mysql_jdbc.component
new file mode 100644
index 0000000000..7ecd7a4418
--- /dev/null
+++ b/connectivity/source/drivers/mysql_jdbc/mysql_jdbc.component
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ -->
+
+<component loader="com.sun.star.loader.SharedLibrary" environment="@CPPU_ENV@"
+ xmlns="http://openoffice.org/2010/uno-components">
+ <implementation name="org.openoffice.comp.drivers.MySQL.Driver"
+ constructor="connectivity_mysql_ODriverDelegator_get_implementation">
+ <service name="com.sun.star.sdbc.Driver"/>
+ <service name="com.sun.star.sdbcx.Driver"/>
+ </implementation>
+</component>
diff --git a/connectivity/source/drivers/mysqlc/mysqlc.component b/connectivity/source/drivers/mysqlc/mysqlc.component
new file mode 100644
index 0000000000..e4295110f8
--- /dev/null
+++ b/connectivity/source/drivers/mysqlc/mysqlc.component
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+-->
+<component xmlns="http://openoffice.org/2010/uno-components"
+ loader="com.sun.star.loader.SharedLibrary">
+ <implementation name="com.sun.star.comp.sdbc.mysqlc.MysqlCDriver">
+ <service name="com.sun.star.sdbc.Driver"/>
+ </implementation>
+</component>
diff --git a/connectivity/source/drivers/mysqlc/mysqlc_catalog.cxx b/connectivity/source/drivers/mysqlc/mysqlc_catalog.cxx
new file mode 100644
index 0000000000..d72ab1f65d
--- /dev/null
+++ b/connectivity/source/drivers/mysqlc/mysqlc_catalog.cxx
@@ -0,0 +1,93 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "mysqlc_catalog.hxx"
+#include "mysqlc_tables.hxx"
+#include "mysqlc_views.hxx"
+#include "mysqlc_users.hxx"
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <comphelper/types.hxx>
+
+connectivity::mysqlc::Catalog::Catalog(
+ const css::uno::Reference<css::sdbc::XConnection>& rConnection)
+ : OCatalog(rConnection)
+ , m_xConnection(rConnection)
+{
+}
+
+//----- OCatalog -------------------------------------------------------------
+void connectivity::mysqlc::Catalog::refreshTables()
+{
+ css::uno::Reference<css::sdbc::XResultSet> xTables
+ = m_xMetaData->getTables(css::uno::Any(), "%", "%", {});
+
+ if (!xTables.is())
+ return;
+
+ ::std::vector<OUString> aTableNames;
+
+ fillNames(xTables, aTableNames);
+
+ if (!m_pTables)
+ m_pTables.reset(new Tables(m_xConnection->getMetaData(), *this, m_aMutex, aTableNames));
+ else
+ m_pTables->reFill(aTableNames);
+}
+
+void connectivity::mysqlc::Catalog::refreshViews()
+{
+ css::uno::Reference<css::sdbc::XResultSet> xViews
+ = m_xMetaData->getTables(css::uno::Any(), "%", "%", { "VIEW" });
+
+ if (!xViews.is())
+ return;
+
+ ::std::vector<OUString> aViewNames;
+
+ fillNames(xViews, aViewNames);
+
+ if (!m_pViews)
+ m_pViews.reset(new Views(m_xConnection, *this, m_aMutex, aViewNames));
+ else
+ m_pViews->reFill(aViewNames);
+}
+
+//----- IRefreshableGroups ---------------------------------------------------
+void connectivity::mysqlc::Catalog::refreshGroups()
+{
+ // TODO: implement me
+}
+
+//----- IRefreshableUsers ----------------------------------------------------
+void connectivity::mysqlc::Catalog::refreshUsers()
+{
+ css::uno::Reference<css::sdbc::XStatement> statement = m_xConnection->createStatement();
+ css::uno::Reference<css::sdbc::XResultSet> xUsers = statement->executeQuery(
+ "SELECT grantee FROM information_schema.user_privileges GROUP BY grantee");
+
+ if (!xUsers.is())
+ return;
+
+ ::std::vector<OUString> aUserNames;
+
+ css::uno::Reference<css::sdbc::XRow> xRow(xUsers, css::uno::UNO_QUERY);
+ while (xUsers->next())
+ {
+ aUserNames.push_back(xRow->getString(1));
+ }
+ xRow.clear();
+ ::comphelper::disposeComponent(xUsers);
+
+ if (!m_pUsers)
+ m_pUsers.reset(new Users(m_xConnection->getMetaData(), *this, m_aMutex, aUserNames));
+ else
+ m_pUsers->reFill(aUserNames);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/connectivity/source/drivers/mysqlc/mysqlc_catalog.hxx b/connectivity/source/drivers/mysqlc/mysqlc_catalog.hxx
new file mode 100644
index 0000000000..1bea18c766
--- /dev/null
+++ b/connectivity/source/drivers/mysqlc/mysqlc_catalog.hxx
@@ -0,0 +1,38 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include <sdbcx/VCatalog.hxx>
+
+namespace connectivity::mysqlc
+{
+class Catalog : public ::connectivity::sdbcx::OCatalog
+{
+ css::uno::Reference<css::sdbc::XConnection> m_xConnection;
+
+public:
+ explicit Catalog(const css::uno::Reference<css::sdbc::XConnection>& rConnection);
+
+ // OCatalog
+ virtual void refreshTables() override;
+ virtual void refreshViews() override;
+
+ // IRefreshableGroups
+ virtual void refreshGroups() override;
+
+ // IRefreshableUsers
+ virtual void refreshUsers() override;
+
+ sdbcx::OCollection* getPrivateTables() const { return m_pTables.get(); }
+};
+
+} // namespace connectivity::mysqlc
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/connectivity/source/drivers/mysqlc/mysqlc_column.cxx b/connectivity/source/drivers/mysqlc/mysqlc_column.cxx
new file mode 100644
index 0000000000..ceb7437386
--- /dev/null
+++ b/connectivity/source/drivers/mysqlc/mysqlc_column.cxx
@@ -0,0 +1,45 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "mysqlc_column.hxx"
+
+#include <TConnection.hxx>
+
+connectivity::mysqlc::Column::Column()
+ : OColumn(true) // case sensitive
+{
+ construct();
+}
+
+void connectivity::mysqlc::Column::construct()
+{
+ m_sAutoIncrement = "auto_increment";
+ registerProperty(
+ OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_AUTOINCREMENTCREATION),
+ PROPERTY_ID_AUTOINCREMENTCREATION, 0, &m_sAutoIncrement,
+ cppu::UnoType<decltype(m_sAutoIncrement)>::get());
+}
+
+::cppu::IPropertyArrayHelper*
+ connectivity::mysqlc::Column::createArrayHelper(sal_Int32 /*_nId*/) const
+{
+ return doCreateArrayHelper();
+}
+
+::cppu::IPropertyArrayHelper& SAL_CALL connectivity::mysqlc::Column::getInfoHelper()
+{
+ return *Column_PROP::getArrayHelper(isNew() ? 1 : 0);
+}
+
+css::uno::Sequence<OUString> SAL_CALL connectivity::mysqlc::Column::getSupportedServiceNames()
+{
+ return { "com.sun.star.sdbcx.Column" };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/connectivity/source/drivers/mysqlc/mysqlc_column.hxx b/connectivity/source/drivers/mysqlc/mysqlc_column.hxx
new file mode 100644
index 0000000000..f69ef1afce
--- /dev/null
+++ b/connectivity/source/drivers/mysqlc/mysqlc_column.hxx
@@ -0,0 +1,32 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+#pragma once
+
+#include <connectivity/sdbcx/VColumn.hxx>
+
+namespace connectivity::mysqlc
+{
+class Column;
+typedef ::comphelper::OIdPropertyArrayUsageHelper<Column> Column_PROP;
+class Column : public sdbcx::OColumn, public Column_PROP
+{
+ OUString m_sAutoIncrement;
+
+protected:
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper(sal_Int32 _nId) const override;
+ virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override;
+
+public:
+ Column();
+ virtual void construct() override;
+ virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override;
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/connectivity/source/drivers/mysqlc/mysqlc_columns.cxx b/connectivity/source/drivers/mysqlc/mysqlc_columns.cxx
new file mode 100644
index 0000000000..b34b36b45c
--- /dev/null
+++ b/connectivity/source/drivers/mysqlc/mysqlc_columns.cxx
@@ -0,0 +1,28 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "mysqlc_columns.hxx"
+#include "mysqlc_column.hxx"
+
+connectivity::mysqlc::Columns::Columns(Table& rTable, osl::Mutex& rMutex,
+ const ::std::vector<OUString>& rVector)
+ : OColumnsHelper(rTable,
+ true, // case sensitivity
+ rMutex, rVector,
+ /*bUseHardRef*/ true)
+{
+ OColumnsHelper::setParent(&rTable);
+}
+
+css::uno::Reference<css::beans::XPropertySet> connectivity::mysqlc::Columns::createDescriptor()
+{
+ return new Column;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/connectivity/source/drivers/mysqlc/mysqlc_columns.hxx b/connectivity/source/drivers/mysqlc/mysqlc_columns.hxx
new file mode 100644
index 0000000000..34230db37b
--- /dev/null
+++ b/connectivity/source/drivers/mysqlc/mysqlc_columns.hxx
@@ -0,0 +1,29 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include "mysqlc_table.hxx"
+
+#include <connectivity/TColumnsHelper.hxx>
+
+namespace connectivity::mysqlc
+{
+class Columns : public ::connectivity::OColumnsHelper
+{
+protected:
+ virtual css::uno::Reference<css::beans::XPropertySet> createDescriptor() override;
+
+public:
+ Columns(Table& rTable, ::osl::Mutex& rMutex, const ::std::vector<OUString>& _rVector);
+};
+
+} // namespace connectivity::mysqlc
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/connectivity/source/drivers/mysqlc/mysqlc_connection.cxx b/connectivity/source/drivers/mysqlc/mysqlc_connection.cxx
new file mode 100644
index 0000000000..269113383d
--- /dev/null
+++ b/connectivity/source/drivers/mysqlc/mysqlc_connection.cxx
@@ -0,0 +1,521 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "mysqlc_catalog.hxx"
+#include "mysqlc_connection.hxx"
+#include "mysqlc_databasemetadata.hxx"
+#include <com/sun/star/sdbc/SQLException.hpp>
+
+#include "mysqlc_driver.hxx"
+#include "mysqlc_statement.hxx"
+#include "mysqlc_preparedstatement.hxx"
+#include "mysqlc_general.hxx"
+
+#include <com/sun/star/beans/NamedValue.hpp>
+
+#include <comphelper/servicehelper.hxx>
+
+using namespace connectivity::mysqlc;
+
+using namespace com::sun::star::uno;
+using namespace com::sun::star::container;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::sdbc;
+using namespace com::sun::star::sdbcx;
+using ::osl::MutexGuard;
+
+namespace
+{
+void lcl_executeUpdate(MYSQL* pMySql, const OString& sql)
+{
+ mysql_real_query(pMySql, sql.getStr(), sql.getLength());
+ // TODO handle error
+}
+}
+
+OConnection::OConnection(MysqlCDriver& _rDriver)
+ : OMetaConnection_BASE(m_aMutex)
+ , m_mysql()
+ , m_xCatalog(nullptr)
+ , m_xMetaData(nullptr)
+ , m_xDriver(&_rDriver)
+{
+}
+
+OConnection::~OConnection()
+{
+ if (!isClosed())
+ {
+ close();
+ }
+}
+
+void OConnection::construct(const OUString& url, const Sequence<PropertyValue>& info)
+{
+ MutexGuard aGuard(m_aMutex);
+
+ mysql_library_init(0, nullptr, nullptr);
+ mysql_init(&m_mysql);
+
+ OString charset_name{ "utf8mb4"_ostr };
+ mysql_options(&m_mysql, MYSQL_SET_CHARSET_NAME, charset_name.getStr());
+
+ sal_Int32 nIndex;
+ OUString token;
+ OUString aHostName("localhost");
+ sal_Int32 nPort = 3306;
+ OUString aDbName;
+
+ m_settings.encoding = MysqlCDriver::getDefaultEncoding();
+
+ // parse url. Url has the following format:
+ // external server: sdbc:mysqlc:[hostname]:[port]/[dbname]
+
+ if (url.startsWith("sdbc:mysqlc:"))
+ {
+ nIndex = 12;
+ }
+ else
+ {
+ // sdbc:mysql:mysqlc:[hostname]:[port]/[dbname]
+ nIndex = 18;
+ }
+
+ token = url.getToken(0, '/', nIndex);
+ if (!token.isEmpty())
+ {
+ sal_Int32 nIndex1 = 0;
+ OUString hostandport = token.getToken(0, ':', nIndex1);
+ if (!hostandport.isEmpty())
+ {
+ aHostName = hostandport;
+ hostandport = token.getToken(0, ':', nIndex1);
+ if (!hostandport.isEmpty() && nIndex1)
+ {
+ nPort = hostandport.toInt32();
+ }
+ token = url.getToken(0, '/', nIndex);
+ if (!token.isEmpty() && nIndex)
+ {
+ aDbName = token;
+ }
+ }
+ }
+
+ // get user and password for mysql connection
+ const PropertyValue* pIter = info.getConstArray();
+ const PropertyValue* pEnd = pIter + info.getLength();
+ OUString aUser, aPass, sUnixSocket, sNamedPipe;
+ bool unixSocketPassed = false;
+ bool namedPipePassed = false;
+
+ m_settings.connectionURL = url;
+ for (; pIter != pEnd; ++pIter)
+ {
+ if (pIter->Name == "user")
+ {
+ OSL_VERIFY(pIter->Value >>= aUser);
+ }
+ else if (pIter->Name == "password")
+ {
+ OSL_VERIFY(pIter->Value >>= aPass);
+ }
+ else if (pIter->Name == "LocalSocket")
+ {
+ OSL_VERIFY(pIter->Value >>= sUnixSocket);
+ unixSocketPassed = !sUnixSocket.isEmpty();
+ }
+ else if (pIter->Name == "NamedPipe")
+ {
+ OSL_VERIFY(pIter->Value >>= sNamedPipe);
+ namedPipePassed = !sNamedPipe.isEmpty();
+ }
+ else if (pIter->Name == "PublicConnectionURL")
+ {
+ OSL_VERIFY(pIter->Value >>= m_settings.connectionURL);
+ }
+ else if (pIter->Name == "NewURL")
+ { // legacy name for "PublicConnectionURL"
+ OSL_VERIFY(pIter->Value >>= m_settings.connectionURL);
+ }
+ }
+
+ OString host_str = OUStringToOString(aHostName, m_settings.encoding);
+ OString user_str = OUStringToOString(aUser, m_settings.encoding);
+ OString pass_str = OUStringToOString(aPass, m_settings.encoding);
+ OString schema_str = OUStringToOString(aDbName, m_settings.encoding);
+ OString socket_str;
+
+ // use TCP as connection by default
+ mysql_protocol_type protocol = MYSQL_PROTOCOL_TCP;
+ if (unixSocketPassed)
+ {
+ socket_str = OUStringToOString(sUnixSocket, m_settings.encoding);
+ protocol = MYSQL_PROTOCOL_SOCKET;
+ }
+ else if (namedPipePassed)
+ {
+ socket_str = OUStringToOString(sNamedPipe, m_settings.encoding);
+ protocol = MYSQL_PROTOCOL_PIPE;
+ }
+
+ mysql_options(&m_mysql, MYSQL_OPT_PROTOCOL, &protocol);
+
+ // flags can also be passed as last parameter
+ if (!mysql_real_connect(&m_mysql, host_str.getStr(), user_str.getStr(), pass_str.getStr(),
+ schema_str.getStr(), nPort, socket_str.getStr(),
+ CLIENT_MULTI_STATEMENTS))
+ mysqlc_sdbc_driver::throwSQLExceptionWithMsg(
+ mysql_error(&m_mysql), mysql_sqlstate(&m_mysql), mysql_errno(&m_mysql), *this,
+ getConnectionEncoding());
+
+ // Check if the server is 4.1 or above
+ if (getMysqlVersion() < 40100)
+ {
+ throw SQLException("MariaDB LibreOffice Connector requires MySQL Server 4.1 or above",
+ *this, OUString(), 0, Any());
+ }
+
+ lcl_executeUpdate(&m_mysql, "SET session sql_mode='ANSI_QUOTES,NO_AUTO_VALUE_ON_ZERO'"_ostr);
+ lcl_executeUpdate(&m_mysql, "SET NAMES utf8mb4"_ostr);
+}
+
+OUString OConnection::getImplementationName()
+{
+ return "com.sun.star.sdbc.drivers.mysqlc.OConnection";
+}
+
+css::uno::Sequence<OUString> OConnection::getSupportedServiceNames()
+{
+ return { "com.sun.star.sdbc.Connection" };
+}
+
+sal_Bool OConnection::supportsService(OUString const& ServiceName)
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+Reference<XStatement> SAL_CALL OConnection::createStatement()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OConnection_BASE::rBHelper.bDisposed);
+
+ // create a statement
+ // the statement can only be executed once
+ Reference<XStatement> xReturn = new OStatement(this);
+ m_aStatements.push_back(WeakReferenceHelper(xReturn));
+
+ return xReturn;
+}
+
+Reference<XPreparedStatement> SAL_CALL OConnection::prepareStatement(const OUString& _sSql)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OConnection_BASE::rBHelper.bDisposed);
+ const OString sSqlStatement
+ = OUStringToOString(_sSql, getConnectionEncoding()); // FIXME transform statement ?
+
+ MYSQL_STMT* pStmt = mysql_stmt_init(&m_mysql);
+ mysql_stmt_prepare(pStmt, sSqlStatement.getStr(), sSqlStatement.getLength());
+
+ unsigned int nErrorNum = mysql_errno(&m_mysql);
+ if (nErrorNum != 0)
+ mysqlc_sdbc_driver::throwSQLExceptionWithMsg(mysql_error(&m_mysql),
+ mysql_sqlstate(&m_mysql), nErrorNum, *this,
+ getConnectionEncoding());
+
+ Reference<XPreparedStatement> xStatement = new OPreparedStatement(this, pStmt);
+ m_aStatements.push_back(WeakReferenceHelper(xStatement));
+ return xStatement;
+}
+
+Reference<XPreparedStatement> SAL_CALL OConnection::prepareCall(const OUString& /*_sSql*/)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OConnection_BASE::rBHelper.bDisposed);
+
+ mysqlc_sdbc_driver::throwFeatureNotImplementedException("OConnection::prepareCall", *this);
+ return Reference<XPreparedStatement>();
+}
+
+OUString SAL_CALL OConnection::nativeSQL(const OUString& /*_sSql*/)
+{
+ // const OUString sSqlStatement = transFormPreparedStatement( _sSql );
+ // TODO
+ return OUString();
+}
+
+void SAL_CALL OConnection::setAutoCommit(sal_Bool autoCommit)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OConnection_BASE::rBHelper.bDisposed);
+ if (!mysql_autocommit(&m_mysql, autoCommit))
+ mysqlc_sdbc_driver::throwSQLExceptionWithMsg(
+ mysql_error(&m_mysql), mysql_sqlstate(&m_mysql), mysql_errno(&m_mysql), *this,
+ getConnectionEncoding());
+}
+
+sal_Bool SAL_CALL OConnection::getAutoCommit()
+{
+ // you have to distinguish which if you are in autocommit mode or not
+ // at normal case true should be fine here
+
+ // TODO use SELECT @@autocommit query for that
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OConnection_BASE::rBHelper.bDisposed);
+
+ return false;
+}
+
+void SAL_CALL OConnection::commit()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OConnection_BASE::rBHelper.bDisposed);
+
+ if (!mysql_commit(&m_mysql))
+ mysqlc_sdbc_driver::throwSQLExceptionWithMsg(
+ mysql_error(&m_mysql), mysql_sqlstate(&m_mysql), mysql_errno(&m_mysql), *this,
+ getConnectionEncoding());
+}
+
+void SAL_CALL OConnection::rollback()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OConnection_BASE::rBHelper.bDisposed);
+
+ if (!mysql_rollback(&m_mysql))
+ mysqlc_sdbc_driver::throwSQLExceptionWithMsg(
+ mysql_error(&m_mysql), mysql_sqlstate(&m_mysql), mysql_errno(&m_mysql), *this,
+ getConnectionEncoding());
+}
+
+sal_Bool SAL_CALL OConnection::isClosed()
+{
+ MutexGuard aGuard(m_aMutex);
+
+ // just simple -> we are close when we are disposed that means someone called dispose(); (XComponent)
+ return OConnection_BASE::rBHelper.bDisposed;
+}
+
+Reference<XDatabaseMetaData> SAL_CALL OConnection::getMetaData()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OConnection_BASE::rBHelper.bDisposed);
+
+ Reference<XDatabaseMetaData> xMetaData = m_xMetaData;
+ if (!xMetaData.is())
+ {
+ xMetaData = new ODatabaseMetaData(*this, &m_mysql);
+ m_xMetaData = xMetaData;
+ }
+
+ return xMetaData;
+}
+
+void SAL_CALL OConnection::setReadOnly(sal_Bool readOnly)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OConnection_BASE::rBHelper.bDisposed);
+
+ m_settings.readOnly = readOnly;
+}
+
+sal_Bool SAL_CALL OConnection::isReadOnly()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OConnection_BASE::rBHelper.bDisposed);
+
+ // return if your connection to readonly
+ return m_settings.readOnly;
+}
+
+void SAL_CALL OConnection::setCatalog(const OUString& /*catalog*/)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OConnection_BASE::rBHelper.bDisposed);
+
+ // TODO How?
+}
+
+OUString SAL_CALL OConnection::getCatalog()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OConnection_BASE::rBHelper.bDisposed);
+
+ // TODO How?
+ return OUString{};
+}
+
+void SAL_CALL OConnection::setTransactionIsolation(sal_Int32 /*level*/)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OConnection_BASE::rBHelper.bDisposed);
+
+ // TODO
+}
+
+sal_Int32 SAL_CALL OConnection::getTransactionIsolation()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OConnection_BASE::rBHelper.bDisposed);
+
+ return 0; // TODO
+}
+
+Reference<XNameAccess> SAL_CALL OConnection::getTypeMap()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OConnection_BASE::rBHelper.bDisposed);
+
+ Reference<XNameAccess> t = m_typeMap;
+ return t;
+}
+
+void SAL_CALL OConnection::setTypeMap(const Reference<XNameAccess>& typeMap)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OConnection_BASE::rBHelper.bDisposed);
+
+ m_typeMap = typeMap;
+}
+
+// XCloseable
+void SAL_CALL OConnection::close()
+{
+ /*
+ we need block, because the mutex is a local variable,
+ which will guard the block
+ */
+ {
+ // we just dispose us
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OConnection_BASE::rBHelper.bDisposed);
+ }
+ mysql_close(&m_mysql);
+ mysql_library_end();
+ dispose();
+}
+
+// XWarningsSupplier
+Any SAL_CALL OConnection::getWarnings()
+{
+ Any x;
+ // when you collected some warnings -> return it
+ return x;
+}
+
+void SAL_CALL OConnection::clearWarnings()
+{
+ // you should clear your collected warnings here#
+}
+
+void OConnection::disposing()
+{
+ // we noticed that we should be destroyed in near future so we have to dispose our statements
+ MutexGuard aGuard(m_aMutex);
+
+ for (auto const& statement : m_aStatements)
+ {
+ Reference<XComponent> xComp(statement.get(), UNO_QUERY);
+ if (xComp.is())
+ {
+ xComp->dispose();
+ }
+ }
+ m_aStatements.clear();
+
+ m_xMetaData = WeakReference<XDatabaseMetaData>();
+
+ OConnection_BASE::disposing();
+}
+
+sal_Int32 OConnection::getMysqlVersion()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OConnection_BASE::rBHelper.bDisposed);
+
+ unsigned long version = mysql_get_server_version(&m_mysql);
+ return static_cast<sal_Int32>(version);
+}
+
+OUString OConnection::transFormPreparedStatement(const OUString& _sSQL)
+{
+ OUString sSqlStatement = _sSQL;
+ if (!m_xParameterSubstitution.is())
+ {
+ try
+ {
+ Reference<XConnection> xCon = this;
+ Sequence<Any> aArgs{ Any(NamedValue("ActiveConnection", Any(xCon))) };
+
+ m_xParameterSubstitution.set(
+ m_xDriver->getFactory()->createInstanceWithArguments(
+ "org.openoffice.comp.helper.ParameterSubstitution", aArgs),
+ UNO_QUERY);
+ }
+ catch (const Exception&)
+ {
+ }
+ }
+ if (m_xParameterSubstitution.is())
+ {
+ try
+ {
+ sSqlStatement = m_xParameterSubstitution->substituteVariables(sSqlStatement, true);
+ }
+ catch (const Exception&)
+ {
+ }
+ }
+ return sSqlStatement;
+}
+
+//----- XUnoTunnel ----------------------------------------------------------
+// virtual
+sal_Int64 SAL_CALL OConnection::getSomething(const css::uno::Sequence<sal_Int8>& rId)
+{
+ return comphelper::getSomethingImpl(rId, this);
+}
+
+// static
+const Sequence<sal_Int8>& OConnection::getUnoTunnelId()
+{
+ static const comphelper::UnoIdInit implId;
+ return implId.getSeq();
+}
+
+Reference<XTablesSupplier> OConnection::createCatalog()
+{
+ MutexGuard aGuard(m_aMutex);
+
+ // m_xCatalog is a weak reference. Reuse it if it still exists.
+ Reference<XTablesSupplier> xCatalog = m_xCatalog;
+ if (xCatalog.is())
+ {
+ return xCatalog;
+ }
+ else
+ {
+ xCatalog = new Catalog(this);
+ m_xCatalog = xCatalog;
+ return m_xCatalog;
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/mysqlc/mysqlc_connection.hxx b/connectivity/source/drivers/mysqlc/mysqlc_connection.hxx
new file mode 100644
index 0000000000..3a0ccf36b4
--- /dev/null
+++ b/connectivity/source/drivers/mysqlc/mysqlc_connection.hxx
@@ -0,0 +1,190 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <memory>
+#include "mysqlc_subcomponent.hxx"
+#include "mysqlc_types.hxx"
+
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/lang/XUnoTunnel.hpp>
+#include <com/sun/star/sdbc/ColumnValue.hpp>
+#include <com/sun/star/sdbc/SQLWarning.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <com/sun/star/sdbc/XWarningsSupplier.hpp>
+#include <com/sun/star/util/XStringSubstitution.hpp>
+
+#include <com/sun/star/sdbcx/XTablesSupplier.hpp>
+
+#include <cppuhelper/basemutex.hxx>
+#include <cppuhelper/compbase.hxx>
+#include <rtl/ref.hxx>
+
+#include <mysql.h>
+
+#include <map>
+
+namespace sql
+{
+class SQLException;
+}
+
+namespace connectivity
+{
+class OMetaConnection;
+class ODatabaseMetaData;
+
+namespace mysqlc
+{
+typedef ::cppu::WeakComponentImplHelper<css::sdbc::XConnection, css::sdbc::XWarningsSupplier,
+ css::lang::XUnoTunnel, css::lang::XServiceInfo>
+ OMetaConnection_BASE;
+
+struct ConnectionSettings
+{
+ rtl_TextEncoding encoding;
+ OUString connectionURL;
+ bool readOnly;
+ ConnectionSettings()
+ : encoding(RTL_TEXTENCODING_DONTKNOW)
+ , readOnly(false)
+ {
+ }
+};
+
+class MysqlCDriver;
+
+typedef OMetaConnection_BASE OConnection_BASE;
+
+typedef std::vector<css::uno::WeakReferenceHelper> OWeakRefArray;
+
+class OConnection final : public cppu::BaseMutex, public OConnection_BASE
+{
+private:
+ MYSQL m_mysql;
+ ConnectionSettings m_settings;
+ css::uno::Reference<css::container::XNameAccess> m_typeMap;
+ css::uno::Reference<css::util::XStringSubstitution> m_xParameterSubstitution;
+
+ // Data attributes
+
+ css::uno::WeakReference<css::sdbcx::XTablesSupplier> m_xCatalog;
+ css::uno::WeakReference<css::sdbc::XDatabaseMetaData> m_xMetaData;
+
+ OWeakRefArray m_aStatements; // vector containing a list
+ // of all the Statement objects
+ // for this Connection
+
+ rtl::Reference<MysqlCDriver> m_xDriver; // Pointer to the owning driver object
+public:
+ MYSQL* getMysqlConnection() { return &m_mysql; }
+
+ /// @throws SQLException
+ /// @throws RuntimeException
+ sal_Int32 getMysqlVersion();
+
+ /// @throws SQLException
+ void construct(const OUString& url, const css::uno::Sequence<css::beans::PropertyValue>& info);
+
+ OConnection(MysqlCDriver& _rDriver);
+ virtual ~OConnection() override;
+
+ rtl_TextEncoding getConnectionEncoding() const { return m_settings.encoding; }
+
+ /**
+ * Create and/or connect to the sdbcx Catalog. This is completely
+ * unrelated to the SQL "Catalog".
+ */
+ css::uno::Reference<css::sdbcx::XTablesSupplier> createCatalog();
+
+ // OComponentHelper
+ virtual void SAL_CALL disposing() override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+
+ virtual sal_Bool SAL_CALL supportsService(OUString const& ServiceName) override;
+
+ virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override;
+
+ // XUnoTunnel
+ virtual sal_Int64 SAL_CALL getSomething(const css::uno::Sequence<sal_Int8>& rId) override;
+ static const css::uno::Sequence<sal_Int8>& getUnoTunnelId();
+
+ // XConnection
+ css::uno::Reference<css::sdbc::XStatement> SAL_CALL createStatement() override;
+
+ css::uno::Reference<css::sdbc::XPreparedStatement>
+ SAL_CALL prepareStatement(const OUString& sql) override;
+
+ css::uno::Reference<css::sdbc::XPreparedStatement>
+ SAL_CALL prepareCall(const OUString& sql) override;
+
+ OUString SAL_CALL nativeSQL(const OUString& sql) override;
+
+ void SAL_CALL setAutoCommit(sal_Bool autoCommit) override;
+
+ sal_Bool SAL_CALL getAutoCommit() override;
+
+ void SAL_CALL commit() override;
+
+ void SAL_CALL rollback() override;
+
+ sal_Bool SAL_CALL isClosed() override;
+
+ css::uno::Reference<css::sdbc::XDatabaseMetaData> SAL_CALL getMetaData() override;
+
+ void SAL_CALL setReadOnly(sal_Bool readOnly) override;
+
+ sal_Bool SAL_CALL isReadOnly() override;
+
+ void SAL_CALL setCatalog(const OUString& catalog) override;
+
+ OUString SAL_CALL getCatalog() override;
+
+ void SAL_CALL setTransactionIsolation(sal_Int32 level) override;
+
+ sal_Int32 SAL_CALL getTransactionIsolation() override;
+
+ css::uno::Reference<css::container::XNameAccess> SAL_CALL getTypeMap() override;
+
+ void SAL_CALL
+ setTypeMap(const css::uno::Reference<css::container::XNameAccess>& typeMap) override;
+ // XCloseable
+ void SAL_CALL close() override;
+ // XWarningsSupplier
+ css::uno::Any SAL_CALL getWarnings() override;
+ void SAL_CALL clearWarnings() override;
+
+ // TODO: Not used
+ //sal_Int32 sdbcColumnType(OUString typeName);
+ const ConnectionSettings& getConnectionSettings() const { return m_settings; }
+ OUString transFormPreparedStatement(const OUString& _sSQL);
+
+ const MysqlCDriver& getDriver() const { return *m_xDriver; }
+
+}; /* OConnection */
+// TODO: Not used.
+//inline OUString getPattern(OUString p) { return (p.getLength()) ? p : ASC2OU("%"); }
+} /* mysqlc */
+} /* connectivity */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/mysqlc/mysqlc_databasemetadata.cxx b/connectivity/source/drivers/mysqlc/mysqlc_databasemetadata.cxx
new file mode 100644
index 0000000000..901c9bd6dc
--- /dev/null
+++ b/connectivity/source/drivers/mysqlc/mysqlc_databasemetadata.cxx
@@ -0,0 +1,1057 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#include "mysqlc_databasemetadata.hxx"
+#include <com/sun/star/sdbc/ResultSetType.hpp>
+#include <com/sun/star/sdbc/TransactionIsolation.hpp>
+#include <com/sun/star/sdbc/Deferrability.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <comphelper/sequence.hxx>
+#include <o3tl/string_view.hxx>
+
+#include <sal/log.hxx>
+#include <rtl/ustrbuf.hxx>
+#include "mysqlc_general.hxx"
+#include "mysqlc_driver.hxx"
+#include "mysqlc_preparedstatement.hxx"
+
+using namespace connectivity::mysqlc;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::sdbc;
+
+static std::string wild("%");
+
+static void lcl_setRows_throw(const Reference<XResultSet>& _xResultSet, sal_Int32 _nType,
+ const std::vector<std::vector<Any>>& _rRows)
+{
+ Reference<XInitialization> xIni(_xResultSet, UNO_QUERY);
+
+ Sequence<Sequence<Any>> aRows(_rRows.size());
+
+ Sequence<Any>* pRowsIter = aRows.getArray();
+ for (const auto& rRow : _rRows)
+ {
+ if (!rRow.empty())
+ {
+ (*pRowsIter) = comphelper::containerToSequence(rRow);
+ }
+ ++pRowsIter;
+ }
+ Sequence<Any> aArgs{ Any(_nType), Any(aRows) };
+ xIni->initialize(aArgs);
+}
+
+ODatabaseMetaData::ODatabaseMetaData(OConnection& _rCon, MYSQL* pMySql)
+ : m_rConnection(_rCon)
+ , m_pMySql(pMySql)
+{
+}
+
+ODatabaseMetaData::~ODatabaseMetaData() {}
+
+OUString SAL_CALL ODatabaseMetaData::getCatalogSeparator() { return OUString(); }
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxBinaryLiteralLength() { return 16777208L; }
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxRowSize()
+{
+ return 2147483647L - 8; // Max buffer size - HEADER
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxCatalogNameLength() { return 32; }
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxCharLiteralLength() { return 16777208; }
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxColumnNameLength() { return 64; }
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxColumnsInIndex() { return 16; }
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxCursorNameLength() { return 64; }
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxConnections()
+{
+ SAL_WARN("connectivity.mysqlc", "method not implemented");
+ // TODO
+ // SELECT @@max_connections
+ return 100;
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxColumnsInTable() { return 512; }
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxStatementLength()
+{
+ SAL_WARN("connectivity.mysqlc", "method not implemented");
+ // TODO
+ // "SHOW VARIABLES LIKE 'max_allowed_packet'"
+ return 32767;
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxTableNameLength() { return 64; }
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxTablesInSelect() { return 256; }
+
+sal_Bool SAL_CALL ODatabaseMetaData::doesMaxRowSizeIncludeBlobs() { return true; }
+
+sal_Bool SAL_CALL ODatabaseMetaData::storesLowerCaseQuotedIdentifiers()
+{
+ SAL_WARN("connectivity.mysqlc", "method not implemented");
+ // TODO
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::storesLowerCaseIdentifiers()
+{
+ SAL_WARN("connectivity.mysqlc", "method not implemented");
+ //TODO;
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::storesMixedCaseQuotedIdentifiers()
+{
+ SAL_WARN("connectivity.mysqlc", "method not implemented");
+ // TODO
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::storesMixedCaseIdentifiers()
+{
+ // TODO
+ SAL_WARN("connectivity.mysqlc", "method not implemented");
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::storesUpperCaseQuotedIdentifiers()
+{
+ // TODO
+ SAL_WARN("connectivity.mysqlc", "method not implemented");
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::storesUpperCaseIdentifiers()
+{
+ // TODO
+ SAL_WARN("connectivity.mysqlc", "method not implemented");
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsAlterTableWithAddColumn() { return true; }
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsAlterTableWithDropColumn() { return true; }
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxIndexLength() { return 256; }
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsNonNullableColumns() { return true; }
+
+OUString SAL_CALL ODatabaseMetaData::getCatalogTerm() { return "n/a"; }
+
+OUString SAL_CALL ODatabaseMetaData::getIdentifierQuoteString() { return "`"; }
+
+OUString SAL_CALL ODatabaseMetaData::getExtraNameCharacters() { return "#@"; }
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsDifferentTableCorrelationNames() { return true; }
+
+sal_Bool SAL_CALL ODatabaseMetaData::isCatalogAtStart() { return true; }
+
+sal_Bool SAL_CALL ODatabaseMetaData::dataDefinitionIgnoredInTransactions() { return false; }
+
+sal_Bool SAL_CALL ODatabaseMetaData::dataDefinitionCausesTransactionCommit() { return true; }
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsDataManipulationTransactionsOnly() { return false; }
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsDataDefinitionAndDataManipulationTransactions()
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsPositionedDelete() { return false; }
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsPositionedUpdate() { return false; }
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsOpenStatementsAcrossRollback() { return false; }
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsOpenStatementsAcrossCommit() { return false; }
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsOpenCursorsAcrossCommit() { return false; }
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsOpenCursorsAcrossRollback() { return false; }
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsTransactionIsolationLevel(sal_Int32 /*level*/)
+{
+ return true;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsSchemasInDataManipulation() { return true; }
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsANSI92FullSQL() { return false; }
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsANSI92EntryLevelSQL() { return true; }
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsIntegrityEnhancementFacility() { return false; }
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsSchemasInIndexDefinitions() { return true; }
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsSchemasInTableDefinitions() { return true; }
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsCatalogsInTableDefinitions() { return false; }
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsCatalogsInIndexDefinitions() { return false; }
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsCatalogsInDataManipulation() { return false; }
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsOuterJoins() { return true; }
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxStatements() { return 0; }
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxProcedureNameLength() { return 64; }
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxSchemaNameLength() { return 64; }
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsTransactions() { return true; }
+
+sal_Bool SAL_CALL ODatabaseMetaData::allProceduresAreCallable() { return false; }
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsStoredProcedures()
+{
+ return m_rConnection.getMysqlVersion() >= 50000;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsSelectForUpdate()
+{
+ return m_rConnection.getMysqlVersion() >= 40000;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::allTablesAreSelectable() { return false; }
+
+sal_Bool SAL_CALL ODatabaseMetaData::isReadOnly() { return false; }
+
+sal_Bool SAL_CALL ODatabaseMetaData::usesLocalFiles() { return false; }
+
+sal_Bool SAL_CALL ODatabaseMetaData::usesLocalFilePerTable() { return false; }
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsTypeConversion() { return true; }
+
+sal_Bool SAL_CALL ODatabaseMetaData::nullPlusNonNullIsNull() { return true; }
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsColumnAliasing() { return true; }
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsTableCorrelationNames() { return true; }
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsConvert(sal_Int32 /*fromType*/, sal_Int32 /*toType*/)
+{
+ // TODO
+ SAL_WARN("connectivity.mysqlc", "method not implemented");
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsExpressionsInOrderBy() { return true; }
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsGroupBy() { return true; }
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsGroupByBeyondSelect() { return true; }
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsGroupByUnrelated() { return true; }
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsMultipleTransactions() { return true; }
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsMultipleResultSets() { return true; }
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsLikeEscapeClause() { return true; }
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsOrderByUnrelated() { return true; }
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsUnion()
+{
+ return m_rConnection.getMysqlVersion() >= 40000;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsUnionAll()
+{
+ return m_rConnection.getMysqlVersion() >= 40000;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsMixedCaseIdentifiers() { return false; }
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsMixedCaseQuotedIdentifiers() { return false; }
+
+sal_Bool SAL_CALL ODatabaseMetaData::nullsAreSortedAtEnd() { return false; }
+
+sal_Bool SAL_CALL ODatabaseMetaData::nullsAreSortedAtStart()
+{
+ return m_rConnection.getMysqlVersion() > 40001 && m_rConnection.getMysqlVersion() < 40011;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::nullsAreSortedHigh() { return false; }
+
+sal_Bool SAL_CALL ODatabaseMetaData::nullsAreSortedLow() { return !nullsAreSortedHigh(); }
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsSchemasInProcedureCalls()
+{
+ return m_rConnection.getMysqlVersion() >= 32200;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsSchemasInPrivilegeDefinitions()
+{
+ return m_rConnection.getMysqlVersion() >= 32200;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsCatalogsInProcedureCalls() { return false; }
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsCatalogsInPrivilegeDefinitions() { return false; }
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsCorrelatedSubqueries()
+{
+ return m_rConnection.getMysqlVersion() >= 40100;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsSubqueriesInComparisons()
+{
+ return m_rConnection.getMysqlVersion() >= 40100;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsSubqueriesInExists()
+{
+ return m_rConnection.getMysqlVersion() >= 40100;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsSubqueriesInIns()
+{
+ return m_rConnection.getMysqlVersion() >= 40100;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsSubqueriesInQuantifieds()
+{
+ return m_rConnection.getMysqlVersion() >= 40100;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsANSI92IntermediateSQL() { return false; }
+
+OUString SAL_CALL ODatabaseMetaData::getURL()
+{
+ return m_rConnection.getConnectionSettings().connectionURL;
+}
+
+OUString SAL_CALL ODatabaseMetaData::getUserName()
+{
+ Reference<XStatement> statement = m_rConnection.createStatement();
+ Reference<XResultSet> rs = statement->executeQuery("select user()");
+ Reference<XRow> xRow(rs, UNO_QUERY_THROW);
+ (void)rs->next(); // the first and only result
+ // e.g. root@localhost
+ OUString userWithConnection = xRow->getString(1);
+ sal_Int32 nIndexOfAt = userWithConnection.indexOf("@");
+ if (nIndexOfAt > 0)
+ {
+ OUString user = userWithConnection.copy(0, nIndexOfAt);
+ return user;
+ }
+ return userWithConnection;
+}
+
+OUString SAL_CALL ODatabaseMetaData::getDriverName() { return "MySQL Connector/OO.org"; }
+
+OUString SAL_CALL ODatabaseMetaData::getDriverVersion() { return "0.9.2"; }
+
+OUString SAL_CALL ODatabaseMetaData::getDatabaseProductVersion()
+{
+ return OStringToOUString(mysql_get_server_info(m_pMySql),
+ m_rConnection.getConnectionEncoding());
+}
+
+OUString SAL_CALL ODatabaseMetaData::getDatabaseProductName() { return "MySQL"; }
+
+OUString SAL_CALL ODatabaseMetaData::getProcedureTerm() { return "procedure"; }
+
+OUString SAL_CALL ODatabaseMetaData::getSchemaTerm() { return "database"; }
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getDriverMajorVersion()
+{
+ // TODO
+ SAL_WARN("connectivity.mysqlc", "method not implemented");
+ return MARIADBC_VERSION_MAJOR;
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getDefaultTransactionIsolation()
+{
+ return TransactionIsolation::REPEATABLE_READ;
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getDriverMinorVersion()
+{
+ // TODO
+ SAL_WARN("connectivity.mysqlc", "method not implemented");
+ return MARIADBC_VERSION_MINOR;
+}
+
+OUString SAL_CALL ODatabaseMetaData::getSQLKeywords()
+{
+ return "ACCESSIBLE, ADD, ALL,"
+ "ALTER, ANALYZE, AND, AS, ASC, ASENSITIVE, BEFORE,"
+ "BETWEEN, BIGINT, BINARY, BLOB, BOTH, BY, CALL,"
+ "CASCADE, CASE, CHANGE, CHAR, CHARACTER, CHECK,"
+ "COLLATE, COLUMN, CONDITION, CONNECTION, CONSTRAINT,"
+ "CONTINUE, CONVERT, CREATE, CROSS, CURRENT_DATE,"
+ "CURRENT_TIME, CURRENT_TIMESTAMP, CURRENT_USER, CURSOR,"
+ "DATABASE, DATABASES, DAY_HOUR, DAY_MICROSECOND,"
+ "DAY_MINUTE, DAY_SECOND, DEC, DECIMAL, DECLARE,"
+ "DEFAULT, DELAYED, DELETE, DESC, DESCRIBE,"
+ "DETERMINISTIC, DISTINCT, DISTINCTROW, DIV, DOUBLE,"
+ "DROP, DUAL, EACH, ELSE, ELSEIF, ENCLOSED,"
+ "ESCAPED, EXISTS, EXIT, EXPLAIN, FALSE, FETCH,"
+ "FLOAT, FLOAT4, FLOAT8, FOR, FORCE, FOREIGN, FROM,"
+ "FULLTEXT, GRANT, GROUP, HAVING, HIGH_PRIORITY,"
+ "HOUR_MICROSECOND, HOUR_MINUTE, HOUR_SECOND, IF,"
+ "IGNORE, IN, INDEX, INFILE, INNER, INOUT,"
+ "INSENSITIVE, INSERT, INT, INT1, INT2, INT3, INT4,"
+ "INT8, INTEGER, INTERVAL, INTO, IS, ITERATE, JOIN,"
+ "KEY, KEYS, KILL, LEADING, LEAVE, LEFT, LIKE,"
+ "LOCALTIMESTAMP, LOCK, LONG, LONGBLOB, LONGTEXT,"
+ "LOOP, LOW_PRIORITY, MATCH, MEDIUMBLOB, MEDIUMINT,"
+ "MEDIUMTEXT, MIDDLEINT, MINUTE_MICROSECOND,"
+ "MINUTE_SECOND, MOD, MODIFIES, NATURAL, NOT,"
+ "NO_WRITE_TO_BINLOG, NULL, NUMERIC, ON, OPTIMIZE,"
+ "OPTION, OPTIONALLY, OR, ORDER, OUT, OUTER,"
+ "OUTFILE, PRECISION, PRIMARY, PROCEDURE, PURGE,"
+ "RANGE, READ, READS, READ_ONLY, READ_WRITE, REAL,"
+ "REFERENCES, REGEXP, RELEASE, RENAME, REPEAT,"
+ "REPLACE, REQUIRE, RESTRICT, RETURN, REVOKE, RIGHT,"
+ "RLIKE, SCHEMA, SCHEMAS, SECOND_MICROSECOND, SELECT,"
+ "SENSITIVE, SEPARATOR, SET, SHOW, SMALLINT, SPATIAL,"
+ "SPECIFIC, SQL, SQLEXCEPTION, SQLSTATE, SQLWARNING,"
+ "SQL_BIG_RESULT, SQL_CALC_FOUND_ROWS, SQL_SMALL_RESULT,"
+ "SSL, STARTING, STRAIGHT_JOIN, TABLE, TERMINATED,"
+ "THEN, TINYBLOB, TINYINT, TINYTEXT, TO, TRAILING,"
+ "TRIGGER, TRUE, UNDO, UNION, UNIQUE, UNLOCK,"
+ "UNSIGNED, UPDATE, USAGE, USE, USING, UTC_DATE,"
+ "UTC_TIME, UTC_TIMESTAMP, VALUES, VARBINARY, VARCHAR,"
+ "VARCHARACTER, VARYING, WHEN, WHERE, WHILE, WITH,"
+ "WRITE, X509, XOR, YEAR_MONTH, ZEROFILL"
+ "GENERAL, IGNORE_SERVER_IDS, MASTER_HEARTBEAT_PERIOD,"
+ "MAXVALUE, RESIGNAL, SIGNAL, SLOW";
+}
+
+OUString SAL_CALL ODatabaseMetaData::getSearchStringEscape() { return "\\"; }
+
+OUString SAL_CALL ODatabaseMetaData::getStringFunctions()
+{
+ return "ASCII,BIN,BIT_LENGTH,CHAR,CHARACTER_LENGTH,CHAR_LENGTH,CONCAT,"
+ "CONCAT_WS,CONV,ELT,EXPORT_SET,FIELD,FIND_IN_SET,HEX,INSERT,"
+ "INSTR,LCASE,LEFT,LENGTH,LOAD_FILE,LOCATE,LOCATE,LOWER,LPAD,"
+ "LTRIM,MAKE_SET,MATCH,MID,OCT,OCTET_LENGTH,ORD,POSITION,"
+ "QUOTE,REPEAT,REPLACE,REVERSE,RIGHT,RPAD,RTRIM,SOUNDEX,"
+ "SPACE,STRCMP,SUBSTRING,SUBSTRING,SUBSTRING,SUBSTRING,"
+ "SUBSTRING_INDEX,TRIM,UCASE,UPPER";
+}
+
+OUString SAL_CALL ODatabaseMetaData::getTimeDateFunctions()
+{
+ return "DAYOFWEEK,WEEKDAY,DAYOFMONTH,DAYOFYEAR,MONTH,DAYNAME,"
+ "MONTHNAME,QUARTER,WEEK,YEAR,HOUR,MINUTE,SECOND,PERIOD_ADD,"
+ "PERIOD_DIFF,TO_DAYS,FROM_DAYS,DATE_FORMAT,TIME_FORMAT,"
+ "CURDATE,CURRENT_DATE,CURTIME,CURRENT_TIME,NOW,SYSDATE,"
+ "CURRENT_TIMESTAMP,UNIX_TIMESTAMP,FROM_UNIXTIME,"
+ "SEC_TO_TIME,TIME_TO_SEC";
+}
+
+OUString SAL_CALL ODatabaseMetaData::getSystemFunctions()
+{
+ return "DATABASE,USER,SYSTEM_USER,"
+ "SESSION_USER,PASSWORD,ENCRYPT,LAST_INSERT_ID,VERSION";
+}
+
+OUString SAL_CALL ODatabaseMetaData::getNumericFunctions()
+{
+ return "ABS,ACOS,ASIN,ATAN,ATAN2,BIT_COUNT,CEILING,COS,"
+ "COT,DEGREES,EXP,FLOOR,LOG,LOG10,MAX,MIN,MOD,PI,POW,"
+ "POWER,RADIANS,RAND,ROUND,SIN,SQRT,TAN,TRUNCATE";
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsExtendedSQLGrammar() { return false; }
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsCoreSQLGrammar() { return true; }
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsMinimumSQLGrammar() { return true; }
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsFullOuterJoins() { return false; }
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsLimitedOuterJoins() { return true; }
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxColumnsInGroupBy() { return 64; }
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxColumnsInOrderBy() { return 64; }
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxColumnsInSelect() { return 256; }
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxUserNameLength() { return 16; }
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsResultSetType(sal_Int32 setType)
+{
+ return setType == ResultSetType::SCROLL_SENSITIVE;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsResultSetConcurrency(sal_Int32 /*setType*/,
+ sal_Int32 /*concurrency*/)
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::ownUpdatesAreVisible(sal_Int32 /*setType*/) { return false; }
+
+sal_Bool SAL_CALL ODatabaseMetaData::ownDeletesAreVisible(sal_Int32 /*setType*/) { return false; }
+
+sal_Bool SAL_CALL ODatabaseMetaData::ownInsertsAreVisible(sal_Int32 /*setType*/) { return false; }
+
+sal_Bool SAL_CALL ODatabaseMetaData::othersUpdatesAreVisible(sal_Int32 /*setType*/)
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::othersDeletesAreVisible(sal_Int32 /*setType*/)
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::othersInsertsAreVisible(sal_Int32 /*setType*/)
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::updatesAreDetected(sal_Int32 /*setType*/) { return false; }
+
+sal_Bool SAL_CALL ODatabaseMetaData::deletesAreDetected(sal_Int32 /*setType*/) { return false; }
+
+sal_Bool SAL_CALL ODatabaseMetaData::insertsAreDetected(sal_Int32 /*setType*/) { return false; }
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsBatchUpdates() { return false; }
+
+Reference<XConnection> SAL_CALL ODatabaseMetaData::getConnection() { return &m_rConnection; }
+
+/*
+ Here follow all methods which return(a resultset
+ the first methods is an example implementation how to use this resultset
+ of course you could implement it on your and you should do this because
+ the general way is more memory expensive
+*/
+
+Reference<XResultSet> SAL_CALL ODatabaseMetaData::getTableTypes()
+{
+ const char* const table_types[] = { "TABLE", "VIEW" };
+ sal_Int32 const requiredVersion[] = { 0, 50000 };
+
+ Reference<XResultSet> xResultSet(getOwnConnection().getDriver().getFactory()->createInstance(
+ "org.openoffice.comp.helper.DatabaseMetaDataResultSet"),
+ UNO_QUERY);
+ std::vector<std::vector<Any>> rRows;
+ rtl_TextEncoding encoding = m_rConnection.getConnectionEncoding();
+
+ for (sal_uInt32 i = 0; i < 2; i++)
+ {
+ if (m_rConnection.getMysqlVersion() >= requiredVersion[i])
+ {
+ rRows.push_back(
+ { { Any(), Any(mysqlc_sdbc_driver::convert(table_types[i], encoding)) } });
+ }
+ }
+ lcl_setRows_throw(xResultSet, 5, rRows);
+ return xResultSet;
+}
+
+Reference<XResultSet> SAL_CALL ODatabaseMetaData::getTypeInfo()
+{
+ Reference<XResultSet> xResultSet(getOwnConnection().getDriver().getFactory()->createInstance(
+ "org.openoffice.comp.helper.DatabaseMetaDataResultSet"),
+ UNO_QUERY);
+
+ std::vector<std::vector<Any>> rRows;
+
+ rtl_TextEncoding encoding = m_rConnection.getConnectionEncoding();
+ unsigned int i = 0;
+ while (mysqlc_types[i].typeName)
+ {
+ rRows.push_back(
+ { { Any(), Any(mysqlc_sdbc_driver::convert(mysqlc_types[i].typeName, encoding)),
+ Any(mysqlc_types[i].dataType), Any(mysqlc_types[i].precision),
+ Any(mysqlc_sdbc_driver::convert(mysqlc_types[i].literalPrefix, encoding)),
+ Any(mysqlc_sdbc_driver::convert(mysqlc_types[i].literalSuffix, encoding)),
+ Any(mysqlc_sdbc_driver::convert(mysqlc_types[i].createParams, encoding)),
+ Any(mysqlc_types[i].nullable), Any(mysqlc_types[i].caseSensitive),
+ Any(mysqlc_types[i].searchable), Any(mysqlc_types[i].isUnsigned),
+ Any(mysqlc_types[i].fixedPrecScale), Any(mysqlc_types[i].autoIncrement),
+ Any(mysqlc_sdbc_driver::convert(mysqlc_types[i].localTypeName, encoding)),
+ Any(mysqlc_types[i].minScale), Any(mysqlc_types[i].maxScale), Any(sal_Int32(0)),
+ Any(sal_Int32(0)), Any(sal_Int32(10)) } });
+
+ i++;
+ }
+
+ lcl_setRows_throw(xResultSet, 14, rRows);
+ return xResultSet;
+}
+
+Reference<XResultSet> SAL_CALL ODatabaseMetaData::getCatalogs()
+{
+ Reference<XResultSet> xResultSet(getOwnConnection().getDriver().getFactory()->createInstance(
+ "org.openoffice.comp.helper.DatabaseMetaDataResultSet"),
+ UNO_QUERY);
+ return xResultSet;
+}
+
+Reference<XResultSet> SAL_CALL ODatabaseMetaData::getSchemas()
+{
+ Reference<XResultSet> xResultSet(getOwnConnection().getDriver().getFactory()->createInstance(
+ "org.openoffice.comp.helper.DatabaseMetaDataResultSet"),
+ UNO_QUERY);
+ std::vector<std::vector<Any>> rRows;
+
+ Reference<XStatement> statement = m_rConnection.createStatement();
+ Reference<XInterface> executed = statement->executeQuery(
+ u"SELECT SCHEMA_NAME AS TABLE_SCHEM, CATALOG_NAME AS TABLE_CATALOG FROM INFORMATION_SCHEMA.SCHEMATA \
+ WHERE SCHEMA_NAME NOT IN ('information_schema', 'mysql', 'performance_schema') \
+ ORDER BY SCHEMA_NAME"_ustr);
+ Reference<XResultSet> rs(executed, UNO_QUERY_THROW);
+ Reference<XResultSetMetaDataSupplier> supp(executed, UNO_QUERY_THROW);
+ Reference<XResultSetMetaData> rs_meta = supp->getMetaData();
+
+ Reference<XRow> xRow(rs, UNO_QUERY_THROW);
+ sal_uInt32 columns = rs_meta->getColumnCount();
+ while (rs->next())
+ {
+ std::vector<Any> aRow{ Any() };
+ for (sal_uInt32 i = 1; i <= columns; i++)
+ {
+ OUString columnStringValue = xRow->getString(i);
+ aRow.push_back(Any(columnStringValue));
+ }
+ rRows.push_back(aRow);
+ }
+
+ lcl_setRows_throw(xResultSet, 1, rRows);
+ return xResultSet;
+}
+
+Reference<XResultSet>
+ SAL_CALL ODatabaseMetaData::getColumnPrivileges(const Any& /*catalog*/, const OUString& schema,
+ const OUString& table,
+ const OUString& columnNamePattern)
+{
+ OUString query("SELECT TABLE_CATALOG AS TABLE_CAT, TABLE_SCHEMA AS "
+ "TABLE_SCHEM, TABLE_NAME, COLUMN_NAME, NULL AS GRANTOR, "
+ "GRANTEE, PRIVILEGE_TYPE AS PRIVILEGE, IS_GRANTABLE FROM "
+ "INFORMATION_SCHEMA.COLUMN_PRIVILEGES WHERE TABLE_SCHEMA LIKE "
+ "'?' AND TABLE_NAME='?' AND COLUMN_NAME LIKE '?' ORDER BY "
+ "COLUMN_NAME, PRIVILEGE_TYPE");
+
+ query = query.replaceFirst("?", schema);
+ query = query.replaceFirst("?", table);
+ query = query.replaceFirst("?", columnNamePattern);
+
+ Reference<XStatement> statement = m_rConnection.createStatement();
+ Reference<XResultSet> rs = statement->executeQuery(query);
+ return rs;
+}
+
+Reference<XResultSet> SAL_CALL ODatabaseMetaData::getColumns(const Any& /*catalog*/,
+ const OUString& schemaPattern,
+ const OUString& tableNamePattern,
+ const OUString& columnNamePattern)
+{
+ OUStringBuffer queryBuf("SELECT TABLE_CATALOG, " // 1
+ "TABLE_SCHEMA, " // 2
+ "TABLE_NAME, " // 3
+ "COLUMN_NAME, " // 4
+ "DATA_TYPE, " // 5
+ // TYPE_NAME missing
+ "CHARACTER_MAXIMUM_LENGTH, " // 6
+ "NUMERIC_PRECISION, " // 7
+ // buffer length missing
+ "NUMERIC_SCALE AS DECIMAL_DIGITS, " // 8
+ // NUM_PREC_RADIX missing
+ // NULLABLE missing
+ "COLUMN_COMMENT AS REMARKS, " // 9
+ "COLUMN_DEFAULT AS COLUMN_DEF," // 10
+ "CHARACTER_OCTET_LENGTH, " // 11
+ "ORDINAL_POSITION, " // 12
+ "IS_NULLABLE, " // 13
+ "COLUMN_TYPE " // 14
+ "FROM INFORMATION_SCHEMA.COLUMNS "
+ "WHERE (1 = 1) ");
+ if (!tableNamePattern.isEmpty())
+ {
+ OUString sAppend;
+ if (tableNamePattern.match("%"))
+ sAppend = "AND TABLE_NAME LIKE '%' ";
+ else
+ sAppend = "AND TABLE_NAME = '%' ";
+ queryBuf.append(sAppend.replaceAll("%", tableNamePattern));
+ }
+ if (!schemaPattern.isEmpty())
+ {
+ OUString sAppend;
+ if (schemaPattern.match("%"))
+ sAppend = "AND TABLE_SCHEMA LIKE '%' ";
+ else
+ sAppend = "AND TABLE_SCHEMA = '%' ";
+ queryBuf.append(sAppend.replaceAll("%", schemaPattern));
+ }
+ if (!columnNamePattern.isEmpty())
+ {
+ OUString sAppend;
+ if (columnNamePattern.match("%"))
+ sAppend = "AND COLUMN_NAME LIKE '%' ";
+ else
+ sAppend = "AND COLUMN_NAME = '%' ";
+ queryBuf.append(sAppend.replaceAll("%", columnNamePattern));
+ }
+
+ OUString query = queryBuf.makeStringAndClear();
+ Reference<XStatement> statement = m_rConnection.createStatement();
+ Reference<XResultSet> rs = statement->executeQuery(query);
+ Reference<XRow> xRow(rs, UNO_QUERY_THROW);
+
+ Reference<XResultSet> xResultSet(getOwnConnection().getDriver().getFactory()->createInstance(
+ "org.openoffice.comp.helper.DatabaseMetaDataResultSet"),
+ UNO_QUERY);
+ std::vector<std::vector<Any>> aRows;
+ while (rs->next())
+ {
+ std::vector<Any> aRow{ Any() }; // 0. element is unused
+
+ // catalog name
+ aRow.push_back(Any(xRow->getString(1)));
+ // schema name
+ aRow.push_back(Any(xRow->getString(2)));
+ // table name
+ aRow.push_back(Any(xRow->getString(3)));
+ // column name
+ aRow.push_back(Any(xRow->getString(4)));
+ // data type
+ OUString sDataType = xRow->getString(5);
+ aRow.push_back(Any(mysqlc_sdbc_driver::mysqlStrToOOOType(sDataType)));
+ // type name
+ aRow.push_back(Any(sDataType)); // TODO
+ // column size
+ sal_Int32 nColumnSize = 0;
+ OUString sColumnType = xRow->getString(14);
+ sal_Int32 nCharMaxLen = xRow->getShort(6);
+ bool bIsCharMax = !xRow->wasNull();
+ if (sDataType.equalsIgnoreAsciiCase("year"))
+ nColumnSize = o3tl::toInt32(sColumnType.subView(6, 1)); // 'year(' length is 5
+ else if (sDataType.equalsIgnoreAsciiCase("date"))
+ nColumnSize = 10;
+ else if (sDataType.equalsIgnoreAsciiCase("time"))
+ nColumnSize = 8;
+ else if (sDataType.equalsIgnoreAsciiCase("datetime")
+ || sDataType.equalsIgnoreAsciiCase("timestamp"))
+ nColumnSize = 19;
+ else if (!bIsCharMax)
+ nColumnSize = xRow->getShort(7); // numeric precision
+ else
+ nColumnSize = nCharMaxLen;
+ aRow.push_back(Any(nColumnSize));
+ aRow.push_back(Any()); // buffer length - unused
+ // decimal digits (scale)
+ aRow.push_back(Any(xRow->getShort(8)));
+ // num_prec_radix
+ aRow.push_back(Any(sal_Int32(10)));
+ // nullable
+ OUString sIsNullable = xRow->getString(13);
+ if (xRow->wasNull())
+ aRow.push_back(Any(ColumnValue::NULLABLE_UNKNOWN));
+ else if (sIsNullable.equalsIgnoreAsciiCase("YES"))
+ aRow.push_back(Any(ColumnValue::NULLABLE));
+ else
+ aRow.push_back(Any(ColumnValue::NO_NULLS));
+ // remarks
+ aRow.push_back(Any(xRow->getString(9)));
+ // default
+ aRow.push_back(Any(xRow->getString(10)));
+
+ aRow.push_back(Any{}); // sql_data_type - unused
+ aRow.push_back(Any{}); // sql_datetime_sub - unused
+
+ // character octet length
+ aRow.push_back(Any(xRow->getString(11)));
+ // ordinal position
+ aRow.push_back(Any(xRow->getString(12)));
+ // is nullable
+ aRow.push_back(Any(sIsNullable));
+ aRows.push_back(aRow);
+ }
+ lcl_setRows_throw(xResultSet, 1, aRows);
+ return xResultSet;
+}
+
+Reference<XResultSet> SAL_CALL ODatabaseMetaData::getTables(const Any& /*catalog*/,
+ const OUString& schemaPattern,
+ const OUString& tableNamePattern,
+ const Sequence<OUString>& types)
+{
+ OUStringBuffer buffer{
+ "SELECT TABLE_CATALOG AS TABLE_CAT, TABLE_SCHEMA AS TABLE_SCHEM, TABLE_NAME,"
+ "IF(STRCMP(TABLE_TYPE,'BASE TABLE'), TABLE_TYPE, 'TABLE') AS TABLE_TYPE, TABLE_COMMENT AS "
+ "REMARKS "
+ "FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA NOT IN ('information_schema', 'mysql', "
+ "'performance_schema') AND TABLE_SCHEMA LIKE '?' AND TABLE_NAME LIKE '?' "
+ };
+
+ if (types.getLength() == 1)
+ {
+ buffer.append("AND TABLE_TYPE LIKE '" + types[0] + "'");
+ }
+ else if (types.getLength() > 1)
+ {
+ buffer.append("AND (TABLE_TYPE LIKE '" + types[0] + "'");
+ for (sal_Int32 i = 1; i < types.getLength(); ++i)
+ {
+ buffer.append(" OR TABLE_TYPE LIKE '" + types[i] + "'");
+ }
+ buffer.append(")");
+ }
+
+ buffer.append(" ORDER BY TABLE_TYPE, TABLE_SCHEMA, TABLE_NAME");
+ OUString query = buffer.makeStringAndClear();
+
+ // TODO use prepared stmt instead
+ // TODO escape schema, table name ?
+ query = query.replaceFirst("?", schemaPattern);
+ query = query.replaceFirst("?", tableNamePattern);
+
+ Reference<XStatement> statement = m_rConnection.createStatement();
+ Reference<XResultSet> rs = statement->executeQuery(query);
+ return rs;
+}
+
+Reference<XResultSet> SAL_CALL ODatabaseMetaData::getProcedureColumns(
+ const Any& /* catalog */, const OUString& /* schemaPattern */,
+ const OUString& /* procedureNamePattern */, const OUString& /* columnNamePattern */)
+{
+ // Currently there is no information available
+ return nullptr;
+}
+
+Reference<XResultSet>
+ SAL_CALL ODatabaseMetaData::getProcedures(const Any& /*catalog*/,
+ const OUString& /*schemaPattern*/,
+ const OUString& /*procedureNamePattern*/)
+{
+ Reference<XResultSet> xResultSet(getOwnConnection().getDriver().getFactory()->createInstance(
+ "org.openoffice.comp.helper.DatabaseMetaDataResultSet"),
+ UNO_QUERY);
+ std::vector<std::vector<Any>> rRows;
+ // TODO IMPL
+ SAL_WARN("connectivity.mysqlc", "method not implemented");
+ lcl_setRows_throw(xResultSet, 7, rRows);
+ return xResultSet;
+}
+
+Reference<XResultSet> SAL_CALL ODatabaseMetaData::getVersionColumns(const Any& /* catalog */,
+ const OUString& /* schema */,
+ const OUString& /* table */)
+{
+ Reference<XResultSet> xResultSet(getOwnConnection().getDriver().getFactory()->createInstance(
+ "org.openoffice.comp.helper.DatabaseMetaDataResultSet"),
+ UNO_QUERY);
+ std::vector<std::vector<Any>> rRows;
+ lcl_setRows_throw(xResultSet, 16, rRows);
+ return xResultSet;
+}
+
+Reference<XResultSet> SAL_CALL ODatabaseMetaData::getExportedKeys(const Any& /*catalog */,
+ const OUString& /*schema */,
+ const OUString& /*table */)
+{
+ Reference<XResultSet> xResultSet(getOwnConnection().getDriver().getFactory()->createInstance(
+ "org.openoffice.comp.helper.DatabaseMetaDataResultSet"),
+ UNO_QUERY);
+ std::vector<std::vector<Any>> rRows;
+ // TODO implement
+ SAL_WARN("connectivity.mysqlc", "method not implemented");
+ lcl_setRows_throw(xResultSet, 8, rRows);
+ return xResultSet;
+}
+
+Reference<XResultSet> SAL_CALL ODatabaseMetaData::getImportedKeys(const Any& /*catalog*/,
+ const OUString& schema,
+ const OUString& table)
+{
+ Reference<XResultSet> xResultSet(getOwnConnection().getDriver().getFactory()->createInstance(
+ "org.openoffice.comp.helper.DatabaseMetaDataResultSet"),
+ UNO_QUERY);
+
+ OUString query("SELECT refi.CONSTRAINT_CATALOG," // 1: foreign catalog
+ " k.COLUMN_NAME," // 2: foreign column name
+ " refi.UNIQUE_CONSTRAINT_CATALOG," // 3: primary catalog FIXME
+ " k.REFERENCED_TABLE_SCHEMA," // 4: primary schema
+ " refi.REFERENCED_TABLE_NAME," // 5: primary table name
+ " k.REFERENCED_COLUMN_NAME," // 6: primary column name
+ " refi.UPDATE_RULE, refi.DELETE_RULE," // 7,8: update, delete rule
+ " refi.CONSTRAINT_NAME, " // 9: name of constraint itself
+ " refi.TABLE_NAME, " // 10: foreign table name
+ " refi.CONSTRAINT_SCHEMA " // 11: foreign schema name FIXME
+ " FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS as refi"
+ " INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE as k ON k.CONSTRAINT_NAME = "
+ "refi.CONSTRAINT_NAME "
+ " and k.TABLE_NAME = refi.TABLE_NAME "
+ " WHERE k.REFERENCED_TABLE_SCHEMA LIKE "
+ "'?' AND refi.TABLE_NAME='?'");
+ query = query.replaceFirst("?", schema); // TODO what if schema is NULL?
+ query = query.replaceFirst("?", table);
+
+ std::vector<std::vector<Any>> aRows;
+ Reference<XStatement> statement = m_rConnection.createStatement();
+ Reference<XResultSet> rs = statement->executeQuery(query);
+ Reference<XRow> xRow(rs, UNO_QUERY_THROW);
+
+ while (rs->next())
+ {
+ std::vector<Any> aRow{ Any() }; // 0. element is unused
+
+ // primary key catalog
+ aRow.push_back(Any(xRow->getString(3)));
+ // primary key schema
+ aRow.push_back(Any(xRow->getString(4)));
+ // primary key table
+ aRow.push_back(Any(xRow->getString(5)));
+ // primary column name
+ aRow.push_back(Any(xRow->getString(6)));
+
+ // fk table catalog
+ aRow.push_back(Any(xRow->getString(1)));
+ // fk schema
+ aRow.push_back(Any(xRow->getString(11)));
+ // fk table
+ aRow.push_back(Any(xRow->getString(10)));
+ // fk column name
+ aRow.push_back(Any(xRow->getString(2)));
+ // KEY_SEQ
+ aRow.push_back(Any(sal_Int32{ 0 })); // TODO
+ // update rule
+ aRow.push_back(Any(xRow->getShort(7)));
+ // delete rule
+ aRow.push_back(Any(xRow->getShort(8)));
+ // foreign key name
+ aRow.push_back(Any(xRow->getString(9)));
+ // primary key name
+ aRow.push_back(Any(OUString{})); // TODO
+ // deferrability
+ aRow.push_back(Any(Deferrability::NONE));
+ aRows.push_back(aRow);
+ }
+ lcl_setRows_throw(xResultSet, 1, aRows);
+ return xResultSet;
+}
+
+Reference<XResultSet> SAL_CALL ODatabaseMetaData::getPrimaryKeys(const Any& /*catalog*/,
+ const OUString& schema,
+ const OUString& table)
+{
+ OUString query("SELECT TABLE_CATALOG AS TABLE_CAT, TABLE_SCHEMA "
+ "AS TABLE_SCHEM, TABLE_NAME, "
+ "COLUMN_NAME, SEQ_IN_INDEX AS KEY_SEQ,"
+ "INDEX_NAME AS PK_NAME FROM INFORMATION_SCHEMA.STATISTICS "
+ "WHERE TABLE_SCHEMA LIKE '?' AND TABLE_NAME LIKE '?' AND INDEX_NAME='PRIMARY' "
+ "ORDER BY TABLE_SCHEMA, TABLE_NAME, INDEX_NAME, SEQ_IN_INDEX");
+
+ // TODO use prepared stmt instead
+ // TODO escape schema, table name ?
+ query = query.replaceFirst("?", schema);
+ query = query.replaceFirst("?", table);
+
+ Reference<XStatement> statement = m_rConnection.createStatement();
+ Reference<XResultSet> rs = statement->executeQuery(query);
+ return rs;
+}
+
+Reference<XResultSet> SAL_CALL ODatabaseMetaData::getIndexInfo(const Any& /*catalog*/,
+ const OUString& /*schema*/,
+ const OUString& /*table*/,
+ sal_Bool /*unique*/,
+ sal_Bool /*approximate*/)
+{
+ Reference<XResultSet> xResultSet(getOwnConnection().getDriver().getFactory()->createInstance(
+ "org.openoffice.comp.helper.DatabaseMetaDataResultSet"),
+ UNO_QUERY);
+ std::vector<std::vector<Any>> rRows;
+ // TODO
+ SAL_WARN("connectivity.mysqlc", "method not implemented");
+ lcl_setRows_throw(xResultSet, 11, rRows);
+ return xResultSet;
+}
+
+Reference<XResultSet> SAL_CALL ODatabaseMetaData::getBestRowIdentifier(const Any& /*catalog*/,
+ const OUString& /*schema*/,
+ const OUString& /*table*/,
+ sal_Int32 /*scope*/,
+ sal_Bool /*nullable*/)
+{
+ Reference<XResultSet> xResultSet(getOwnConnection().getDriver().getFactory()->createInstance(
+ "org.openoffice.comp.helper.DatabaseMetaDataResultSet"),
+ UNO_QUERY);
+ std::vector<std::vector<Any>> rRows;
+ // TODO
+ SAL_WARN("connectivity.mysqlc", "method not implemented");
+ lcl_setRows_throw(xResultSet, 15, rRows);
+ return xResultSet;
+}
+
+Reference<XResultSet> SAL_CALL ODatabaseMetaData::getTablePrivileges(
+ const Any& /* catalog */, const OUString& schemaPattern, const OUString& tableNamePattern)
+{
+ OUString query("SELECT TABLE_SCHEMA TABLE_CAT, "
+ "NULL TABLE_SCHEM, "
+ "TABLE_NAME, "
+ "NULL GRANTOR,"
+ "GRANTEE, "
+ "PRIVILEGE_TYPE PRIVILEGE, "
+ "IS_GRANTABLE "
+ "FROM INFORMATION_SCHEMA.TABLE_PRIVILEGES "
+ "WHERE TABLE_SCHEMA LIKE '?' "
+ "AND TABLE_NAME='?'");
+ query = query.replaceFirst("?", schemaPattern);
+ query = query.replaceFirst("?", tableNamePattern);
+ Reference<XStatement> statement = m_rConnection.createStatement();
+ Reference<XResultSet> rs = statement->executeQuery(query);
+ return rs;
+}
+
+Reference<XResultSet> SAL_CALL ODatabaseMetaData::getCrossReference(
+ const Any& /*primaryCatalog*/, const OUString& /*primarySchema_*/,
+ const OUString& /*primaryTable_*/, const Any& /*foreignCatalog*/,
+ const OUString& /*foreignSchema*/, const OUString& /*foreignTable*/)
+{
+ Reference<XResultSet> xResultSet(getOwnConnection().getDriver().getFactory()->createInstance(
+ "org.openoffice.comp.helper.DatabaseMetaDataResultSet"),
+ UNO_QUERY);
+ std::vector<std::vector<Any>> rRows;
+ // TODO
+ SAL_WARN("connectivity.mysqlc", "method not implemented");
+ lcl_setRows_throw(xResultSet, 13, rRows);
+ return xResultSet;
+}
+
+Reference<XResultSet> SAL_CALL ODatabaseMetaData::getUDTs(const Any& /* catalog */,
+ const OUString& /* schemaPattern */,
+ const OUString& /* typeNamePattern */,
+ const Sequence<sal_Int32>& /* types */)
+{
+ mysqlc_sdbc_driver::throwFeatureNotImplementedException("ODatabaseMetaData::getUDTs", *this);
+ return nullptr;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/mysqlc/mysqlc_databasemetadata.hxx b/connectivity/source/drivers/mysqlc/mysqlc_databasemetadata.hxx
new file mode 100644
index 0000000000..caed92f20e
--- /dev/null
+++ b/connectivity/source/drivers/mysqlc/mysqlc_databasemetadata.hxx
@@ -0,0 +1,233 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "mysqlc_connection.hxx"
+
+#include <com/sun/star/sdbc/XDatabaseMetaData.hpp>
+#include <cppuhelper/implbase1.hxx>
+
+namespace connectivity::mysqlc
+{
+using ::com::sun::star::uno::Any;
+
+//************ Class: ODatabaseMetaData
+
+typedef ::cppu::WeakImplHelper1<css::sdbc::XDatabaseMetaData> ODatabaseMetaData_BASE;
+
+class ODatabaseMetaData final : public ODatabaseMetaData_BASE
+{
+ OConnection& m_rConnection;
+ MYSQL* m_pMySql;
+
+public:
+ const OConnection& getOwnConnection() const { return m_rConnection; }
+
+ explicit ODatabaseMetaData(OConnection& _rCon, MYSQL* pMySql);
+ virtual ~ODatabaseMetaData() override;
+
+ // as I mentioned before this interface is really BIG
+ // XDatabaseMetaData
+ sal_Bool SAL_CALL allProceduresAreCallable() override;
+ sal_Bool SAL_CALL allTablesAreSelectable() override;
+ OUString SAL_CALL getURL() override;
+ OUString SAL_CALL getUserName() override;
+ sal_Bool SAL_CALL isReadOnly() override;
+ sal_Bool SAL_CALL nullsAreSortedHigh() override;
+ sal_Bool SAL_CALL nullsAreSortedLow() override;
+ sal_Bool SAL_CALL nullsAreSortedAtStart() override;
+ sal_Bool SAL_CALL nullsAreSortedAtEnd() override;
+ OUString SAL_CALL getDatabaseProductName() override;
+ OUString SAL_CALL getDatabaseProductVersion() override;
+ OUString SAL_CALL getDriverName() override;
+ OUString SAL_CALL getDriverVersion() override;
+ sal_Int32 SAL_CALL getDriverMajorVersion() override;
+ sal_Int32 SAL_CALL getDriverMinorVersion() override;
+ sal_Bool SAL_CALL usesLocalFiles() override;
+ sal_Bool SAL_CALL usesLocalFilePerTable() override;
+ sal_Bool SAL_CALL supportsMixedCaseIdentifiers() override;
+ sal_Bool SAL_CALL storesUpperCaseIdentifiers() override;
+ sal_Bool SAL_CALL storesLowerCaseIdentifiers() override;
+ sal_Bool SAL_CALL storesMixedCaseIdentifiers() override;
+ sal_Bool SAL_CALL supportsMixedCaseQuotedIdentifiers() override;
+ sal_Bool SAL_CALL storesUpperCaseQuotedIdentifiers() override;
+ sal_Bool SAL_CALL storesLowerCaseQuotedIdentifiers() override;
+ sal_Bool SAL_CALL storesMixedCaseQuotedIdentifiers() override;
+ OUString SAL_CALL getIdentifierQuoteString() override;
+ OUString SAL_CALL getSQLKeywords() override;
+ OUString SAL_CALL getNumericFunctions() override;
+ OUString SAL_CALL getStringFunctions() override;
+ OUString SAL_CALL getSystemFunctions() override;
+ OUString SAL_CALL getTimeDateFunctions() override;
+ OUString SAL_CALL getSearchStringEscape() override;
+ OUString SAL_CALL getExtraNameCharacters() override;
+ sal_Bool SAL_CALL supportsAlterTableWithAddColumn() override;
+ sal_Bool SAL_CALL supportsAlterTableWithDropColumn() override;
+ sal_Bool SAL_CALL supportsColumnAliasing() override;
+ sal_Bool SAL_CALL nullPlusNonNullIsNull() override;
+ sal_Bool SAL_CALL supportsTypeConversion() override;
+ sal_Bool SAL_CALL supportsConvert(sal_Int32 fromType, sal_Int32 toType) override;
+ sal_Bool SAL_CALL supportsTableCorrelationNames() override;
+ sal_Bool SAL_CALL supportsDifferentTableCorrelationNames() override;
+ sal_Bool SAL_CALL supportsExpressionsInOrderBy() override;
+ sal_Bool SAL_CALL supportsOrderByUnrelated() override;
+ sal_Bool SAL_CALL supportsGroupBy() override;
+ sal_Bool SAL_CALL supportsGroupByUnrelated() override;
+ sal_Bool SAL_CALL supportsGroupByBeyondSelect() override;
+ sal_Bool SAL_CALL supportsLikeEscapeClause() override;
+ sal_Bool SAL_CALL supportsMultipleResultSets() override;
+ sal_Bool SAL_CALL supportsMultipleTransactions() override;
+ sal_Bool SAL_CALL supportsNonNullableColumns() override;
+ sal_Bool SAL_CALL supportsMinimumSQLGrammar() override;
+ sal_Bool SAL_CALL supportsCoreSQLGrammar() override;
+ sal_Bool SAL_CALL supportsExtendedSQLGrammar() override;
+ sal_Bool SAL_CALL supportsANSI92EntryLevelSQL() override;
+ sal_Bool SAL_CALL supportsANSI92IntermediateSQL() override;
+ sal_Bool SAL_CALL supportsANSI92FullSQL() override;
+ sal_Bool SAL_CALL supportsIntegrityEnhancementFacility() override;
+ sal_Bool SAL_CALL supportsOuterJoins() override;
+ sal_Bool SAL_CALL supportsFullOuterJoins() override;
+ sal_Bool SAL_CALL supportsLimitedOuterJoins() override;
+ OUString SAL_CALL getSchemaTerm() override;
+ OUString SAL_CALL getProcedureTerm() override;
+ OUString SAL_CALL getCatalogTerm() override;
+ sal_Bool SAL_CALL isCatalogAtStart() override;
+ OUString SAL_CALL getCatalogSeparator() override;
+ sal_Bool SAL_CALL supportsSchemasInDataManipulation() override;
+ sal_Bool SAL_CALL supportsSchemasInProcedureCalls() override;
+ sal_Bool SAL_CALL supportsSchemasInTableDefinitions() override;
+ sal_Bool SAL_CALL supportsSchemasInIndexDefinitions() override;
+ sal_Bool SAL_CALL supportsSchemasInPrivilegeDefinitions() override;
+ sal_Bool SAL_CALL supportsCatalogsInDataManipulation() override;
+ sal_Bool SAL_CALL supportsCatalogsInProcedureCalls() override;
+ sal_Bool SAL_CALL supportsCatalogsInTableDefinitions() override;
+ sal_Bool SAL_CALL supportsCatalogsInIndexDefinitions() override;
+ sal_Bool SAL_CALL supportsCatalogsInPrivilegeDefinitions() override;
+ sal_Bool SAL_CALL supportsPositionedDelete() override;
+ sal_Bool SAL_CALL supportsPositionedUpdate() override;
+ sal_Bool SAL_CALL supportsSelectForUpdate() override;
+ sal_Bool SAL_CALL supportsStoredProcedures() override;
+ sal_Bool SAL_CALL supportsSubqueriesInComparisons() override;
+ sal_Bool SAL_CALL supportsSubqueriesInExists() override;
+ sal_Bool SAL_CALL supportsSubqueriesInIns() override;
+ sal_Bool SAL_CALL supportsSubqueriesInQuantifieds() override;
+ sal_Bool SAL_CALL supportsCorrelatedSubqueries() override;
+ sal_Bool SAL_CALL supportsUnion() override;
+ sal_Bool SAL_CALL supportsUnionAll() override;
+ sal_Bool SAL_CALL supportsOpenCursorsAcrossCommit() override;
+ sal_Bool SAL_CALL supportsOpenCursorsAcrossRollback() override;
+ sal_Bool SAL_CALL supportsOpenStatementsAcrossCommit() override;
+ sal_Bool SAL_CALL supportsOpenStatementsAcrossRollback() override;
+ sal_Int32 SAL_CALL getMaxBinaryLiteralLength() override;
+ sal_Int32 SAL_CALL getMaxCharLiteralLength() override;
+ sal_Int32 SAL_CALL getMaxColumnNameLength() override;
+ sal_Int32 SAL_CALL getMaxColumnsInGroupBy() override;
+ sal_Int32 SAL_CALL getMaxColumnsInIndex() override;
+ sal_Int32 SAL_CALL getMaxColumnsInOrderBy() override;
+ sal_Int32 SAL_CALL getMaxColumnsInSelect() override;
+ sal_Int32 SAL_CALL getMaxColumnsInTable() override;
+ sal_Int32 SAL_CALL getMaxConnections() override;
+ sal_Int32 SAL_CALL getMaxCursorNameLength() override;
+ sal_Int32 SAL_CALL getMaxIndexLength() override;
+ sal_Int32 SAL_CALL getMaxSchemaNameLength() override;
+ sal_Int32 SAL_CALL getMaxProcedureNameLength() override;
+ sal_Int32 SAL_CALL getMaxCatalogNameLength() override;
+ sal_Int32 SAL_CALL getMaxRowSize() override;
+ sal_Bool SAL_CALL doesMaxRowSizeIncludeBlobs() override;
+ sal_Int32 SAL_CALL getMaxStatementLength() override;
+ sal_Int32 SAL_CALL getMaxStatements() override;
+ sal_Int32 SAL_CALL getMaxTableNameLength() override;
+ sal_Int32 SAL_CALL getMaxTablesInSelect() override;
+ sal_Int32 SAL_CALL getMaxUserNameLength() override;
+ sal_Int32 SAL_CALL getDefaultTransactionIsolation() override;
+ sal_Bool SAL_CALL supportsTransactions() override;
+ sal_Bool SAL_CALL supportsTransactionIsolationLevel(sal_Int32 level) override;
+ sal_Bool SAL_CALL supportsDataDefinitionAndDataManipulationTransactions() override;
+ sal_Bool SAL_CALL supportsDataManipulationTransactionsOnly() override;
+ sal_Bool SAL_CALL dataDefinitionCausesTransactionCommit() override;
+ sal_Bool SAL_CALL dataDefinitionIgnoredInTransactions() override;
+ css::uno::Reference<css::sdbc::XResultSet>
+ SAL_CALL getProcedures(const Any& catalog, const OUString& schemaPattern,
+ const OUString& procedureNamePattern) override;
+ css::uno::Reference<css::sdbc::XResultSet>
+ SAL_CALL getProcedureColumns(const Any& catalog, const OUString& schemaPattern,
+ const OUString& procedureNamePattern,
+ const OUString& columnNamePattern) override;
+ css::uno::Reference<css::sdbc::XResultSet>
+ SAL_CALL getTables(const Any& catalog, const OUString& schemaPattern,
+ const OUString& tableNamePattern,
+ const css::uno::Sequence<OUString>& types) override;
+ css::uno::Reference<css::sdbc::XResultSet> SAL_CALL getSchemas() override;
+ css::uno::Reference<css::sdbc::XResultSet> SAL_CALL getCatalogs() override;
+ css::uno::Reference<css::sdbc::XResultSet> SAL_CALL getTableTypes() override;
+ virtual css::uno::Reference<css::sdbc::XResultSet>
+ SAL_CALL getColumns(const Any& catalog, const OUString& schemaPattern,
+ const OUString& tableNamePattern,
+ const OUString& columnNamePattern) override;
+ css::uno::Reference<css::sdbc::XResultSet>
+ SAL_CALL getColumnPrivileges(const Any& catalog, const OUString& schema,
+ const OUString& table,
+ const OUString& columnNamePattern) override;
+ css::uno::Reference<css::sdbc::XResultSet>
+ SAL_CALL getTablePrivileges(const Any& catalog, const OUString& schemaPattern,
+ const OUString& tableNamePattern) override;
+ css::uno::Reference<css::sdbc::XResultSet>
+ SAL_CALL getBestRowIdentifier(const Any& catalog, const OUString& schema,
+ const OUString& table, sal_Int32 scope,
+ sal_Bool nullable) override;
+ css::uno::Reference<css::sdbc::XResultSet> SAL_CALL
+ getVersionColumns(const Any& catalog, const OUString& schema, const OUString& table) override;
+ css::uno::Reference<css::sdbc::XResultSet> SAL_CALL
+ getPrimaryKeys(const Any& catalog, const OUString& schema, const OUString& table) override;
+ css::uno::Reference<css::sdbc::XResultSet> SAL_CALL
+ getImportedKeys(const Any& catalog, const OUString& schema, const OUString& table) override;
+ css::uno::Reference<css::sdbc::XResultSet> SAL_CALL
+ getExportedKeys(const Any& catalog, const OUString& schema, const OUString& table) override;
+ css::uno::Reference<css::sdbc::XResultSet>
+ SAL_CALL getCrossReference(const Any& primaryCatalog, const OUString& primarySchema,
+ const OUString& primaryTable, const Any& foreignCatalog,
+ const OUString& foreignSchema,
+ const OUString& foreignTable) override;
+ css::uno::Reference<css::sdbc::XResultSet> SAL_CALL getTypeInfo() override;
+ css::uno::Reference<css::sdbc::XResultSet>
+ SAL_CALL getIndexInfo(const Any& catalog, const OUString& schema, const OUString& table,
+ sal_Bool unique, sal_Bool approximate) override;
+ sal_Bool SAL_CALL supportsResultSetType(sal_Int32 setType) override;
+ sal_Bool SAL_CALL supportsResultSetConcurrency(sal_Int32 setType,
+ sal_Int32 concurrency) override;
+ sal_Bool SAL_CALL ownUpdatesAreVisible(sal_Int32 setType) override;
+ sal_Bool SAL_CALL ownDeletesAreVisible(sal_Int32 setType) override;
+ sal_Bool SAL_CALL ownInsertsAreVisible(sal_Int32 setType) override;
+ sal_Bool SAL_CALL othersUpdatesAreVisible(sal_Int32 setType) override;
+ sal_Bool SAL_CALL othersDeletesAreVisible(sal_Int32 setType) override;
+ sal_Bool SAL_CALL othersInsertsAreVisible(sal_Int32 setType) override;
+ sal_Bool SAL_CALL updatesAreDetected(sal_Int32 setType) override;
+ sal_Bool SAL_CALL deletesAreDetected(sal_Int32 setType) override;
+ sal_Bool SAL_CALL insertsAreDetected(sal_Int32 setType) override;
+ sal_Bool SAL_CALL supportsBatchUpdates() override;
+ css::uno::Reference<css::sdbc::XResultSet>
+ SAL_CALL getUDTs(const Any& catalog, const OUString& schemaPattern,
+ const OUString& typeNamePattern,
+ const css::uno::Sequence<sal_Int32>& types) override;
+ css::uno::Reference<css::sdbc::XConnection> SAL_CALL getConnection() override;
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/mysqlc/mysqlc_driver.cxx b/connectivity/source/drivers/mysqlc/mysqlc_driver.cxx
new file mode 100644
index 0000000000..79a514a578
--- /dev/null
+++ b/connectivity/source/drivers/mysqlc/mysqlc_driver.cxx
@@ -0,0 +1,148 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#include "mysqlc_driver.hxx"
+#include "mysqlc_connection.hxx"
+#include <cppuhelper/supportsservice.hxx>
+#include <comphelper/servicehelper.hxx>
+
+using namespace css::uno;
+using namespace css::lang;
+using namespace css::beans;
+using namespace css::sdbc;
+using namespace css::sdbcx;
+using namespace connectivity::mysqlc;
+
+MysqlCDriver::MysqlCDriver(const Reference<XMultiServiceFactory>& _rxFactory)
+ : ODriver_BASE(m_aMutex)
+ , m_xFactory(_rxFactory)
+{
+}
+
+void MysqlCDriver::disposing()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+
+ // when driver will be destroyed so all our connections have to be destroyed as well
+ for (auto const& connection : m_xConnections)
+ {
+ Reference<XComponent> xComp(connection.get(), UNO_QUERY);
+ if (xComp.is())
+ {
+ xComp->dispose();
+ }
+ }
+ m_xConnections.clear();
+
+ ODriver_BASE::disposing();
+}
+
+// static ServiceInfo
+OUString MysqlCDriver::getImplementationName_Static()
+{
+ return "com.sun.star.comp.sdbc.mysqlc.MysqlCDriver";
+}
+
+Sequence<OUString> MysqlCDriver::getSupportedServiceNames_Static()
+{
+ return { "com.sun.star.sdbc.Driver", "com.sun.star.sdbcx.Driver" };
+}
+
+OUString SAL_CALL MysqlCDriver::getImplementationName() { return getImplementationName_Static(); }
+
+sal_Bool SAL_CALL MysqlCDriver::supportsService(const OUString& _rServiceName)
+{
+ return cppu::supportsService(this, _rServiceName);
+}
+
+Sequence<OUString> SAL_CALL MysqlCDriver::getSupportedServiceNames()
+{
+ return getSupportedServiceNames_Static();
+}
+
+Reference<XConnection> SAL_CALL MysqlCDriver::connect(const OUString& url,
+ const Sequence<PropertyValue>& info)
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+
+ if (!acceptsURL(url))
+ {
+ return nullptr;
+ }
+
+ // create a new connection with the given properties and append it to our vector
+ rtl::Reference<OConnection> pCon = new OConnection(*this);
+
+ pCon->construct(url, info);
+ m_xConnections.push_back(WeakReferenceHelper(*pCon));
+ return pCon;
+}
+
+sal_Bool SAL_CALL MysqlCDriver::acceptsURL(const OUString& url)
+{
+ return url.startsWith("sdbc:mysqlc:") || url.startsWith("sdbc:mysql:mysqlc:");
+}
+
+Sequence<DriverPropertyInfo> SAL_CALL
+MysqlCDriver::getPropertyInfo(const OUString& url, const Sequence<PropertyValue>& /* info */)
+{
+ if (acceptsURL(url))
+ {
+ return { { "Hostname", "Name of host", true, "localhost", {} },
+ { "Port", "Port", true, "3306", {} } };
+ }
+
+ return Sequence<DriverPropertyInfo>();
+}
+
+sal_Int32 SAL_CALL MysqlCDriver::getMajorVersion() { return MARIADBC_VERSION_MAJOR; }
+
+sal_Int32 SAL_CALL MysqlCDriver::getMinorVersion() { return MARIADBC_VERSION_MINOR; }
+
+Reference<XTablesSupplier>
+ SAL_CALL MysqlCDriver::getDataDefinitionByConnection(const Reference<XConnection>& rConnection)
+{
+ if (OConnection* pConnection = comphelper::getFromUnoTunnel<OConnection>(rConnection))
+ return pConnection->createCatalog();
+ return {};
+}
+
+Reference<XTablesSupplier> SAL_CALL
+MysqlCDriver::getDataDefinitionByURL(const OUString& rURL, const Sequence<PropertyValue>& rInfo)
+{
+ Reference<XConnection> xConnection = connect(rURL, rInfo);
+ return getDataDefinitionByConnection(xConnection);
+}
+
+namespace connectivity::mysqlc
+{
+Reference<XInterface> MysqlCDriver_CreateInstance(const Reference<XMultiServiceFactory>& _rxFactory)
+{
+ return (*(new MysqlCDriver(_rxFactory)));
+}
+
+void checkDisposed(bool _bThrow)
+{
+ if (_bThrow)
+ {
+ throw DisposedException();
+ }
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/connectivity/source/drivers/mysqlc/mysqlc_driver.hxx b/connectivity/source/drivers/mysqlc/mysqlc_driver.hxx
new file mode 100644
index 0000000000..a290408925
--- /dev/null
+++ b/connectivity/source/drivers/mysqlc/mysqlc_driver.hxx
@@ -0,0 +1,88 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include "mysqlc_connection.hxx"
+
+#include <com/sun/star/sdbc/XDriver.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/sdbcx/XDataDefinitionSupplier.hpp>
+#include <cppuhelper/compbase.hxx>
+
+namespace connectivity::mysqlc
+{
+using css::uno::Reference;
+using css::uno::Sequence;
+
+Reference<css::uno::XInterface>
+MysqlCDriver_CreateInstance(const Reference<css::lang::XMultiServiceFactory>& _rxFactory);
+
+typedef ::cppu::WeakComponentImplHelper<css::sdbc::XDriver, css::sdbcx::XDataDefinitionSupplier,
+ css::lang::XServiceInfo>
+ ODriver_BASE;
+
+typedef void* (*OMysqlCConnection_CreateInstanceFunction)(void* _pDriver);
+
+class MysqlCDriver : public ODriver_BASE
+{
+protected:
+ Reference<css::lang::XMultiServiceFactory> m_xFactory;
+ ::osl::Mutex m_aMutex; // mutex is need to control member access
+ OWeakRefArray m_xConnections; // vector containing a list
+ // of all the Connection objects
+ // for this Driver
+public:
+ explicit MysqlCDriver(const Reference<css::lang::XMultiServiceFactory>& _rxFactory);
+
+ // OComponentHelper
+ void SAL_CALL disposing() override;
+ // XInterface
+ static OUString getImplementationName_Static();
+ static Sequence<OUString> getSupportedServiceNames_Static();
+
+ // XServiceInfo
+ OUString SAL_CALL getImplementationName() override;
+ sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override;
+ Sequence<OUString> SAL_CALL getSupportedServiceNames() override;
+
+ // XDriver
+ Reference<css::sdbc::XConnection> SAL_CALL
+ connect(const OUString& url, const Sequence<css::beans::PropertyValue>& info) override;
+
+ sal_Bool SAL_CALL acceptsURL(const OUString& url) override;
+ Sequence<css::sdbc::DriverPropertyInfo> SAL_CALL
+ getPropertyInfo(const OUString& url, const Sequence<css::beans::PropertyValue>& info) override;
+
+ sal_Int32 SAL_CALL getMajorVersion() override;
+ sal_Int32 SAL_CALL getMinorVersion() override;
+
+ const Reference<css::lang::XMultiServiceFactory>& getFactory() const { return m_xFactory; }
+
+ static rtl_TextEncoding getDefaultEncoding() { return RTL_TEXTENCODING_UTF8; }
+
+ // XDataDefinitionSupplier
+ virtual css::uno::Reference<css::sdbcx::XTablesSupplier> SAL_CALL getDataDefinitionByConnection(
+ const css::uno::Reference<css::sdbc::XConnection>& rxConnection) override;
+ virtual css::uno::Reference<css::sdbcx::XTablesSupplier> SAL_CALL getDataDefinitionByURL(
+ const OUString& rsURL, const css::uno::Sequence<css::beans::PropertyValue>& rInfo) override;
+};
+
+} /* connectivity::mysqlc */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/connectivity/source/drivers/mysqlc/mysqlc_general.cxx b/connectivity/source/drivers/mysqlc/mysqlc_general.cxx
new file mode 100644
index 0000000000..bc57770413
--- /dev/null
+++ b/connectivity/source/drivers/mysqlc/mysqlc_general.cxx
@@ -0,0 +1,357 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#include "mysqlc_general.hxx"
+
+#include <sal/log.hxx>
+#include <rtl/ustring.hxx>
+#include <o3tl/string_view.hxx>
+
+#include <com/sun/star/sdbc/DataType.hpp>
+
+using com::sun::star::sdbc::SQLException;
+
+using com::sun::star::uno::Any;
+using com::sun::star::uno::Reference;
+using com::sun::star::uno::XInterface;
+
+using namespace rtl;
+
+namespace mysqlc_sdbc_driver
+{
+void allocateSqlVar(void** mem, enum_field_types eType, unsigned nSize)
+{
+ assert(mem);
+ switch (eType)
+ {
+ case MYSQL_TYPE_LONG:
+ case MYSQL_TYPE_INT24:
+ *mem = malloc(sizeof(sal_Int32));
+ break;
+ case MYSQL_TYPE_SHORT:
+ case MYSQL_TYPE_YEAR:
+ *mem = malloc(sizeof(sal_Int16));
+ break;
+ case MYSQL_TYPE_BIT:
+ case MYSQL_TYPE_TINY:
+ *mem = malloc(sizeof(sal_Int8));
+ break;
+ case MYSQL_TYPE_LONGLONG:
+ *mem = malloc(sizeof(sal_Int64));
+ break;
+ case MYSQL_TYPE_FLOAT:
+ *mem = malloc(sizeof(float));
+ break;
+ case MYSQL_TYPE_DOUBLE:
+ *mem = malloc(sizeof(double));
+ break;
+ case MYSQL_TYPE_DATE:
+ case MYSQL_TYPE_TIME:
+ case MYSQL_TYPE_DATETIME:
+ case MYSQL_TYPE_TIMESTAMP:
+ case MYSQL_TYPE_NEWDATE:
+ case MYSQL_TYPE_ENUM:
+ case MYSQL_TYPE_SET:
+ case MYSQL_TYPE_GEOMETRY:
+ *mem = malloc(sizeof(MYSQL_TIME));
+ break;
+ case MYSQL_TYPE_STRING:
+ case MYSQL_TYPE_VAR_STRING:
+ case MYSQL_TYPE_VARCHAR:
+ case MYSQL_TYPE_DECIMAL:
+ case MYSQL_TYPE_NEWDECIMAL:
+ *mem = malloc(sizeof(char) * nSize);
+ break;
+ case MYSQL_TYPE_NULL:
+ case MYSQL_TYPE_BLOB:
+ case MYSQL_TYPE_TINY_BLOB:
+ case MYSQL_TYPE_MEDIUM_BLOB:
+ case MYSQL_TYPE_LONG_BLOB:
+ *mem = nullptr;
+ break;
+ default:
+ SAL_WARN("connectivity.mysqlc", "unknown enum_field_type");
+ }
+}
+
+void throwFeatureNotImplementedException(const char* _pAsciiFeatureName,
+ const css::uno::Reference<XInterface>& _rxContext)
+{
+ const OUString sMessage
+ = OUString::createFromAscii(_pAsciiFeatureName) + ": feature not implemented.";
+ throw SQLException(sMessage, _rxContext, "HYC00", 0, Any());
+}
+
+void throwInvalidArgumentException(const char* _pAsciiFeatureName,
+ const css::uno::Reference<XInterface>& _rxContext)
+{
+ const OUString sMessage
+ = OUString::createFromAscii(_pAsciiFeatureName) + ": invalid arguments.";
+ throw SQLException(sMessage, _rxContext, "HYC00", 0, Any());
+}
+
+void throwSQLExceptionWithMsg(const char* msg, const char* SQLSTATE, unsigned int errorNum,
+ const css::uno::Reference<css::uno::XInterface>& _context,
+ const rtl_TextEncoding encoding)
+{
+ OString errorMsg{ msg };
+ throwSQLExceptionWithMsg(OStringToOUString(errorMsg, encoding), SQLSTATE, errorNum, _context);
+}
+
+void throwSQLExceptionWithMsg(const OUString& msg, const char* SQLSTATE, unsigned int errorNum,
+ const css::uno::Reference<css::uno::XInterface>& _context)
+{
+ throw SQLException(msg, _context, OStringToOUString(SQLSTATE, RTL_TEXTENCODING_ASCII_US),
+ errorNum, Any());
+}
+
+sal_Int32 mysqlToOOOType(int eType, int charsetnr) noexcept
+{
+ // charset number 63 indicates binary
+ switch (eType)
+ {
+ case MYSQL_TYPE_BIT:
+ return css::sdbc::DataType::BIT;
+
+ case MYSQL_TYPE_TINY:
+ return css::sdbc::DataType::TINYINT;
+
+ case MYSQL_TYPE_SHORT:
+ case MYSQL_TYPE_YEAR:
+ return css::sdbc::DataType::SMALLINT;
+
+ case MYSQL_TYPE_INT24:
+ case MYSQL_TYPE_LONG:
+ return css::sdbc::DataType::INTEGER;
+
+ case MYSQL_TYPE_LONGLONG:
+ return css::sdbc::DataType::BIGINT;
+
+ case MYSQL_TYPE_FLOAT:
+ return css::sdbc::DataType::REAL;
+
+ case MYSQL_TYPE_DOUBLE:
+ return css::sdbc::DataType::DOUBLE;
+
+ case MYSQL_TYPE_DECIMAL:
+ case MYSQL_TYPE_NEWDECIMAL:
+ return css::sdbc::DataType::DECIMAL;
+
+ case MYSQL_TYPE_STRING:
+ if (charsetnr == 63)
+ return css::sdbc::DataType::BINARY;
+ return css::sdbc::DataType::CHAR;
+
+ case MYSQL_TYPE_ENUM:
+ case MYSQL_TYPE_SET:
+ case MYSQL_TYPE_VAR_STRING:
+ if (charsetnr == 63)
+ return css::sdbc::DataType::VARBINARY;
+ return css::sdbc::DataType::VARCHAR;
+
+ case MYSQL_TYPE_BLOB:
+ case MYSQL_TYPE_TINY_BLOB:
+ case MYSQL_TYPE_MEDIUM_BLOB:
+ case MYSQL_TYPE_LONG_BLOB:
+ if (charsetnr == 63)
+ return css::sdbc::DataType::LONGVARBINARY;
+ return css::sdbc::DataType::LONGVARCHAR;
+
+ case MYSQL_TYPE_TIMESTAMP:
+ case MYSQL_TYPE_DATETIME:
+ return css::sdbc::DataType::TIMESTAMP;
+
+ case MYSQL_TYPE_DATE:
+ return css::sdbc::DataType::DATE;
+
+ case MYSQL_TYPE_TIME:
+ return css::sdbc::DataType::TIME;
+
+ case MYSQL_TYPE_GEOMETRY:
+ return css::sdbc::DataType::VARCHAR;
+
+ case MYSQL_TYPE_NULL:
+ return css::sdbc::DataType::SQLNULL;
+ }
+
+ OSL_FAIL("mysqlToOOOType: unhandled case, falling back to VARCHAR");
+ return css::sdbc::DataType::VARCHAR;
+}
+
+sal_Int32 mysqlStrToOOOType(std::u16string_view sType)
+{
+ // TODO other types.
+ if (o3tl::equalsIgnoreAsciiCase(sType, u"tiny")
+ || o3tl::equalsIgnoreAsciiCase(sType, u"tinyint"))
+ return css::sdbc::DataType::TINYINT;
+ if (o3tl::equalsIgnoreAsciiCase(sType, u"smallint")
+ || o3tl::equalsIgnoreAsciiCase(sType, u"year"))
+ return css::sdbc::DataType::SMALLINT;
+ if (o3tl::equalsIgnoreAsciiCase(sType, u"int")
+ || o3tl::equalsIgnoreAsciiCase(sType, u"mediumint"))
+ return css::sdbc::DataType::INTEGER;
+ if (o3tl::equalsIgnoreAsciiCase(sType, u"varchar") || o3tl::equalsIgnoreAsciiCase(sType, u"set")
+ || o3tl::equalsIgnoreAsciiCase(sType, u"enum"))
+ return css::sdbc::DataType::VARCHAR;
+ if (o3tl::equalsIgnoreAsciiCase(sType, u"bigint"))
+ return css::sdbc::DataType::BIGINT;
+ if (o3tl::equalsIgnoreAsciiCase(sType, u"blob")
+ || o3tl::equalsIgnoreAsciiCase(sType, u"longblob")
+ || o3tl::equalsIgnoreAsciiCase(sType, u"tinyblob")
+ || o3tl::equalsIgnoreAsciiCase(sType, u"mediumblob"))
+ return css::sdbc::DataType::BLOB;
+ if (o3tl::equalsIgnoreAsciiCase(sType, u"varbinary"))
+ return css::sdbc::DataType::VARBINARY;
+ if (o3tl::equalsIgnoreAsciiCase(sType, u"char"))
+ return css::sdbc::DataType::CHAR;
+ if (o3tl::equalsIgnoreAsciiCase(sType, u"tinytext"))
+ return css::sdbc::DataType::VARCHAR;
+ if (o3tl::equalsIgnoreAsciiCase(sType, u"text"))
+ return css::sdbc::DataType::LONGVARCHAR;
+ if (o3tl::equalsIgnoreAsciiCase(sType, u"mediumtext")
+ || o3tl::equalsIgnoreAsciiCase(sType, u"longtext"))
+ return css::sdbc::DataType::CLOB;
+ if (o3tl::equalsIgnoreAsciiCase(sType, u"binary"))
+ return css::sdbc::DataType::BINARY;
+ if (o3tl::equalsIgnoreAsciiCase(sType, u"time"))
+ return css::sdbc::DataType::TIME;
+ if (o3tl::equalsIgnoreAsciiCase(sType, u"date"))
+ return css::sdbc::DataType::DATE;
+ if (o3tl::equalsIgnoreAsciiCase(sType, u"datetime")
+ || o3tl::equalsIgnoreAsciiCase(sType, u"timestamp"))
+ return css::sdbc::DataType::TIMESTAMP;
+ if (o3tl::equalsIgnoreAsciiCase(sType, u"decimal"))
+ return css::sdbc::DataType::DECIMAL;
+ if (o3tl::equalsIgnoreAsciiCase(sType, u"real") || o3tl::equalsIgnoreAsciiCase(sType, u"float"))
+ return css::sdbc::DataType::REAL;
+ if (o3tl::equalsIgnoreAsciiCase(sType, u"double"))
+ return css::sdbc::DataType::DOUBLE;
+ if (o3tl::equalsIgnoreAsciiCase(sType, u"bit"))
+ return css::sdbc::DataType::BIT;
+ if (o3tl::equalsIgnoreAsciiCase(sType, u"bool")
+ || o3tl::equalsIgnoreAsciiCase(sType, u"boolean"))
+ return css::sdbc::DataType::BOOLEAN;
+ OSL_FAIL("Unknown type name from string, failing back to varchar.");
+ return css::sdbc::DataType::VARCHAR;
+}
+
+OUString mysqlTypeToStr(unsigned type, unsigned flags)
+{
+ bool isUnsigned = (flags & UNSIGNED_FLAG) != 0;
+ bool isZerofill = (flags & ZEROFILL_FLAG) != 0;
+ switch (type)
+ {
+ case MYSQL_TYPE_BIT:
+ return OUString{ "BIT" };
+ case MYSQL_TYPE_DECIMAL:
+ case MYSQL_TYPE_NEWDECIMAL:
+ return isUnsigned ? (isZerofill ? OUString{ "DECIMAL UNSIGNED ZEROFILL" }
+ : OUString{ "DECIMAL UNSIGNED" })
+ : OUString{ "DECIMAL" };
+ case MYSQL_TYPE_TINY:
+ return isUnsigned ? (isZerofill ? OUString{ "TINYINT UNSIGNED ZEROFILL" }
+ : OUString{ "TINYINT UNSIGNED" })
+ : OUString{ "TINYINT" };
+ case MYSQL_TYPE_SHORT:
+ return isUnsigned ? (isZerofill ? OUString{ "SMALLINT UNSIGNED ZEROFILL" }
+ : OUString{ "SMALLINT UNSIGNED" })
+ : OUString{ "SMALLINT" };
+ case MYSQL_TYPE_LONG:
+ return isUnsigned ? (isZerofill ? OUString{ "INT UNSIGNED ZEROFILL" }
+ : OUString{ "INT UNSIGNED" })
+ : OUString{ "INT" };
+ case MYSQL_TYPE_FLOAT:
+ return isUnsigned ? (isZerofill ? OUString{ "FLOAT UNSIGNED ZEROFILL" }
+ : OUString{ "FLOAT UNSIGNED" })
+ : OUString{ "FLOAT" };
+ case MYSQL_TYPE_DOUBLE:
+ return isUnsigned ? (isZerofill ? OUString{ "DOUBLE UNSIGNED ZEROFILL" }
+ : OUString{ "DOUBLE UNSIGNED" })
+ : OUString{ "DOUBLE" };
+ case MYSQL_TYPE_NULL:
+ return OUString{ "NULL" };
+ case MYSQL_TYPE_TIMESTAMP:
+ return OUString{ "TIMESTAMP" };
+ case MYSQL_TYPE_LONGLONG:
+ return isUnsigned ? (isZerofill ? OUString{ "BIGINT UNSIGNED ZEROFILL" }
+ : OUString{ "BIGINT UNSIGNED" })
+ : OUString{ "BIGINT" };
+ case MYSQL_TYPE_INT24:
+ return isUnsigned ? (isZerofill ? OUString{ "MEDIUMINT UNSIGNED ZEROFILL" }
+ : OUString{ "MEDIUMINT UNSIGNED" })
+ : OUString{ "MEDIUMINT" };
+ case MYSQL_TYPE_DATE:
+ return OUString{ "DATE" };
+ case MYSQL_TYPE_TIME:
+ return OUString{ "TIME" };
+ case MYSQL_TYPE_DATETIME:
+ return OUString{ "DATETIME" };
+ case MYSQL_TYPE_TINY_BLOB:
+ {
+ return OUString{ "TINYBLOB" };
+ }
+ case MYSQL_TYPE_MEDIUM_BLOB:
+ {
+ return OUString{ "MEDIUMBLOB" };
+ }
+ case MYSQL_TYPE_LONG_BLOB:
+ {
+ return OUString{ "LONGBLOB" };
+ }
+ case MYSQL_TYPE_BLOB:
+ {
+ return OUString{ "BLOB" };
+ }
+ case MYSQL_TYPE_VARCHAR:
+ case MYSQL_TYPE_VAR_STRING:
+ if (flags & ENUM_FLAG)
+ {
+ return OUString{ "ENUM" };
+ }
+ if (flags & SET_FLAG)
+ {
+ return OUString{ "SET" };
+ }
+ return OUString{ "VARCHAR" };
+ case MYSQL_TYPE_STRING:
+ if (flags & ENUM_FLAG)
+ {
+ return OUString{ "ENUM" };
+ }
+ if (flags & SET_FLAG)
+ {
+ return OUString{ "SET" };
+ }
+ return OUString{ "CHAR" };
+ case MYSQL_TYPE_YEAR:
+ return OUString{ "YEAR" };
+ case MYSQL_TYPE_GEOMETRY:
+ return OUString{ "GEOMETRY" };
+ default:
+ return OUString{ "UNKNOWN" };
+ }
+}
+
+OUString convert(const ::std::string& _string, const rtl_TextEncoding encoding)
+{
+ return OUString(_string.c_str(), _string.size(), encoding);
+}
+
+} /* namespace */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/mysqlc/mysqlc_general.hxx b/connectivity/source/drivers/mysqlc/mysqlc_general.hxx
new file mode 100644
index 0000000000..16236e1530
--- /dev/null
+++ b/connectivity/source/drivers/mysqlc/mysqlc_general.hxx
@@ -0,0 +1,116 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <config_lgpl.h>
+
+#include <com/sun/star/uno/XInterface.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
+
+#include <osl/diagnose.h>
+#include <mysql.h>
+
+#if defined __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wdeprecated"
+#endif
+
+#if defined __GNUC__
+#pragma GCC diagnostic pop
+#endif
+
+namespace mysqlc_sdbc_driver
+{
+template <typename T>
+void resetSqlVar(void** target, T* pValue, enum_field_types type, sal_Int32 nSize = 0)
+{
+ if (*target)
+ {
+ free(*target);
+ *target = nullptr;
+ }
+ constexpr auto nUnitSize = sizeof(T);
+ switch (type)
+ {
+ case MYSQL_TYPE_INT24:
+ case MYSQL_TYPE_YEAR:
+ case MYSQL_TYPE_NEWDATE:
+ case MYSQL_TYPE_BIT:
+ case MYSQL_TYPE_GEOMETRY:
+ case MYSQL_TYPE_LONG:
+ case MYSQL_TYPE_SHORT:
+ case MYSQL_TYPE_TINY:
+ case MYSQL_TYPE_LONGLONG:
+ case MYSQL_TYPE_FLOAT:
+ case MYSQL_TYPE_DOUBLE:
+ case MYSQL_TYPE_TIME:
+ case MYSQL_TYPE_DATE:
+ case MYSQL_TYPE_DATETIME:
+ case MYSQL_TYPE_TIMESTAMP:
+ *target = malloc(nUnitSize);
+ memcpy(*target, pValue, nUnitSize);
+ break;
+ case MYSQL_TYPE_STRING:
+ case MYSQL_TYPE_BLOB:
+ case MYSQL_TYPE_DECIMAL:
+ case MYSQL_TYPE_VARCHAR:
+ case MYSQL_TYPE_NEWDECIMAL:
+ case MYSQL_TYPE_ENUM:
+ case MYSQL_TYPE_SET:
+ case MYSQL_TYPE_VAR_STRING:
+ case MYSQL_TYPE_TINY_BLOB:
+ case MYSQL_TYPE_MEDIUM_BLOB:
+ case MYSQL_TYPE_LONG_BLOB:
+ *target = malloc(nUnitSize * nSize);
+ memcpy(*target, pValue, nUnitSize * nSize);
+ break;
+ case MYSQL_TYPE_NULL:
+ // nothing I guess
+ break;
+ default:
+ OSL_FAIL("resetSqlVar: unknown enum_field_type");
+ }
+}
+
+void allocateSqlVar(void** mem, enum_field_types eType, unsigned nSize = 0);
+
+void throwFeatureNotImplementedException(
+ const char* _pAsciiFeatureName, const css::uno::Reference<css::uno::XInterface>& _rxContext);
+
+void throwInvalidArgumentException(const char* _pAsciiFeatureName,
+ const css::uno::Reference<css::uno::XInterface>& _rxContext);
+
+void throwSQLExceptionWithMsg(const char* msg, const char* SQLSTATE, unsigned int errorNum,
+ const css::uno::Reference<css::uno::XInterface>& _context,
+ const rtl_TextEncoding encoding);
+
+void throwSQLExceptionWithMsg(const OUString& msg, const char* SQLSTATE, unsigned int errorNum,
+ const css::uno::Reference<css::uno::XInterface>& _context);
+
+sal_Int32 mysqlToOOOType(int eType, int charsetnr) noexcept;
+
+OUString mysqlTypeToStr(unsigned mysql_type, unsigned mysql_flags);
+
+sal_Int32 mysqlStrToOOOType(std::u16string_view sType);
+
+OUString convert(const ::std::string& _string, const rtl_TextEncoding encoding);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/mysqlc/mysqlc_indexes.cxx b/connectivity/source/drivers/mysqlc/mysqlc_indexes.cxx
new file mode 100644
index 0000000000..c496f9c21c
--- /dev/null
+++ b/connectivity/source/drivers/mysqlc/mysqlc_indexes.cxx
@@ -0,0 +1,25 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "mysqlc_indexes.hxx"
+
+connectivity::mysqlc::Indexes::Indexes(Table* pTable, osl::Mutex& rMutex,
+ const std::vector<OUString>& rVector)
+ : OIndexesHelper(pTable, rMutex, rVector)
+{
+}
+
+// XDrop
+void connectivity::mysqlc::Indexes::dropObject(sal_Int32 /*nPosition*/,
+ const OUString& /* sIndexName */)
+{
+ // TODO: implement
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/connectivity/source/drivers/mysqlc/mysqlc_indexes.hxx b/connectivity/source/drivers/mysqlc/mysqlc_indexes.hxx
new file mode 100644
index 0000000000..4c918d1846
--- /dev/null
+++ b/connectivity/source/drivers/mysqlc/mysqlc_indexes.hxx
@@ -0,0 +1,34 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include "mysqlc_table.hxx"
+
+#include <connectivity/TIndexes.hxx>
+
+namespace connectivity::mysqlc
+{
+class Indexes : public ::connectivity::OIndexesHelper
+{
+private:
+ // TODO: useful?
+ // Table* m_pTable;
+
+protected:
+ // XDrop
+ void dropObject(sal_Int32 nPosition, const OUString& sIndexName);
+
+public:
+ Indexes(Table* pTable, ::osl::Mutex& rMutex, const std::vector<OUString>& rVector);
+};
+
+} // namespace connectivity::mysqlc
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/connectivity/source/drivers/mysqlc/mysqlc_keys.cxx b/connectivity/source/drivers/mysqlc/mysqlc_keys.cxx
new file mode 100644
index 0000000000..7706844f23
--- /dev/null
+++ b/connectivity/source/drivers/mysqlc/mysqlc_keys.cxx
@@ -0,0 +1,19 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "mysqlc_keys.hxx"
+#include "mysqlc_table.hxx"
+
+connectivity::mysqlc::Keys::Keys(Table* pTable, osl::Mutex& rMutex,
+ const ::std::vector<OUString>& rNames)
+ : OKeysHelper(pTable, rMutex, rNames)
+{
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/connectivity/source/drivers/mysqlc/mysqlc_keys.hxx b/connectivity/source/drivers/mysqlc/mysqlc_keys.hxx
new file mode 100644
index 0000000000..9d0a9ef1cc
--- /dev/null
+++ b/connectivity/source/drivers/mysqlc/mysqlc_keys.hxx
@@ -0,0 +1,25 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include <connectivity/TKeys.hxx>
+
+namespace connectivity::mysqlc
+{
+class Table;
+
+class Keys : public ::connectivity::OKeysHelper
+{
+public:
+ Keys(Table* pTable, ::osl::Mutex& rMutex, const ::std::vector<OUString>& rNames);
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/connectivity/source/drivers/mysqlc/mysqlc_prepared_resultset.cxx b/connectivity/source/drivers/mysqlc/mysqlc_prepared_resultset.cxx
new file mode 100644
index 0000000000..32d4915377
--- /dev/null
+++ b/connectivity/source/drivers/mysqlc/mysqlc_prepared_resultset.cxx
@@ -0,0 +1,1127 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "mysqlc_propertyids.hxx"
+#include "mysqlc_general.hxx"
+#include "mysqlc_prepared_resultset.hxx"
+#include "mysqlc_resultsetmetadata.hxx"
+
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/sdbc/ResultSetConcurrency.hpp>
+#include <com/sun/star/sdbc/ResultSetType.hpp>
+#include <com/sun/star/sdbc/FetchDirection.hpp>
+#include <com/sun/star/sdbcx/CompareBookmark.hpp>
+#include <cppuhelper/supportsservice.hxx>
+#include <cppuhelper/typeprovider.hxx>
+#include <sal/log.hxx>
+
+#include <cstdlib>
+#include <typeindex>
+
+using namespace rtl;
+using namespace connectivity::mysqlc;
+using namespace connectivity;
+using namespace cppu;
+using namespace com::sun::star;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::sdbc;
+using namespace com::sun::star::sdbcx;
+using namespace com::sun::star::container;
+using namespace com::sun::star::io;
+using namespace com::sun::star::util;
+using namespace ::comphelper;
+using ::osl::MutexGuard;
+
+namespace
+{
+std::type_index getTypeFromMysqlType(enum_field_types type)
+{
+ switch (type)
+ {
+ case MYSQL_TYPE_BIT:
+ return std::type_index(typeid(bool));
+ case MYSQL_TYPE_TINY:
+ return std::type_index(typeid(sal_Int8));
+ case MYSQL_TYPE_SHORT:
+ case MYSQL_TYPE_YEAR:
+ return std::type_index(typeid(sal_Int16));
+ case MYSQL_TYPE_LONG:
+ case MYSQL_TYPE_INT24:
+ return std::type_index(typeid(sal_Int32));
+ case MYSQL_TYPE_LONGLONG:
+ return std::type_index(typeid(sal_Int64));
+ case MYSQL_TYPE_FLOAT:
+ return std::type_index(typeid(float));
+ case MYSQL_TYPE_DOUBLE:
+ return std::type_index(typeid(double));
+ case MYSQL_TYPE_TIMESTAMP:
+ case MYSQL_TYPE_DATETIME:
+ return std::type_index(typeid(DateTime));
+ case MYSQL_TYPE_DATE:
+ return std::type_index(typeid(Date));
+ case MYSQL_TYPE_TIME:
+ return std::type_index(typeid(Time));
+ case MYSQL_TYPE_STRING:
+ case MYSQL_TYPE_VAR_STRING:
+ case MYSQL_TYPE_DECIMAL:
+ case MYSQL_TYPE_NEWDECIMAL:
+ return std::type_index(typeid(OUString));
+ case MYSQL_TYPE_BLOB:
+ case MYSQL_TYPE_SET:
+ case MYSQL_TYPE_ENUM:
+ case MYSQL_TYPE_GEOMETRY:
+ case MYSQL_TYPE_NULL:
+ default:
+ return std::type_index(typeid(nullptr));
+ }
+}
+}
+
+bool OPreparedResultSet::fetchResult()
+{
+ // allocate array if it does not exist
+ if (m_aData == nullptr)
+ {
+ m_aData.reset(new MYSQL_BIND[m_nColumnCount]);
+ memset(m_aData.get(), 0, m_nColumnCount * sizeof(MYSQL_BIND));
+ m_aMetaData.reset(new BindMetaData[m_nColumnCount]);
+ }
+ for (sal_Int32 i = 0; i < m_nColumnCount; ++i)
+ {
+ bool bIsBlobType = false;
+ switch (m_aFields[i].type)
+ {
+ case MYSQL_TYPE_BLOB:
+ case MYSQL_TYPE_TINY_BLOB:
+ case MYSQL_TYPE_MEDIUM_BLOB:
+ case MYSQL_TYPE_LONG_BLOB:
+ bIsBlobType = true;
+ break;
+ default:
+ bIsBlobType = false;
+ }
+ m_aMetaData[i].is_null = false;
+ m_aMetaData[i].length = 0l;
+ m_aMetaData[i].error = false;
+
+ m_aData[i].is_null = &m_aMetaData[i].is_null;
+ m_aData[i].buffer_length = bIsBlobType ? 0 : m_aFields[i].length;
+ m_aData[i].length = &m_aMetaData[i].length;
+ m_aData[i].error = &m_aMetaData[i].error;
+ m_aData[i].buffer = nullptr;
+ m_aData[i].buffer_type = m_aFields[i].type;
+
+ // allocates memory, if it is a fixed size type. If not then nullptr
+ mysqlc_sdbc_driver::allocateSqlVar(&m_aData[i].buffer, m_aData[i].buffer_type,
+ m_aFields[i].length);
+ }
+ mysql_stmt_bind_result(m_pStmt, m_aData.get());
+ int failure = mysql_stmt_fetch(m_pStmt);
+
+ for (sal_Int32 i = 0; i < m_nColumnCount; ++i)
+ {
+ if (*m_aData[i].error)
+ {
+ // expected if we have a BLOB, as buffer_length is set to 0. We want to
+ // fetch it piece by piece
+ // see https://bugs.mysql.com/file.php?id=12361&bug_id=33086
+ if (m_aData[i].buffer == nullptr)
+ {
+ m_aData[i].buffer_length = *m_aData[i].length;
+ m_aData[i].buffer = malloc(*m_aData[i].length);
+ mysql_stmt_fetch_column(m_pStmt, &m_aData[i], i, 0);
+ }
+ }
+ }
+
+ if (failure == 1)
+ {
+ MYSQL* pMysql = m_rConnection.getMysqlConnection();
+ mysqlc_sdbc_driver::throwSQLExceptionWithMsg(mysql_error(pMysql), mysql_sqlstate(pMysql),
+ mysql_errno(pMysql), *this, m_encoding);
+ }
+ else if (failure == MYSQL_NO_DATA)
+ return false;
+ return true;
+}
+
+OUString SAL_CALL OPreparedResultSet::getImplementationName()
+{
+ return "com.sun.star.sdbcx.mysqlc.ResultSet";
+}
+
+uno::Sequence<OUString> SAL_CALL OPreparedResultSet::getSupportedServiceNames()
+{
+ return { "com.sun.star.sdbc.ResultSet", "com.sun.star.sdbcx.ResultSet" };
+}
+
+sal_Bool SAL_CALL OPreparedResultSet::supportsService(const OUString& _rServiceName)
+{
+ return cppu::supportsService(this, _rServiceName);
+}
+OPreparedResultSet::OPreparedResultSet(OConnection& rConn, OPreparedStatement* pStmt,
+ MYSQL_STMT* pMyStmt)
+ : OPreparedResultSet_BASE(m_aMutex)
+ , OPropertySetHelper(OPreparedResultSet_BASE::rBHelper)
+ , m_rConnection(rConn)
+ , m_aStatement(css::uno::Reference(cppu::getXWeak(pStmt)))
+ , m_pStmt(pMyStmt)
+ , m_encoding(rConn.getConnectionEncoding())
+ , m_nColumnCount(mysql_stmt_field_count(pMyStmt))
+{
+ m_pResult = mysql_stmt_result_metadata(m_pStmt);
+ if (m_pResult != nullptr)
+ mysql_stmt_store_result(m_pStmt);
+ m_aFields = mysql_fetch_fields(m_pResult);
+ m_nRowCount = mysql_stmt_num_rows(pMyStmt);
+}
+
+void OPreparedResultSet::disposing()
+{
+ OPropertySetHelper::disposing();
+
+ MutexGuard aGuard(m_aMutex);
+
+ m_aStatement.clear();
+ m_xMetaData = nullptr;
+}
+
+Any SAL_CALL OPreparedResultSet::queryInterface(const Type& rType)
+{
+ Any aRet = OPropertySetHelper::queryInterface(rType);
+ if (!aRet.hasValue())
+ {
+ aRet = OPreparedResultSet_BASE::queryInterface(rType);
+ }
+ return aRet;
+}
+
+uno::Sequence<Type> SAL_CALL OPreparedResultSet::getTypes()
+{
+ OTypeCollection aTypes(cppu::UnoType<XMultiPropertySet>::get(),
+ cppu::UnoType<XFastPropertySet>::get(),
+ cppu::UnoType<XPropertySet>::get());
+
+ return concatSequences(aTypes.getTypes(), OPreparedResultSet_BASE::getTypes());
+}
+
+sal_Int32 SAL_CALL OPreparedResultSet::findColumn(const OUString& columnName)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed);
+
+ MYSQL_FIELD* pFields = mysql_fetch_fields(m_pResult);
+ for (sal_Int32 i = 0; i < m_nColumnCount; ++i)
+ {
+ if (columnName.equalsIgnoreAsciiCaseAscii(pFields[i].name))
+ return i + 1; // sdbc indexes from 1
+ }
+
+ throw SQLException("The column name '" + columnName + "' is not valid.", *this, "42S22", 0,
+ Any());
+}
+
+template <typename T> T OPreparedResultSet::safelyRetrieveValue(sal_Int32 nColumnIndex)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed);
+ checkColumnIndex(nColumnIndex);
+ if (*m_aData[nColumnIndex - 1].is_null)
+ {
+ m_bWasNull = true;
+ return T();
+ }
+ m_bWasNull = false;
+
+ return retrieveValue<T>(nColumnIndex);
+}
+
+template <typename T> T OPreparedResultSet::retrieveValue(sal_Int32 nColumnIndex)
+{
+ if (getTypeFromMysqlType(m_aFields[nColumnIndex - 1].type) == std::type_index(typeid(T)))
+ return *static_cast<T*>(m_aData[nColumnIndex - 1].buffer);
+ else
+ {
+ auto const& row = getRowSetValue(nColumnIndex);
+ if constexpr (std::is_same_v<sal_Int64, T>)
+ return row.getLong();
+ else if constexpr (std::is_same_v<sal_Int32, T>)
+ return row.getInt32();
+ else if constexpr (std::is_same_v<sal_Int16, T>)
+ return row.getInt16();
+ else if constexpr (std::is_same_v<sal_Int8, T>)
+ return row.getInt8();
+ else if constexpr (std::is_same_v<double, T>)
+ return row.getDouble();
+ else if constexpr (std::is_same_v<float, T>)
+ return row.getFloat();
+ else if constexpr (std::is_same_v<bool, T>)
+ return row.getBool();
+ else
+ return row;
+ }
+}
+
+template <> uno::Sequence<sal_Int8> OPreparedResultSet::retrieveValue(sal_Int32 column)
+{
+ // TODO make conversion possible
+ return uno::Sequence<sal_Int8>(static_cast<sal_Int8 const*>(m_aData[column - 1].buffer),
+ *m_aData[column - 1].length);
+}
+
+template <> Date OPreparedResultSet::retrieveValue(sal_Int32 column)
+{
+ if (getTypeFromMysqlType(m_aFields[column - 1].type) != std::type_index(typeid(Date)))
+ return getRowSetValue(column).getDate();
+ const MYSQL_TIME* pTime = static_cast<MYSQL_TIME*>(m_aData[column - 1].buffer);
+
+ Date d;
+ d.Year = pTime->year;
+ d.Month = pTime->month;
+ d.Day = pTime->day;
+ return d;
+}
+
+template <> Time OPreparedResultSet::retrieveValue(sal_Int32 column)
+{
+ if (getTypeFromMysqlType(m_aFields[column - 1].type) != std::type_index(typeid(Time)))
+ return getRowSetValue(column).getTime();
+ const MYSQL_TIME* pTime = static_cast<MYSQL_TIME*>(m_aData[column - 1].buffer);
+
+ Time t;
+ t.Hours = pTime->hour;
+ t.Minutes = pTime->minute;
+ t.Seconds = pTime->second;
+ return t;
+}
+
+template <> DateTime OPreparedResultSet::retrieveValue(sal_Int32 column)
+{
+ if (getTypeFromMysqlType(m_aFields[column - 1].type) != std::type_index(typeid(DateTime)))
+ return getRowSetValue(column).getDateTime();
+ const MYSQL_TIME* pTime = static_cast<MYSQL_TIME*>(m_aData[column - 1].buffer);
+
+ DateTime t;
+ t.Year = pTime->year;
+ t.Month = pTime->month;
+ t.Day = pTime->day;
+ t.Hours = pTime->hour;
+ t.Minutes = pTime->minute;
+ t.Seconds = pTime->second;
+ return t;
+}
+
+template <> OUString OPreparedResultSet::retrieveValue(sal_Int32 column)
+{
+ // redirect call to the appropriate method if needed
+ // BLOB can be simply read out as string
+ bool bIsBlobType = false;
+ switch (m_aFields[column - 1].type)
+ {
+ case MYSQL_TYPE_BLOB:
+ case MYSQL_TYPE_TINY_BLOB:
+ case MYSQL_TYPE_MEDIUM_BLOB:
+ case MYSQL_TYPE_LONG_BLOB:
+ bIsBlobType = true;
+ break;
+ default:
+ bIsBlobType = false;
+ }
+
+ if (getTypeFromMysqlType(m_aFields[column - 1].type) != std::type_index(typeid(OUString))
+ && !bIsBlobType)
+ return getRowSetValue(column).getString();
+ const char* sStr = static_cast<const char*>(m_aData[column - 1].buffer);
+
+ return OUString(sStr, *m_aData[column - 1].length, m_encoding);
+}
+
+ORowSetValue OPreparedResultSet::getRowSetValue(sal_Int32 nColumnIndex)
+{
+ switch (m_aFields[nColumnIndex - 1].type)
+ {
+ case MYSQL_TYPE_TINY:
+ return getByte(nColumnIndex);
+ case MYSQL_TYPE_SHORT:
+ case MYSQL_TYPE_YEAR:
+ return getShort(nColumnIndex);
+ case MYSQL_TYPE_LONG:
+ case MYSQL_TYPE_INT24:
+ return getInt(nColumnIndex);
+ case MYSQL_TYPE_BIT:
+ return ORowSetValue(bool(getBoolean(nColumnIndex)));
+ case MYSQL_TYPE_LONGLONG:
+ return getLong(nColumnIndex);
+ case MYSQL_TYPE_FLOAT:
+ return getFloat(nColumnIndex);
+ case MYSQL_TYPE_DOUBLE:
+ return getDouble(nColumnIndex);
+ case MYSQL_TYPE_TIMESTAMP:
+ case MYSQL_TYPE_DATETIME:
+ return getTimestamp(nColumnIndex);
+ case MYSQL_TYPE_DATE:
+ return getDate(nColumnIndex);
+ case MYSQL_TYPE_TIME:
+ return getTime(nColumnIndex);
+ case MYSQL_TYPE_STRING:
+ case MYSQL_TYPE_VAR_STRING:
+ case MYSQL_TYPE_DECIMAL:
+ case MYSQL_TYPE_NEWDECIMAL:
+ return getString(nColumnIndex);
+ case MYSQL_TYPE_BLOB:
+ case MYSQL_TYPE_TINY_BLOB:
+ case MYSQL_TYPE_MEDIUM_BLOB:
+ case MYSQL_TYPE_LONG_BLOB:
+ throw SQLException("Column with type BLOB cannot be converted", *this, "22000", 1,
+ Any());
+ default:
+ SAL_WARN("connectivity.mysqlc", "OPreparedResultSet::getRowSetValue: unknown type: "
+ << m_aFields[nColumnIndex - 1].type);
+ throw SQLException("Unknown column type when fetching result", *this, "22000", 1,
+ Any());
+ }
+}
+
+uno::Reference<XInputStream> SAL_CALL OPreparedResultSet::getBinaryStream(sal_Int32 /*column*/)
+{
+ mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedResultSet::getBinaryStream",
+ *this);
+ return nullptr;
+}
+
+uno::Reference<XInputStream> SAL_CALL OPreparedResultSet::getCharacterStream(sal_Int32 /*column*/)
+{
+ mysqlc_sdbc_driver::throwFeatureNotImplementedException(
+ "OPreparedResultSet::getCharacterStream", *this);
+ return nullptr;
+}
+
+sal_Bool SAL_CALL OPreparedResultSet::getBoolean(sal_Int32 column)
+{
+ return safelyRetrieveValue<bool>(column);
+}
+
+sal_Int8 SAL_CALL OPreparedResultSet::getByte(sal_Int32 column)
+{
+ return safelyRetrieveValue<sal_Int8>(column);
+}
+
+uno::Sequence<sal_Int8> SAL_CALL OPreparedResultSet::getBytes(sal_Int32 column)
+{
+ return safelyRetrieveValue<uno::Sequence<sal_Int8>>(column);
+}
+
+Date SAL_CALL OPreparedResultSet::getDate(sal_Int32 column)
+{
+ return safelyRetrieveValue<Date>(column);
+}
+
+double SAL_CALL OPreparedResultSet::getDouble(sal_Int32 column)
+{
+ return safelyRetrieveValue<double>(column);
+}
+
+float SAL_CALL OPreparedResultSet::getFloat(sal_Int32 column)
+{
+ return safelyRetrieveValue<float>(column);
+}
+
+sal_Int32 SAL_CALL OPreparedResultSet::getInt(sal_Int32 column)
+{
+ return safelyRetrieveValue<sal_Int32>(column);
+}
+
+sal_Int32 SAL_CALL OPreparedResultSet::getRow()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed);
+
+ return static_cast<sal_Int32>(mysql_field_tell(m_pResult));
+}
+
+sal_Int64 SAL_CALL OPreparedResultSet::getLong(sal_Int32 column)
+{
+ return safelyRetrieveValue<sal_Int64>(column);
+}
+
+uno::Reference<XResultSetMetaData> SAL_CALL OPreparedResultSet::getMetaData()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed);
+ if (!m_xMetaData.is())
+ {
+ m_xMetaData = new OResultSetMetaData(m_rConnection, m_pResult);
+ }
+ return m_xMetaData;
+}
+
+uno::Reference<XArray> SAL_CALL OPreparedResultSet::getArray(sal_Int32 column)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed);
+ checkColumnIndex(column);
+
+ mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedResultSet::getArray", *this);
+ return nullptr;
+}
+
+uno::Reference<XClob> SAL_CALL OPreparedResultSet::getClob(sal_Int32 column)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed);
+ checkColumnIndex(column);
+
+ mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedResultSet::getClob", *this);
+ return nullptr;
+}
+
+uno::Reference<XBlob> SAL_CALL OPreparedResultSet::getBlob(sal_Int32 column)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed);
+ checkColumnIndex(column);
+
+ mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedResultSet::getBlob", *this);
+ return nullptr;
+}
+
+uno::Reference<XRef> SAL_CALL OPreparedResultSet::getRef(sal_Int32 column)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed);
+ checkColumnIndex(column);
+
+ mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedResultSet::getRef", *this);
+ return nullptr;
+}
+
+Any SAL_CALL OPreparedResultSet::getObject(sal_Int32 column,
+ const uno::Reference<XNameAccess>& /* typeMap */)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed);
+ checkColumnIndex(column);
+
+ Any aRet;
+
+ mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedResultSet::getObject", *this);
+ return aRet;
+}
+
+sal_Int16 SAL_CALL OPreparedResultSet::getShort(sal_Int32 column)
+{
+ return safelyRetrieveValue<sal_Int16>(column);
+}
+
+OUString SAL_CALL OPreparedResultSet::getString(sal_Int32 column)
+{
+ return safelyRetrieveValue<OUString>(column);
+}
+
+Time SAL_CALL OPreparedResultSet::getTime(sal_Int32 column)
+{
+ return safelyRetrieveValue<Time>(column);
+}
+
+DateTime SAL_CALL OPreparedResultSet::getTimestamp(sal_Int32 column)
+{
+ return safelyRetrieveValue<DateTime>(column);
+}
+
+sal_Bool SAL_CALL OPreparedResultSet::isBeforeFirst()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed);
+
+ return m_nCurrentRow == 0;
+}
+
+sal_Bool SAL_CALL OPreparedResultSet::isAfterLast()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed);
+
+ return m_nCurrentRow > m_nRowCount;
+}
+
+sal_Bool SAL_CALL OPreparedResultSet::isFirst()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed);
+
+ return m_nCurrentRow == 1 && !isAfterLast();
+}
+
+sal_Bool SAL_CALL OPreparedResultSet::isLast()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed);
+
+ return m_nCurrentRow == m_nRowCount;
+}
+
+void SAL_CALL OPreparedResultSet::beforeFirst()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed);
+ mysql_stmt_data_seek(m_pStmt, 0);
+
+ m_nCurrentRow = 0;
+ m_aData.reset();
+}
+
+void SAL_CALL OPreparedResultSet::afterLast()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed);
+
+ mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedResultSet::afterLast", *this);
+}
+
+void SAL_CALL OPreparedResultSet::close()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed);
+
+ m_aData.reset();
+ m_aMetaData.reset();
+
+ if (m_pResult)
+ mysql_free_result(m_pResult);
+ mysql_stmt_free_result(m_pStmt);
+ dispose();
+}
+
+sal_Bool SAL_CALL OPreparedResultSet::first()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed);
+
+ mysql_stmt_data_seek(m_pStmt, 0);
+ m_nCurrentRow = 0;
+ next();
+
+ return true;
+}
+
+sal_Bool SAL_CALL OPreparedResultSet::last()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed);
+
+ mysql_stmt_data_seek(m_pStmt, m_nRowCount - 1);
+ next();
+
+ return true;
+}
+
+sal_Bool SAL_CALL OPreparedResultSet::absolute(sal_Int32 row)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed);
+
+ sal_Int32 nToGo = row < 0 ? m_nRowCount - row : row - 1;
+
+ if (nToGo >= m_nRowCount)
+ nToGo = m_nRowCount - 1;
+ if (nToGo < 0)
+ nToGo = 0;
+
+ mysql_stmt_data_seek(m_pStmt, nToGo);
+ next();
+
+ return true;
+}
+
+sal_Bool SAL_CALL OPreparedResultSet::relative(sal_Int32 row)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed);
+
+ if (row == 0)
+ return true;
+
+ sal_Int32 nToGo = m_nCurrentRow + row;
+ if (nToGo >= m_nRowCount)
+ nToGo = m_nRowCount - 1;
+ if (nToGo < 0)
+ nToGo = 0;
+
+ mysql_stmt_data_seek(m_pStmt, nToGo);
+ next();
+ m_nCurrentRow += row;
+
+ return true;
+}
+
+sal_Bool SAL_CALL OPreparedResultSet::previous()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed);
+
+ if (m_nCurrentRow <= 1)
+ return false;
+
+ mysql_stmt_data_seek(m_pStmt, m_nCurrentRow - 2);
+ next();
+ --m_nCurrentRow;
+ return true;
+}
+
+uno::Reference<uno::XInterface> SAL_CALL OPreparedResultSet::getStatement()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed);
+
+ return m_aStatement.get();
+}
+
+sal_Bool SAL_CALL OPreparedResultSet::rowDeleted()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed);
+
+ return false;
+}
+
+sal_Bool SAL_CALL OPreparedResultSet::rowInserted()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed);
+
+ return false;
+}
+
+sal_Bool SAL_CALL OPreparedResultSet::rowUpdated()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed);
+
+ return false;
+}
+
+sal_Bool SAL_CALL OPreparedResultSet::next()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed);
+ bool hasData = fetchResult();
+
+ // current field cannot be asked as a number. We have to keep track it
+ // manually.
+ m_nCurrentRow += 1;
+
+ return hasData;
+}
+
+sal_Bool SAL_CALL OPreparedResultSet::wasNull()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed);
+
+ return m_bWasNull;
+}
+
+void SAL_CALL OPreparedResultSet::cancel()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed);
+}
+
+void SAL_CALL OPreparedResultSet::clearWarnings() {}
+
+Any SAL_CALL OPreparedResultSet::getWarnings() { return Any(); }
+
+void SAL_CALL OPreparedResultSet::insertRow()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed);
+ // you only have to implement this if you want to insert new rows
+ mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedResultSet::insertRow", *this);
+}
+
+void SAL_CALL OPreparedResultSet::updateRow()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed);
+
+ // only when you allow updates
+ mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedResultSet::updateRow", *this);
+}
+
+void SAL_CALL OPreparedResultSet::deleteRow()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed);
+ mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedResultSet::deleteRow", *this);
+}
+
+void SAL_CALL OPreparedResultSet::cancelRowUpdates()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed);
+ mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedResultSet::cancelRowUpdates",
+ *this);
+}
+
+void SAL_CALL OPreparedResultSet::moveToInsertRow()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed);
+
+ // only when you allow insert's
+ mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedResultSet::moveToInsertRow",
+ *this);
+}
+
+void SAL_CALL OPreparedResultSet::moveToCurrentRow()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed);
+}
+
+void SAL_CALL OPreparedResultSet::updateNull(sal_Int32 column)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed);
+ checkColumnIndex(column);
+ mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedResultSet::updateNull",
+ *this);
+}
+
+void SAL_CALL OPreparedResultSet::updateBoolean(sal_Int32 column, sal_Bool /* x */)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed);
+ checkColumnIndex(column);
+ mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedResultSet::updateBoolean",
+ *this);
+}
+
+void SAL_CALL OPreparedResultSet::updateByte(sal_Int32 column, sal_Int8 /* x */)
+{
+ checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed);
+ MutexGuard aGuard(m_aMutex);
+ checkColumnIndex(column);
+ mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedResultSet::updateByte",
+ *this);
+}
+
+void SAL_CALL OPreparedResultSet::updateShort(sal_Int32 column, sal_Int16 /* x */)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed);
+ checkColumnIndex(column);
+ mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedResultSet::updateShort",
+ *this);
+}
+
+void SAL_CALL OPreparedResultSet::updateInt(sal_Int32 column, sal_Int32 /* x */)
+{
+ checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed);
+ MutexGuard aGuard(m_aMutex);
+ checkColumnIndex(column);
+ mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedResultSet::updateInt", *this);
+}
+
+void SAL_CALL OPreparedResultSet::updateLong(sal_Int32 column, sal_Int64 /* x */)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed);
+ checkColumnIndex(column);
+ mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedResultSet::updateLong",
+ *this);
+}
+
+void SAL_CALL OPreparedResultSet::updateFloat(sal_Int32 column, float /* x */)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed);
+ checkColumnIndex(column);
+ mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedResultSet::updateFloat",
+ *this);
+}
+
+void SAL_CALL OPreparedResultSet::updateDouble(sal_Int32 column, double /* x */)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed);
+ checkColumnIndex(column);
+ mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedResultSet::updateDouble",
+ *this);
+}
+
+void SAL_CALL OPreparedResultSet::updateString(sal_Int32 column, const OUString& /* x */)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed);
+ checkColumnIndex(column);
+ mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedResultSet::updateString",
+ *this);
+}
+
+void SAL_CALL OPreparedResultSet::updateBytes(sal_Int32 column,
+ const uno::Sequence<sal_Int8>& /* x */)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed);
+ checkColumnIndex(column);
+ mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedResultSet::updateBytes",
+ *this);
+}
+
+void SAL_CALL OPreparedResultSet::updateDate(sal_Int32 column, const Date& /* x */)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed);
+ checkColumnIndex(column);
+ mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedResultSet::updateDate",
+ *this);
+}
+
+void SAL_CALL OPreparedResultSet::updateTime(sal_Int32 column, const Time& /* x */)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed);
+ checkColumnIndex(column);
+ mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedResultSet::updateTime",
+ *this);
+}
+
+void SAL_CALL OPreparedResultSet::updateTimestamp(sal_Int32 column, const DateTime& /* x */)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed);
+ checkColumnIndex(column);
+ mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedResultSet::updateTimestamp",
+ *this);
+}
+
+void SAL_CALL OPreparedResultSet::updateBinaryStream(sal_Int32 column,
+ const uno::Reference<XInputStream>& /* x */,
+ sal_Int32 /* length */)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed);
+ checkColumnIndex(column);
+ mysqlc_sdbc_driver::throwFeatureNotImplementedException(
+ "OPreparedResultSet::updateBinaryStream", *this);
+}
+
+void SAL_CALL OPreparedResultSet::updateCharacterStream(sal_Int32 column,
+ const uno::Reference<XInputStream>& /* x */,
+ sal_Int32 /* length */)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed);
+ checkColumnIndex(column);
+ mysqlc_sdbc_driver::throwFeatureNotImplementedException(
+ "OPreparedResultSet::updateCharacterStream", *this);
+}
+
+void SAL_CALL OPreparedResultSet::refreshRow()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed);
+ mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedResultSet::refreshRow",
+ *this);
+}
+
+void SAL_CALL OPreparedResultSet::updateObject(sal_Int32 column, const Any& /* x */)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed);
+ checkColumnIndex(column);
+ mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedResultSet::updateObject",
+ *this);
+}
+
+void SAL_CALL OPreparedResultSet::updateNumericObject(sal_Int32 column, const Any& /* x */,
+ sal_Int32 /* scale */)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed);
+ checkColumnIndex(column);
+ mysqlc_sdbc_driver::throwFeatureNotImplementedException(
+ "OPreparedResultSet::updateNumericObject", *this);
+}
+
+// XRowLocate
+Any SAL_CALL OPreparedResultSet::getBookmark()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed);
+
+ // if you don't want to support bookmark you must remove the XRowLocate interface
+ mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedResultSet::getBookmark",
+ *this);
+
+ return Any();
+}
+
+sal_Bool SAL_CALL OPreparedResultSet::moveToBookmark(const Any& /* bookmark */)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed);
+
+ return false;
+}
+
+sal_Bool SAL_CALL OPreparedResultSet::moveRelativeToBookmark(const Any& /* bookmark */,
+ sal_Int32 /* rows */)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed);
+
+ mysqlc_sdbc_driver::throwFeatureNotImplementedException(
+ "OPreparedResultSet::moveRelativeToBookmark", *this);
+ return false;
+}
+
+sal_Int32 SAL_CALL OPreparedResultSet::compareBookmarks(const Any& /* n1 */, const Any& /* n2 */)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed);
+
+ mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedResultSet::compareBookmarks",
+ *this);
+
+ return CompareBookmark::NOT_EQUAL;
+}
+
+sal_Bool SAL_CALL OPreparedResultSet::hasOrderedBookmarks() { return false; }
+
+sal_Int32 SAL_CALL OPreparedResultSet::hashBookmark(const Any& /* bookmark */)
+{
+ mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedResultSet::hashBookmark",
+ *this);
+ return 0;
+}
+
+// XDeleteRows
+uno::Sequence<sal_Int32>
+ SAL_CALL OPreparedResultSet::deleteRows(const uno::Sequence<Any>& /* rows */)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed);
+
+ mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedResultSet::deleteRows",
+ *this);
+ return uno::Sequence<sal_Int32>();
+}
+
+IPropertyArrayHelper* OPreparedResultSet::createArrayHelper() const
+{
+ return new OPropertyArrayHelper{
+ { { "FetchDirection", PROPERTY_ID_FETCHDIRECTION, cppu::UnoType<sal_Int32>::get(), 0 },
+ { "FetchSize", PROPERTY_ID_FETCHSIZE, cppu::UnoType<sal_Int32>::get(), 0 },
+ { "IsBookmarkable", PROPERTY_ID_ISBOOKMARKABLE, cppu::UnoType<bool>::get(),
+ PropertyAttribute::READONLY },
+ { "ResultSetConcurrency", PROPERTY_ID_RESULTSETCONCURRENCY,
+ cppu::UnoType<sal_Int32>::get(), PropertyAttribute::READONLY },
+ { "ResultSetType", PROPERTY_ID_RESULTSETTYPE, cppu::UnoType<sal_Int32>::get(),
+ PropertyAttribute::READONLY } }
+ };
+}
+
+IPropertyArrayHelper& OPreparedResultSet::getInfoHelper() { return *getArrayHelper(); }
+
+sal_Bool OPreparedResultSet::convertFastPropertyValue(Any& /* rConvertedValue */,
+ Any& /* rOldValue */, sal_Int32 nHandle,
+ const Any& /* rValue */)
+{
+ switch (nHandle)
+ {
+ case PROPERTY_ID_ISBOOKMARKABLE:
+ case PROPERTY_ID_CURSORNAME:
+ case PROPERTY_ID_RESULTSETCONCURRENCY:
+ case PROPERTY_ID_RESULTSETTYPE:
+ throw css::lang::IllegalArgumentException();
+ case PROPERTY_ID_FETCHDIRECTION:
+ case PROPERTY_ID_FETCHSIZE:
+ default:;
+ }
+ return false;
+}
+
+void OPreparedResultSet::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,
+ const Any& /* rValue */)
+{
+ switch (nHandle)
+ {
+ case PROPERTY_ID_ISBOOKMARKABLE:
+ case PROPERTY_ID_CURSORNAME:
+ case PROPERTY_ID_RESULTSETCONCURRENCY:
+ case PROPERTY_ID_RESULTSETTYPE:
+ throw uno::Exception("cannot set prop " + OUString::number(nHandle), nullptr);
+ case PROPERTY_ID_FETCHDIRECTION:
+ break;
+ case PROPERTY_ID_FETCHSIZE:
+ break;
+ default:;
+ }
+}
+
+void OPreparedResultSet::getFastPropertyValue(Any& _rValue, sal_Int32 nHandle) const
+{
+ switch (nHandle)
+ {
+ case PROPERTY_ID_ISBOOKMARKABLE:
+ _rValue <<= false;
+ break;
+ case PROPERTY_ID_CURSORNAME:
+ break;
+ case PROPERTY_ID_RESULTSETCONCURRENCY:
+ _rValue <<= ResultSetConcurrency::READ_ONLY;
+ break;
+ case PROPERTY_ID_RESULTSETTYPE:
+ _rValue <<= ResultSetType::SCROLL_INSENSITIVE;
+ break;
+ case PROPERTY_ID_FETCHDIRECTION:
+ _rValue <<= FetchDirection::FORWARD;
+ break;
+ case PROPERTY_ID_FETCHSIZE:
+ _rValue <<= sal_Int32(50);
+ break;
+ ;
+ default:;
+ }
+}
+
+void SAL_CALL OPreparedResultSet::acquire() noexcept { OPreparedResultSet_BASE::acquire(); }
+
+void SAL_CALL OPreparedResultSet::release() noexcept { OPreparedResultSet_BASE::release(); }
+
+css::uno::Reference<css::beans::XPropertySetInfo> SAL_CALL OPreparedResultSet::getPropertySetInfo()
+{
+ return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper());
+}
+
+void OPreparedResultSet::checkColumnIndex(sal_Int32 index)
+{
+ if (!m_aData)
+ throw SQLException("Cursor out of range", *this, "HY109", 1, Any());
+ if (index < 1 || index > static_cast<int>(m_nColumnCount))
+ {
+ /* static object for efficiency or thread safety is a problem ? */
+ throw SQLException("index out of range", *this, "42S22", 1, Any());
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/mysqlc/mysqlc_prepared_resultset.hxx b/connectivity/source/drivers/mysqlc/mysqlc_prepared_resultset.hxx
new file mode 100644
index 0000000000..40912c5534
--- /dev/null
+++ b/connectivity/source/drivers/mysqlc/mysqlc_prepared_resultset.hxx
@@ -0,0 +1,251 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "mysqlc_preparedstatement.hxx"
+#include "mysqlc_statement.hxx"
+#include "mysqlc_subcomponent.hxx"
+#include "mysqlc_connection.hxx"
+
+#include <com/sun/star/sdbc/XCloseable.hpp>
+#include <com/sun/star/sdbc/XColumnLocate.hpp>
+#include <com/sun/star/sdbc/XResultSet.hpp>
+#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
+#include <com/sun/star/sdbc/XResultSetUpdate.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XRowUpdate.hpp>
+#include <com/sun/star/sdbc/XWarningsSupplier.hpp>
+#include <com/sun/star/sdbcx/XDeleteRows.hpp>
+#include <com/sun/star/sdbcx/XRowLocate.hpp>
+#include <com/sun/star/util/XCancellable.hpp>
+#include <connectivity/FValue.hxx>
+
+#include <cppuhelper/compbase12.hxx>
+
+namespace connectivity::mysqlc
+{
+using ::com::sun::star::uno::Any;
+
+typedef ::cppu::WeakComponentImplHelper12<
+ css::sdbc::XResultSet, css::sdbc::XRow, css::sdbc::XResultSetMetaDataSupplier,
+ css::util::XCancellable, css::sdbc::XWarningsSupplier, css::sdbc::XResultSetUpdate,
+ css::sdbc::XRowUpdate, css::sdbcx::XRowLocate, css::sdbcx::XDeleteRows, css::sdbc::XCloseable,
+ css::sdbc::XColumnLocate, css::lang::XServiceInfo>
+ OPreparedResultSet_BASE;
+
+class OPreparedResultSet final : public cppu::BaseMutex,
+ public OPreparedResultSet_BASE,
+ public ::cppu::OPropertySetHelper,
+ public OPropertyArrayUsageHelper<OPreparedResultSet>
+{
+ OConnection& m_rConnection;
+ css::uno::WeakReferenceHelper m_aStatement;
+ css::uno::Reference<css::sdbc::XResultSetMetaData> m_xMetaData;
+
+ // non-owning pointers
+ MYSQL_RES* m_pResult;
+ MYSQL_STMT* m_pStmt;
+ MYSQL_FIELD* m_aFields;
+
+ rtl_TextEncoding m_encoding;
+ sal_Int32 m_nCurrentRow = 0;
+ sal_Int32 m_nColumnCount;
+ sal_Int32 m_nRowCount;
+
+ // Use c style arrays, because we have to work with pointers
+ // on these.
+ std::unique_ptr<MYSQL_BIND[]> m_aData;
+ std::unique_ptr<BindMetaData[]> m_aMetaData;
+
+ bool m_bWasNull = false;
+
+ // OPropertyArrayUsageHelper
+ ::cppu::IPropertyArrayHelper* createArrayHelper() const override;
+ // OPropertySetHelper
+ ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override;
+
+ sal_Bool SAL_CALL convertFastPropertyValue(Any& rConvertedValue, Any& rOldValue,
+ sal_Int32 nHandle, const Any& rValue) override;
+
+ void SAL_CALL setFastPropertyValue_NoBroadcast(sal_Int32 nHandle, const Any& rValue) override;
+
+ void SAL_CALL getFastPropertyValue(Any& rValue, sal_Int32 nHandle) const override;
+
+ template <typename T> T safelyRetrieveValue(const sal_Int32 nColumnIndex);
+ template <typename T> T retrieveValue(const sal_Int32 nColumnIndex);
+ connectivity::ORowSetValue getRowSetValue(sal_Int32 nColumnIndex);
+
+ bool fetchResult();
+
+ // you can't delete objects of this type
+ virtual ~OPreparedResultSet() override = default;
+
+public:
+ virtual OUString SAL_CALL getImplementationName() override;
+
+ virtual sal_Bool SAL_CALL supportsService(OUString const& ServiceName) override;
+
+ virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override;
+
+ OPreparedResultSet(OConnection& rConn, OPreparedStatement* pStmt, MYSQL_STMT* pMyStmt);
+
+ // ::cppu::OComponentHelper
+ void SAL_CALL disposing() override;
+
+ // XInterface
+ Any SAL_CALL queryInterface(const css::uno::Type& rType) override;
+
+ void SAL_CALL acquire() noexcept override;
+ void SAL_CALL release() noexcept override;
+
+ //XTypeProvider
+ css::uno::Sequence<css::uno::Type> SAL_CALL getTypes() override;
+
+ // XPropertySet
+ css::uno::Reference<css::beans::XPropertySetInfo> SAL_CALL getPropertySetInfo() override;
+
+ // XResultSet
+ sal_Bool SAL_CALL next() override;
+ sal_Bool SAL_CALL isBeforeFirst() override;
+ sal_Bool SAL_CALL isAfterLast() override;
+ sal_Bool SAL_CALL isFirst() override;
+ sal_Bool SAL_CALL isLast() override;
+
+ void SAL_CALL beforeFirst() override;
+ void SAL_CALL afterLast() override;
+
+ sal_Bool SAL_CALL first() override;
+ sal_Bool SAL_CALL last() override;
+
+ sal_Int32 SAL_CALL getRow() override;
+
+ sal_Bool SAL_CALL absolute(sal_Int32 row) override;
+ sal_Bool SAL_CALL relative(sal_Int32 rows) override;
+ sal_Bool SAL_CALL previous() override;
+
+ void SAL_CALL refreshRow() override;
+
+ sal_Bool SAL_CALL rowUpdated() override;
+ sal_Bool SAL_CALL rowInserted() override;
+ sal_Bool SAL_CALL rowDeleted() override;
+
+ css::uno::Reference<css::uno::XInterface> SAL_CALL getStatement() override;
+ // XRow
+ sal_Bool SAL_CALL wasNull() override;
+
+ OUString SAL_CALL getString(sal_Int32 column) override;
+
+ sal_Bool SAL_CALL getBoolean(sal_Int32 column) override;
+ sal_Int8 SAL_CALL getByte(sal_Int32 column) override;
+ sal_Int16 SAL_CALL getShort(sal_Int32 column) override;
+ sal_Int32 SAL_CALL getInt(sal_Int32 column) override;
+ sal_Int64 SAL_CALL getLong(sal_Int32 column) override;
+
+ float SAL_CALL getFloat(sal_Int32 column) override;
+ double SAL_CALL getDouble(sal_Int32 column) override;
+
+ css::uno::Sequence<sal_Int8> SAL_CALL getBytes(sal_Int32 column) override;
+ css::util::Date SAL_CALL getDate(sal_Int32 column) override;
+ css::util::Time SAL_CALL getTime(sal_Int32 column) override;
+ css::util::DateTime SAL_CALL getTimestamp(sal_Int32 column) override;
+
+ css::uno::Reference<css::io::XInputStream> SAL_CALL getBinaryStream(sal_Int32 column) override;
+ css::uno::Reference<css::io::XInputStream>
+ SAL_CALL getCharacterStream(sal_Int32 column) override;
+
+ Any SAL_CALL getObject(
+ sal_Int32 column, const css::uno::Reference<css::container::XNameAccess>& typeMap) override;
+
+ css::uno::Reference<css::sdbc::XRef> SAL_CALL getRef(sal_Int32 column) override;
+ css::uno::Reference<css::sdbc::XBlob> SAL_CALL getBlob(sal_Int32 column) override;
+ css::uno::Reference<css::sdbc::XClob> SAL_CALL getClob(sal_Int32 column) override;
+ css::uno::Reference<css::sdbc::XArray> SAL_CALL getArray(sal_Int32 column) override;
+
+ // XResultSetMetaDataSupplier
+ css::uno::Reference<css::sdbc::XResultSetMetaData> SAL_CALL getMetaData() override;
+
+ // XCancellable
+ void SAL_CALL cancel() override;
+
+ // XCloseable
+ void SAL_CALL close() override;
+
+ // XWarningsSupplier
+ Any SAL_CALL getWarnings() override;
+
+ void SAL_CALL clearWarnings() override;
+
+ // XResultSetUpdate
+ void SAL_CALL insertRow() override;
+ void SAL_CALL updateRow() override;
+ void SAL_CALL deleteRow() override;
+ void SAL_CALL cancelRowUpdates() override;
+ void SAL_CALL moveToInsertRow() override;
+ void SAL_CALL moveToCurrentRow() override;
+
+ // XRowUpdate
+ void SAL_CALL updateNull(sal_Int32 column) override;
+ void SAL_CALL updateBoolean(sal_Int32 column, sal_Bool x) override;
+ void SAL_CALL updateByte(sal_Int32 column, sal_Int8 x) override;
+ void SAL_CALL updateShort(sal_Int32 column, sal_Int16 x) override;
+ void SAL_CALL updateInt(sal_Int32 column, sal_Int32 x) override;
+ void SAL_CALL updateLong(sal_Int32 column, sal_Int64 x) override;
+ void SAL_CALL updateFloat(sal_Int32 column, float x) override;
+ void SAL_CALL updateDouble(sal_Int32 column, double x) override;
+ void SAL_CALL updateString(sal_Int32 column, const OUString& x) override;
+ void SAL_CALL updateBytes(sal_Int32 column, const css::uno::Sequence<sal_Int8>& x) override;
+ void SAL_CALL updateDate(sal_Int32 column, const css::util::Date& x) override;
+ void SAL_CALL updateTime(sal_Int32 column, const css::util::Time& x) override;
+ void SAL_CALL updateTimestamp(sal_Int32 column, const css::util::DateTime& x) override;
+ void SAL_CALL updateBinaryStream(sal_Int32 column,
+ const css::uno::Reference<css::io::XInputStream>& x,
+ sal_Int32 length) override;
+ void SAL_CALL updateCharacterStream(sal_Int32 column,
+ const css::uno::Reference<css::io::XInputStream>& x,
+ sal_Int32 length) override;
+ void SAL_CALL updateObject(sal_Int32 column, const Any& x) override;
+ void SAL_CALL updateNumericObject(sal_Int32 column, const Any& x, sal_Int32 scale) override;
+
+ // XColumnLocate
+ sal_Int32 SAL_CALL findColumn(const OUString& columnName) override;
+
+ // XRowLocate
+ Any SAL_CALL getBookmark() override;
+
+ sal_Bool SAL_CALL moveToBookmark(const Any& bookmark) override;
+ sal_Bool SAL_CALL moveRelativeToBookmark(const Any& bookmark, sal_Int32 rows) override;
+ sal_Int32 SAL_CALL compareBookmarks(const Any& first, const Any& second) override;
+ sal_Bool SAL_CALL hasOrderedBookmarks() override;
+ sal_Int32 SAL_CALL hashBookmark(const Any& bookmark) override;
+
+ // XDeleteRows
+ css::uno::Sequence<sal_Int32> SAL_CALL deleteRows(const css::uno::Sequence<Any>& rows) override;
+
+ /// @throws SQLException
+ /// @throws RuntimeException
+ void checkColumnIndex(sal_Int32 index);
+
+private:
+ using ::cppu::OPropertySetHelper::getFastPropertyValue;
+};
+
+} /* connectivity::mysqlc */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/mysqlc/mysqlc_preparedstatement.cxx b/connectivity/source/drivers/mysqlc/mysqlc_preparedstatement.cxx
new file mode 100644
index 0000000000..7a8921f085
--- /dev/null
+++ b/connectivity/source/drivers/mysqlc/mysqlc_preparedstatement.cxx
@@ -0,0 +1,580 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "mysqlc_general.hxx"
+#include "mysqlc_prepared_resultset.hxx"
+#include "mysqlc_preparedstatement.hxx"
+#include "mysqlc_propertyids.hxx"
+#include "mysqlc_resultsetmetadata.hxx"
+
+#include <o3tl/safeint.hxx>
+#include <sal/log.hxx>
+
+#include <com/sun/star/sdbc/DataType.hpp>
+
+#include <stdio.h>
+
+using namespace connectivity::mysqlc;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::sdbc;
+using namespace com::sun::star::container;
+using namespace com::sun::star::io;
+using namespace com::sun::star::util;
+using ::osl::MutexGuard;
+
+OUString OPreparedStatement::getImplementationName()
+{
+ return "com.sun.star.sdbcx.mysqlc.PreparedStatement";
+}
+
+css::uno::Sequence<OUString> OPreparedStatement::getSupportedServiceNames()
+{
+ return { "com.sun.star.sdbc.PreparedStatement" };
+}
+
+sal_Bool OPreparedStatement::supportsService(OUString const& ServiceName)
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+OPreparedStatement::OPreparedStatement(OConnection* _pConnection, MYSQL_STMT* pStmt)
+ : OCommonStatement(_pConnection)
+ , m_pStmt(pStmt)
+{
+ m_paramCount = mysql_stmt_param_count(m_pStmt);
+ m_binds.reserve(m_paramCount);
+ m_bindMetas.reserve(m_paramCount);
+ for (unsigned i = 0; i < m_paramCount; ++i)
+ {
+ m_binds.push_back(MYSQL_BIND{});
+ m_bindMetas.push_back(BindMetaData{});
+ m_binds.back().is_null = &m_bindMetas.back().is_null;
+ m_binds.back().length = &m_bindMetas.back().length;
+ m_binds.back().buffer = nullptr;
+ }
+}
+
+OPreparedStatement::~OPreparedStatement() {}
+
+void SAL_CALL OPreparedStatement::acquire() noexcept { OCommonStatement::acquire(); }
+
+void SAL_CALL OPreparedStatement::release() noexcept { OCommonStatement::release(); }
+
+Any SAL_CALL OPreparedStatement::queryInterface(const Type& rType)
+{
+ Any aRet = OCommonStatement::queryInterface(rType);
+ if (!aRet.hasValue())
+ {
+ aRet = OPreparedStatement_BASE::queryInterface(rType);
+ }
+ return aRet;
+}
+
+Sequence<Type> SAL_CALL OPreparedStatement::getTypes()
+{
+ return concatSequences(OPreparedStatement_BASE::getTypes(), OCommonStatement::getTypes());
+}
+
+Reference<XResultSetMetaData> SAL_CALL OPreparedStatement::getMetaData()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(rBHelper.bDisposed);
+
+ if (!m_xMetaData.is())
+ {
+ MYSQL_RES* pRes = mysql_stmt_result_metadata(m_pStmt);
+ // TODO warning or error if no meta data.
+ m_xMetaData = new OResultSetMetaData(*m_xConnection, pRes);
+ }
+ return m_xMetaData;
+}
+
+void SAL_CALL OPreparedStatement::close()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(rBHelper.bDisposed);
+
+ if (mysql_stmt_close(m_pStmt))
+ {
+ SAL_WARN("connectivity.mysqlc", "failed to close mysql prepared statement");
+ }
+ m_pStmt = nullptr; // it's deallocated already
+ clearWarnings();
+ clearParameters();
+ OCommonStatement::close();
+}
+
+sal_Bool SAL_CALL OPreparedStatement::execute()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(rBHelper.bDisposed);
+
+ if (!m_binds.empty() && mysql_stmt_bind_param(m_pStmt, m_binds.data()))
+ {
+ MYSQL* pMysql = m_xConnection->getMysqlConnection();
+ mysqlc_sdbc_driver::throwSQLExceptionWithMsg(mysql_stmt_error(m_pStmt),
+ mysql_sqlstate(pMysql), mysql_errno(pMysql),
+ *this, m_xConnection->getConnectionEncoding());
+ }
+
+ int nFail = mysql_stmt_execute(m_pStmt);
+ if (nFail != 0)
+ {
+ MYSQL* pMysql = m_xConnection->getMysqlConnection();
+ mysqlc_sdbc_driver::throwSQLExceptionWithMsg(mysql_stmt_error(m_pStmt),
+ mysql_sqlstate(pMysql), mysql_errno(pMysql),
+ *this, m_xConnection->getConnectionEncoding());
+ }
+
+ return !nFail;
+}
+
+sal_Int32 SAL_CALL OPreparedStatement::executeUpdate()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(rBHelper.bDisposed);
+
+ if (!m_binds.empty() && mysql_stmt_bind_param(m_pStmt, m_binds.data()))
+ {
+ MYSQL* pMysql = m_xConnection->getMysqlConnection();
+ mysqlc_sdbc_driver::throwSQLExceptionWithMsg(mysql_stmt_error(m_pStmt),
+ mysql_sqlstate(pMysql), mysql_errno(pMysql),
+ *this, m_xConnection->getConnectionEncoding());
+ }
+
+ int nFail = mysql_stmt_execute(m_pStmt);
+
+ if (nFail != 0)
+ {
+ MYSQL* pMysql = m_xConnection->getMysqlConnection();
+ mysqlc_sdbc_driver::throwSQLExceptionWithMsg(mysql_stmt_error(m_pStmt),
+ mysql_sqlstate(pMysql), mysql_errno(pMysql),
+ *this, m_xConnection->getConnectionEncoding());
+ }
+
+ sal_Int32 affectedRows = mysql_stmt_affected_rows(m_pStmt);
+ return affectedRows;
+}
+
+void SAL_CALL OPreparedStatement::setString(sal_Int32 parameter, const OUString& x)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(rBHelper.bDisposed);
+ checkParameterIndex(parameter);
+
+ OString stringie(OUStringToOString(x, m_xConnection->getConnectionEncoding()));
+ const sal_Int32 nIndex = parameter - 1;
+ m_binds[nIndex].buffer_type = MYSQL_TYPE_STRING;
+ mysqlc_sdbc_driver::resetSqlVar(&m_binds[nIndex].buffer, stringie.getStr(), MYSQL_TYPE_STRING,
+ stringie.getLength());
+ m_bindMetas[nIndex].is_null = false;
+ m_bindMetas[nIndex].length = stringie.getLength();
+}
+
+Reference<XConnection> SAL_CALL OPreparedStatement::getConnection()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(rBHelper.bDisposed);
+
+ return m_xConnection;
+}
+
+Reference<XResultSet> SAL_CALL OPreparedStatement::executeQuery()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(rBHelper.bDisposed);
+
+ if (!m_binds.empty() && mysql_stmt_bind_param(m_pStmt, m_binds.data()))
+ {
+ MYSQL* pMysql = m_xConnection->getMysqlConnection();
+ mysqlc_sdbc_driver::throwSQLExceptionWithMsg(mysql_stmt_error(m_pStmt),
+ mysql_sqlstate(pMysql), mysql_errno(pMysql),
+ *this, m_xConnection->getConnectionEncoding());
+ }
+
+ int nFail = mysql_stmt_execute(m_pStmt);
+
+ if (nFail != 0)
+ {
+ MYSQL* pMysql = m_xConnection->getMysqlConnection();
+ mysqlc_sdbc_driver::throwSQLExceptionWithMsg(mysql_stmt_error(m_pStmt),
+ mysql_sqlstate(pMysql), mysql_errno(pMysql),
+ *this, m_xConnection->getConnectionEncoding());
+ }
+
+ Reference<XResultSet> xResultSet = new OPreparedResultSet(*m_xConnection, this, m_pStmt);
+ return xResultSet;
+}
+
+void SAL_CALL OPreparedStatement::setBoolean(sal_Int32 parameter, sal_Bool x)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(rBHelper.bDisposed);
+ checkParameterIndex(parameter);
+
+ const sal_Int32 nIndex = parameter - 1;
+ m_binds[nIndex].buffer_type = MYSQL_TYPE_TINY;
+ mysqlc_sdbc_driver::resetSqlVar(&m_binds[nIndex].buffer, &x, MYSQL_TYPE_TINY);
+ m_bindMetas[nIndex].is_null = false;
+}
+
+void SAL_CALL OPreparedStatement::setByte(sal_Int32 parameter, sal_Int8 x)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(rBHelper.bDisposed);
+ checkParameterIndex(parameter);
+
+ const sal_Int32 nIndex = parameter - 1;
+ m_binds[nIndex].buffer_type = MYSQL_TYPE_TINY;
+ mysqlc_sdbc_driver::resetSqlVar(&m_binds[nIndex].buffer, &x, MYSQL_TYPE_TINY);
+ m_bindMetas[nIndex].is_null = false;
+}
+
+void SAL_CALL OPreparedStatement::setDate(sal_Int32 parameter, const Date& aData)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(rBHelper.bDisposed);
+ checkParameterIndex(parameter);
+
+ MYSQL_TIME my_time = {};
+
+ my_time.year = aData.Year;
+ my_time.month = aData.Month;
+ my_time.day = aData.Day;
+
+ const sal_Int32 nIndex = parameter - 1;
+ m_binds[nIndex].buffer_type = MYSQL_TYPE_DATE;
+ mysqlc_sdbc_driver::resetSqlVar(&m_binds[nIndex].buffer, &my_time, MYSQL_TYPE_DATE);
+ m_bindMetas[nIndex].is_null = false;
+}
+
+void SAL_CALL OPreparedStatement::setTime(sal_Int32 parameter, const Time& aVal)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(rBHelper.bDisposed);
+ checkParameterIndex(parameter);
+
+ MYSQL_TIME my_time = {};
+
+ my_time.hour = aVal.Hours;
+ my_time.minute = aVal.Minutes;
+ my_time.second = aVal.Seconds;
+
+ const sal_Int32 nIndex = parameter - 1;
+ m_binds[nIndex].buffer_type = MYSQL_TYPE_TIME;
+ mysqlc_sdbc_driver::resetSqlVar(&m_binds[nIndex].buffer, &my_time, MYSQL_TYPE_TIME);
+ m_bindMetas[nIndex].is_null = false;
+}
+
+void SAL_CALL OPreparedStatement::setTimestamp(sal_Int32 parameter, const DateTime& aVal)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(rBHelper.bDisposed);
+ checkParameterIndex(parameter);
+
+ MYSQL_TIME my_time = {};
+
+ my_time.hour = aVal.Hours;
+ my_time.minute = aVal.Minutes;
+ my_time.second = aVal.Seconds;
+ my_time.year = aVal.Year;
+ my_time.month = aVal.Month;
+ my_time.day = aVal.Day;
+
+ const sal_Int32 nIndex = parameter - 1;
+ m_binds[nIndex].buffer_type = MYSQL_TYPE_DATETIME;
+ mysqlc_sdbc_driver::resetSqlVar(&m_binds[nIndex].buffer, &my_time, MYSQL_TYPE_DATETIME);
+ m_bindMetas[nIndex].is_null = false;
+}
+
+void SAL_CALL OPreparedStatement::setDouble(sal_Int32 parameter, double x)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(rBHelper.bDisposed);
+ checkParameterIndex(parameter);
+
+ const sal_Int32 nIndex = parameter - 1;
+ m_binds[nIndex].buffer_type = MYSQL_TYPE_DOUBLE;
+ mysqlc_sdbc_driver::resetSqlVar(&m_binds[nIndex].buffer, &x, MYSQL_TYPE_DOUBLE);
+ m_bindMetas[nIndex].is_null = false;
+}
+
+void SAL_CALL OPreparedStatement::setFloat(sal_Int32 parameter, float x)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(rBHelper.bDisposed);
+ checkParameterIndex(parameter);
+
+ const sal_Int32 nIndex = parameter - 1;
+ m_binds[nIndex].buffer_type = MYSQL_TYPE_FLOAT;
+ mysqlc_sdbc_driver::resetSqlVar(&m_binds[nIndex].buffer, &x, MYSQL_TYPE_FLOAT);
+ m_bindMetas[nIndex].is_null = false;
+}
+
+void SAL_CALL OPreparedStatement::setInt(sal_Int32 parameter, sal_Int32 x)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(rBHelper.bDisposed);
+ checkParameterIndex(parameter);
+
+ const sal_Int32 nIndex = parameter - 1;
+ m_binds[nIndex].buffer_type = MYSQL_TYPE_LONG;
+ mysqlc_sdbc_driver::resetSqlVar(&m_binds[nIndex].buffer, &x, MYSQL_TYPE_LONG);
+ m_bindMetas[nIndex].is_null = false;
+}
+
+void SAL_CALL OPreparedStatement::setLong(sal_Int32 parameter, sal_Int64 aVal)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(rBHelper.bDisposed);
+ checkParameterIndex(parameter);
+
+ const sal_Int32 nIndex = parameter - 1;
+ m_binds[nIndex].buffer_type = MYSQL_TYPE_LONGLONG;
+ mysqlc_sdbc_driver::resetSqlVar(&m_binds[nIndex].buffer, &aVal, MYSQL_TYPE_LONGLONG);
+ m_bindMetas[nIndex].is_null = false;
+}
+
+void SAL_CALL OPreparedStatement::setNull(sal_Int32 parameter, sal_Int32 /*sqlType*/)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(rBHelper.bDisposed);
+ checkParameterIndex(parameter);
+
+ const sal_Int32 nIndex = parameter - 1;
+ m_bindMetas[nIndex].is_null = true;
+ free(m_binds[nIndex].buffer);
+ m_binds[nIndex].buffer = nullptr;
+}
+
+void SAL_CALL OPreparedStatement::setClob(sal_Int32 parameter, const Reference<XClob>& /* x */)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(rBHelper.bDisposed);
+ checkParameterIndex(parameter);
+
+ mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedStatement::setClob", *this);
+}
+
+void SAL_CALL OPreparedStatement::setBlob(sal_Int32 parameter, const Reference<XBlob>& /* x */)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(rBHelper.bDisposed);
+ checkParameterIndex(parameter);
+
+ mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedStatement::setBlob", *this);
+}
+
+void SAL_CALL OPreparedStatement::setArray(sal_Int32 parameter, const Reference<XArray>& /* x */)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(rBHelper.bDisposed);
+ checkParameterIndex(parameter);
+
+ mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedStatement::setArray", *this);
+}
+
+void SAL_CALL OPreparedStatement::setRef(sal_Int32 parameter, const Reference<XRef>& /* x */)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(rBHelper.bDisposed);
+ checkParameterIndex(parameter);
+
+ mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedStatement::setRef", *this);
+}
+
+void SAL_CALL OPreparedStatement::setObjectWithInfo(sal_Int32 parameterIndex, const Any& value,
+ sal_Int32 targetSqlType, sal_Int32 /* scale */)
+{
+ checkDisposed(rBHelper.bDisposed);
+ MutexGuard aGuard(m_aMutex);
+ checkParameterIndex(parameterIndex);
+
+ const sal_Int32 nIndex = parameterIndex - 1;
+ if (!value.hasValue())
+ {
+ free(m_binds[nIndex].buffer);
+ m_binds[nIndex].buffer = nullptr;
+ m_bindMetas[parameterIndex - 1].is_null = true;
+ return;
+ }
+
+ switch (targetSqlType)
+ {
+ case DataType::DECIMAL:
+ case DataType::NUMERIC:
+ {
+ double nValue(0.0);
+ OUString sValue;
+ if (value >>= nValue)
+ {
+ setDouble(parameterIndex, nValue);
+ break;
+ }
+ else if (value >>= sValue)
+ {
+ OString sAscii
+ = OUStringToOString(sValue, getOwnConnection()->getConnectionEncoding());
+ std::stringstream sStream{ std::string(sAscii) };
+ sStream >> nValue;
+ m_binds[nIndex].buffer_type = MYSQL_TYPE_DOUBLE;
+ mysqlc_sdbc_driver::resetSqlVar(&m_binds[nIndex].buffer, &nValue, MYSQL_TYPE_DOUBLE,
+ sValue.getLength());
+ m_bindMetas[nIndex].is_null = false;
+ break;
+ }
+
+ [[fallthrough]];
+ }
+
+ // TODO other types
+
+ default:
+ mysqlc_sdbc_driver::throwInvalidArgumentException(
+ "OPreparedStatement::setObjectWithInfo", *this);
+ break;
+ }
+}
+
+void SAL_CALL OPreparedStatement::setObjectNull(sal_Int32 parameter, sal_Int32 /* sqlType */,
+ const OUString& /* typeName */)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(rBHelper.bDisposed);
+ checkParameterIndex(parameter);
+
+ mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedStatement::setObjectNull",
+ *this);
+}
+
+void SAL_CALL OPreparedStatement::setObject(sal_Int32 parameter, const Any& /* x */)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(rBHelper.bDisposed);
+ checkParameterIndex(parameter);
+
+ mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedStatement::setObject", *this);
+}
+
+void SAL_CALL OPreparedStatement::setShort(sal_Int32 parameter, sal_Int16 x)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(rBHelper.bDisposed);
+ checkParameterIndex(parameter);
+
+ const sal_Int32 nIndex = parameter - 1;
+ m_binds[nIndex].buffer_type = MYSQL_TYPE_SHORT;
+ mysqlc_sdbc_driver::resetSqlVar(&m_binds[nIndex].buffer, &x, MYSQL_TYPE_SHORT);
+ m_bindMetas[nIndex].is_null = false;
+}
+
+void SAL_CALL OPreparedStatement::setBytes(sal_Int32 parameter, const Sequence<sal_Int8>& x)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(rBHelper.bDisposed);
+ checkParameterIndex(parameter);
+
+ const sal_Int32 nIndex = parameter - 1;
+ m_binds[nIndex].buffer_type = MYSQL_TYPE_BLOB;
+ mysqlc_sdbc_driver::resetSqlVar(&m_binds[nIndex].buffer, &x[0], MYSQL_TYPE_BLOB, x.getLength());
+ m_bindMetas[nIndex].is_null = false;
+ m_bindMetas[nIndex].length = x.getLength();
+}
+
+void SAL_CALL OPreparedStatement::setCharacterStream(sal_Int32 parameter,
+ const Reference<XInputStream>& /* x */,
+ sal_Int32 /* length */)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(rBHelper.bDisposed);
+ checkParameterIndex(parameter);
+
+ mysqlc_sdbc_driver::throwFeatureNotImplementedException(
+ "OPreparedStatement::setCharacterStream", *this);
+}
+
+void SAL_CALL OPreparedStatement::setBinaryStream(sal_Int32 parameter,
+ const Reference<XInputStream>& /* x */,
+ sal_Int32 /* length */)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(rBHelper.bDisposed);
+ checkParameterIndex(parameter);
+
+ mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedStatement::setBinaryStream",
+ *this);
+}
+
+void SAL_CALL OPreparedStatement::clearParameters()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(rBHelper.bDisposed);
+
+ for (size_t i = 0; i < m_binds.size(); ++i)
+ {
+ m_bindMetas[i].is_null = true;
+ free(m_binds[i].buffer);
+ m_binds[i].buffer = nullptr;
+ }
+}
+
+// void SAL_CALL OPreparedStatement::clearBatch()
+// {
+// mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedStatement::clearBatch",
+// *this);
+// }
+
+// void SAL_CALL OPreparedStatement::addBatch()
+// {
+// mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedStatement::addBatch", *this);
+// }
+
+// Sequence<sal_Int32> SAL_CALL OPreparedStatement::executeBatch() {
+// mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedStatement::executeBatch", *this);
+// }
+
+void OPreparedStatement::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle, const Any& rValue)
+{
+ switch (nHandle)
+ {
+ case PROPERTY_ID_RESULTSETCONCURRENCY:
+ break;
+ case PROPERTY_ID_RESULTSETTYPE:
+ break;
+ case PROPERTY_ID_FETCHDIRECTION:
+ break;
+ case PROPERTY_ID_USEBOOKMARKS:
+ break;
+ default:
+ /* XXX: Recursion ?? */
+ OPreparedStatement::setFastPropertyValue_NoBroadcast(nHandle, rValue);
+ }
+}
+
+void OPreparedStatement::checkParameterIndex(sal_Int32 column)
+{
+ if (column < 1 || o3tl::make_unsigned(column) > m_paramCount)
+ {
+ throw SQLException("Parameter index out of range", *this, OUString(), 1, Any());
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/mysqlc/mysqlc_preparedstatement.hxx b/connectivity/source/drivers/mysqlc/mysqlc_preparedstatement.hxx
new file mode 100644
index 0000000000..e1743d91db
--- /dev/null
+++ b/connectivity/source/drivers/mysqlc/mysqlc_preparedstatement.hxx
@@ -0,0 +1,155 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+#include "mysqlc_statement.hxx"
+#include "mysqlc_resultset.hxx"
+
+#include <com/sun/star/sdbc/XPreparedStatement.hpp>
+#include <com/sun/star/sdbc/XParameters.hpp>
+#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
+#include <com/sun/star/sdbc/XPreparedBatchExecution.hpp>
+#include <com/sun/star/io/XInputStream.hpp>
+#include <cppuhelper/compbase4.hxx>
+
+namespace connectivity::mysqlc
+{
+using ::com::sun::star::sdbc::XResultSetMetaData;
+using ::com::sun::star::uno::Any;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::Type;
+
+#if defined MYSQL_VERSION_ID && (MYSQL_VERSION_ID >= 80000) && !defined MARIADB_BASE_VERSION
+using my_bool = bool;
+#else
+using my_bool = char;
+#endif
+
+struct BindMetaData
+{
+ my_bool is_null = false;
+ unsigned long length = 0;
+ my_bool error = false;
+};
+
+typedef ::cppu::ImplHelper4<css::sdbc::XPreparedStatement, css::sdbc::XParameters,
+ css::sdbc::XResultSetMetaDataSupplier, css::lang::XServiceInfo>
+ OPreparedStatement_BASE;
+
+class OPreparedStatement final : public OCommonStatement, public OPreparedStatement_BASE
+{
+ unsigned int m_paramCount = 0; // number of placeholders
+ Reference<XResultSetMetaData> m_xMetaData;
+ MYSQL_STMT* m_pStmt;
+ std::vector<MYSQL_BIND> m_binds;
+ std::vector<BindMetaData> m_bindMetas;
+
+ void checkParameterIndex(sal_Int32 parameter);
+
+ void SAL_CALL setFastPropertyValue_NoBroadcast(sal_Int32 nHandle, const Any& rValue) override;
+ virtual ~OPreparedStatement() override;
+
+public:
+ virtual OUString SAL_CALL getImplementationName() override;
+
+ virtual sal_Bool SAL_CALL supportsService(OUString const& ServiceName) override;
+
+ virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override;
+
+ OPreparedStatement(OConnection* _pConnection, MYSQL_STMT* pStmt);
+
+ //XInterface
+ Any SAL_CALL queryInterface(const Type& rType) override;
+ void SAL_CALL acquire() noexcept override;
+ void SAL_CALL release() noexcept override;
+
+ //XTypeProvider
+ css::uno::Sequence<Type> SAL_CALL getTypes() override;
+
+ // XPreparedStatement
+ Reference<css::sdbc::XResultSet> SAL_CALL executeQuery() override;
+ sal_Int32 SAL_CALL executeUpdate() override;
+ sal_Bool SAL_CALL execute() override;
+ Reference<css::sdbc::XConnection> SAL_CALL getConnection() override;
+
+ // XParameters
+ void SAL_CALL setNull(sal_Int32 parameter, sal_Int32 sqlType) override;
+
+ void SAL_CALL setObjectNull(sal_Int32 parameter, sal_Int32 sqlType,
+ const OUString& typeName) override;
+
+ void SAL_CALL setBoolean(sal_Int32 parameter, sal_Bool x) override;
+
+ void SAL_CALL setByte(sal_Int32 parameter, sal_Int8 x) override;
+
+ void SAL_CALL setShort(sal_Int32 parameter, sal_Int16 x) override;
+
+ void SAL_CALL setInt(sal_Int32 parameter, sal_Int32 x) override;
+
+ void SAL_CALL setLong(sal_Int32 parameter, sal_Int64 x) override;
+
+ void SAL_CALL setFloat(sal_Int32 parameter, float x) override;
+
+ void SAL_CALL setDouble(sal_Int32 parameter, double x) override;
+
+ void SAL_CALL setString(sal_Int32 parameter, const OUString& x) override;
+
+ void SAL_CALL setBytes(sal_Int32 parameter, const css::uno::Sequence<sal_Int8>& x) override;
+
+ void SAL_CALL setDate(sal_Int32 parameter, const css::util::Date& x) override;
+
+ void SAL_CALL setTime(sal_Int32 parameter, const css::util::Time& x) override;
+ void SAL_CALL setTimestamp(sal_Int32 parameter, const css::util::DateTime& x) override;
+
+ void SAL_CALL setBinaryStream(sal_Int32 parameter, const Reference<css::io::XInputStream>& x,
+ sal_Int32 length) override;
+
+ void SAL_CALL setCharacterStream(sal_Int32 parameter, const Reference<css::io::XInputStream>& x,
+ sal_Int32 length) override;
+
+ void SAL_CALL setObject(sal_Int32 parameter, const Any& x) override;
+
+ void SAL_CALL setObjectWithInfo(sal_Int32 parameter, const Any& x, sal_Int32 targetSqlType,
+ sal_Int32 scale) override;
+
+ void SAL_CALL setRef(sal_Int32 parameter, const Reference<css::sdbc::XRef>& x) override;
+
+ void SAL_CALL setBlob(sal_Int32 parameter, const Reference<css::sdbc::XBlob>& x) override;
+
+ void SAL_CALL setClob(sal_Int32 parameter, const Reference<css::sdbc::XClob>& x) override;
+
+ void SAL_CALL setArray(sal_Int32 parameter, const Reference<css::sdbc::XArray>& x) override;
+
+ void SAL_CALL clearParameters() override;
+
+ // XPreparedBatchExecution
+ // void SAL_CALL addBatch() override;
+ // void SAL_CALL clearBatch() override;
+ // css::uno::Sequence<sal_Int32> SAL_CALL executeBatch() override;
+
+ // XCloseable
+ void SAL_CALL close() override;
+
+ // XResultSetMetaDataSupplier
+ Reference<css::sdbc::XResultSetMetaData> SAL_CALL getMetaData() override;
+};
+
+} /* connectivity::mysqlc */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/mysqlc/mysqlc_propertyids.hxx b/connectivity/source/drivers/mysqlc/mysqlc_propertyids.hxx
new file mode 100644
index 0000000000..113b28a2fe
--- /dev/null
+++ b/connectivity/source/drivers/mysqlc/mysqlc_propertyids.hxx
@@ -0,0 +1,44 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+// this define has to be set to split the names into different dll's or so's
+// every dll has his own set of property names
+
+namespace connectivity::mysqlc
+{
+enum
+{
+ PROPERTY_ID_QUERYTIMEOUT = 1,
+ PROPERTY_ID_MAXFIELDSIZE,
+ PROPERTY_ID_MAXROWS,
+ PROPERTY_ID_CURSORNAME,
+ PROPERTY_ID_RESULTSETCONCURRENCY,
+ PROPERTY_ID_RESULTSETTYPE,
+ PROPERTY_ID_FETCHDIRECTION,
+ PROPERTY_ID_FETCHSIZE,
+ PROPERTY_ID_ESCAPEPROCESSING,
+ PROPERTY_ID_USEBOOKMARKS,
+ PROPERTY_ID_ISBOOKMARKABLE
+};
+
+} /* connectivity::mysqlc */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/mysqlc/mysqlc_resultset.cxx b/connectivity/source/drivers/mysqlc/mysqlc_resultset.cxx
new file mode 100644
index 0000000000..5fc0fc9a7d
--- /dev/null
+++ b/connectivity/source/drivers/mysqlc/mysqlc_resultset.cxx
@@ -0,0 +1,1111 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "mysqlc_propertyids.hxx"
+#include "mysqlc_general.hxx"
+#include "mysqlc_resultset.hxx"
+#include "mysqlc_resultsetmetadata.hxx"
+
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/sdbc/ResultSetConcurrency.hpp>
+#include <com/sun/star/sdbc/ResultSetType.hpp>
+#include <com/sun/star/sdbc/FetchDirection.hpp>
+#include <com/sun/star/sdbcx/CompareBookmark.hpp>
+#include <cppuhelper/supportsservice.hxx>
+#include <cppuhelper/typeprovider.hxx>
+#include <comphelper/seqstream.hxx>
+#include <o3tl/safeint.hxx>
+#include <o3tl/string_view.hxx>
+
+using namespace rtl;
+
+using namespace connectivity::mysqlc;
+using namespace cppu;
+using namespace com::sun::star;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::sdbc;
+using namespace com::sun::star::sdbcx;
+using namespace com::sun::star::container;
+using namespace com::sun::star::io;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::util;
+using namespace ::comphelper;
+using ::osl::MutexGuard;
+
+namespace
+{
+// copied from string misc, it should be replaced when library is not an
+// extension anymore
+std::vector<OString> lcl_split(std::string_view rStr, char cSeparator)
+{
+ std::vector<OString> vec;
+ sal_Int32 idx = 0;
+ do
+ {
+ OString kw(o3tl::trim(o3tl::getToken(rStr, 0, cSeparator, idx)));
+ if (!kw.isEmpty())
+ {
+ vec.push_back(kw);
+ }
+ } while (idx >= 0);
+ return vec;
+}
+}
+
+void OResultSet::checkRowIndex()
+{
+ if (m_nRowPosition < 0 || m_nRowPosition >= m_nRowCount)
+ {
+ throw SQLException("Cursor position out of range", *this, OUString(), 1, Any());
+ }
+}
+
+bool OResultSet::checkNull(sal_Int32 column)
+{
+ if (m_aRows[m_nRowPosition][column - 1].isEmpty())
+ {
+ m_bWasNull = true;
+ return true;
+ }
+ m_bWasNull = false;
+ return false;
+}
+
+OUString SAL_CALL OResultSet::getImplementationName()
+{
+ return "com.sun.star.sdbcx.mysqlc.ResultSet";
+}
+
+uno::Sequence<OUString> SAL_CALL OResultSet::getSupportedServiceNames()
+{
+ return { "com.sun.star.sdbc.ResultSet", "com.sun.star.sdbcx.ResultSet" };
+}
+
+sal_Bool SAL_CALL OResultSet::supportsService(const OUString& _rServiceName)
+{
+ return cppu::supportsService(this, _rServiceName);
+}
+
+OResultSet::OResultSet(OConnection& rConn, OCommonStatement* pStmt, MYSQL_RES* pResult,
+ rtl_TextEncoding _encoding)
+ : OResultSet_BASE(m_aMutex)
+ , OPropertySetHelper(OResultSet_BASE::rBHelper)
+ , m_pMysql(rConn.getMysqlConnection())
+ , m_aStatement(css::uno::Reference(cppu::getXWeak(pStmt)))
+ , m_pResult(pResult)
+ , m_encoding(_encoding)
+{
+ assert(m_pResult);
+ m_xMetaData = new OResultSetMetaData(rConn, m_pResult);
+}
+
+void OResultSet::ensureResultFetched()
+{
+ if (m_pResult)
+ {
+ fetchResult();
+ }
+}
+
+void OResultSet::ensureFieldInfoFetched()
+{
+ if (m_pResult == nullptr)
+ return; // already fetched
+
+ // it works only if result set is produced via mysql_store_result
+ // TODO ensure that
+ m_nRowCount = mysql_num_rows(m_pResult);
+
+ if (!m_aFields.empty())
+ return;
+ unsigned nFieldCount = mysql_num_fields(m_pResult);
+ MYSQL_FIELD* pFields = mysql_fetch_fields(m_pResult);
+ m_aFields.reserve(nFieldCount);
+ for (unsigned i = 0; i < nFieldCount; ++i)
+ m_aFields.push_back(OUString{
+ pFields[i].name, static_cast<sal_Int32>(strlen(pFields[i].name)), m_encoding });
+}
+
+void OResultSet::fetchResult()
+{
+ // Mysql C API does not allow simultaneously opened result sets, but sdbc does.
+ // Because of that we need to fetch all of the data ASAP
+ ensureFieldInfoFetched();
+
+ // fetch all the data
+ m_aRows.reserve(m_nRowCount);
+
+ for (sal_Int32 row = 0; row < m_nRowCount; ++row)
+ {
+ MYSQL_ROW data = mysql_fetch_row(m_pResult);
+ unsigned long* lengths = mysql_fetch_lengths(m_pResult);
+ m_aRows.push_back(DataFields{});
+ // MYSQL_ROW is char**, array of strings
+ for (std::size_t col = 0; col < m_aFields.size(); ++col)
+ {
+ m_aRows.back().push_back(OString{ data[col], static_cast<sal_Int32>(lengths[col]) });
+ }
+ }
+ unsigned errorNum = mysql_errno(m_pMysql);
+ if (errorNum)
+ mysqlc_sdbc_driver::throwSQLExceptionWithMsg(
+ mysql_error(m_pMysql), mysql_sqlstate(m_pMysql), errorNum, *this, m_encoding);
+ mysql_free_result(m_pResult);
+ m_pResult = nullptr;
+}
+
+void OResultSet::disposing()
+{
+ OPropertySetHelper::disposing();
+
+ MutexGuard aGuard(m_aMutex);
+
+ if (m_pResult != nullptr)
+ {
+ mysql_free_result(m_pResult);
+ m_pResult = nullptr;
+ }
+ m_aStatement.clear();
+ m_xMetaData = nullptr;
+}
+
+Any SAL_CALL OResultSet::queryInterface(const Type& rType)
+{
+ Any aRet = OPropertySetHelper::queryInterface(rType);
+ if (!aRet.hasValue())
+ {
+ aRet = OResultSet_BASE::queryInterface(rType);
+ }
+ return aRet;
+}
+
+uno::Sequence<Type> SAL_CALL OResultSet::getTypes()
+{
+ OTypeCollection aTypes(cppu::UnoType<XMultiPropertySet>::get(),
+ cppu::UnoType<XFastPropertySet>::get(),
+ cppu::UnoType<XPropertySet>::get());
+
+ return concatSequences(aTypes.getTypes(), OResultSet_BASE::getTypes());
+}
+
+sal_Int32 SAL_CALL OResultSet::findColumn(const OUString& columnName)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+ ensureFieldInfoFetched();
+
+ for (std::size_t i = 0; i < m_aFields.size(); ++i)
+ {
+ if (columnName.equalsIgnoreAsciiCase(m_aFields[i]))
+ return static_cast<sal_Int32>(i) + 1; // sdbc indexes from 1
+ }
+
+ throw SQLException("The column name '" + columnName + "' is not valid.", *this, "42S22", 0,
+ Any());
+}
+
+uno::Reference<XInputStream> SAL_CALL OResultSet::getBinaryStream(sal_Int32 column)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+ checkBordersAndEnsureFetched(column);
+ if (checkNull(column))
+ return nullptr;
+
+ OString sVal = m_aRows[m_nRowPosition][column - 1];
+ return new SequenceInputStream{ uno::Sequence<sal_Int8>(
+ reinterpret_cast<sal_Int8 const*>(sVal.getStr()), getDataLength(column)) };
+}
+
+uno::Reference<XInputStream> SAL_CALL OResultSet::getCharacterStream(sal_Int32 column)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+ checkBordersAndEnsureFetched(column);
+ mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::getCharacterStream",
+ *this);
+ return nullptr;
+}
+
+sal_Bool SAL_CALL OResultSet::getBoolean(sal_Int32 column)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+ checkBordersAndEnsureFetched(column);
+ if (checkNull(column))
+ return false;
+
+ OString sVal = m_aRows[m_nRowPosition][column - 1];
+ return sVal.toInt32() != 0;
+}
+
+sal_Int8 SAL_CALL OResultSet::getByte(sal_Int32 column)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+ checkBordersAndEnsureFetched(column);
+ if (checkNull(column))
+ return 0;
+
+ OString sVal = m_aRows[m_nRowPosition][column - 1];
+
+ return static_cast<sal_Int8>(sVal.toInt32());
+}
+
+uno::Sequence<sal_Int8> SAL_CALL OResultSet::getBytes(sal_Int32 column)
+{
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+ MutexGuard aGuard(m_aMutex);
+ checkBordersAndEnsureFetched(column);
+ OString sVal = m_aRows[m_nRowPosition][column - 1];
+ if (checkNull(column))
+ return uno::Sequence<sal_Int8>();
+
+ return uno::Sequence<sal_Int8>(reinterpret_cast<sal_Int8 const*>(sVal.getStr()),
+ getDataLength(column));
+}
+
+Date SAL_CALL OResultSet::getDate(sal_Int32 column)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+ checkBordersAndEnsureFetched(column);
+
+ Date d;
+
+ if (checkNull(column))
+ return d;
+
+ const OString& dateStr = m_aRows[m_nRowPosition][column - 1];
+
+ std::string_view dateString(dateStr);
+ sal_Int32 nIndex = 0, i = 0;
+ do
+ {
+ std::string_view token = o3tl::getToken(dateString, 0, '-', nIndex);
+ switch (i)
+ {
+ case 0:
+ d.Year = static_cast<sal_uInt16>(o3tl::toUInt32(token));
+ break;
+ case 1:
+ d.Month = static_cast<sal_uInt16>(o3tl::toUInt32(token));
+ break;
+ case 2:
+ d.Day = static_cast<sal_uInt16>(o3tl::toUInt32(token));
+ break;
+ default:;
+ }
+ i++;
+ } while (nIndex >= 0);
+ return d;
+}
+
+double SAL_CALL OResultSet::getDouble(sal_Int32 column)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+ checkBordersAndEnsureFetched(column);
+
+ if (checkNull(column))
+ return 0.0;
+
+ OString sVal = m_aRows[m_nRowPosition][column - 1];
+ return sVal.toDouble();
+}
+
+float SAL_CALL OResultSet::getFloat(sal_Int32 column)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+ checkBordersAndEnsureFetched(column);
+ if (checkNull(column))
+ return 0.0f;
+
+ OString sVal = m_aRows[m_nRowPosition][column - 1];
+ return sVal.toFloat();
+}
+
+sal_Int32 SAL_CALL OResultSet::getInt(sal_Int32 column)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+ checkBordersAndEnsureFetched(column);
+ if (checkNull(column))
+ return 0;
+
+ OString sVal = m_aRows[m_nRowPosition][column - 1];
+ return sVal.toInt32();
+}
+
+sal_Int32 SAL_CALL OResultSet::getRow()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ return m_nRowPosition + 1; // indexed from 1
+}
+
+sal_Int64 SAL_CALL OResultSet::getLong(sal_Int32 column)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+ checkBordersAndEnsureFetched(column);
+ if (checkNull(column))
+ return 0LL;
+
+ OString sVal = m_aRows[m_nRowPosition][column - 1];
+ return sVal.toInt64();
+}
+
+uno::Reference<XResultSetMetaData> SAL_CALL OResultSet::getMetaData()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+ return m_xMetaData;
+}
+
+uno::Reference<XArray> SAL_CALL OResultSet::getArray(sal_Int32 column)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+ checkBordersAndEnsureFetched(column);
+
+ mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::getArray", *this);
+ return nullptr;
+}
+
+uno::Reference<XClob> SAL_CALL OResultSet::getClob(sal_Int32 column)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+ checkBordersAndEnsureFetched(column);
+
+ mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::getClob", *this);
+ return nullptr;
+}
+
+uno::Reference<XBlob> SAL_CALL OResultSet::getBlob(sal_Int32 column)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+ checkBordersAndEnsureFetched(column);
+
+ mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::getBlob", *this);
+ return nullptr;
+}
+
+uno::Reference<XRef> SAL_CALL OResultSet::getRef(sal_Int32 column)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+ checkBordersAndEnsureFetched(column);
+
+ mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::getRef", *this);
+ return nullptr;
+}
+
+Any SAL_CALL OResultSet::getObject(sal_Int32 column,
+ const uno::Reference<XNameAccess>& /* typeMap */)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+ checkBordersAndEnsureFetched(column);
+
+ mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::getObject", *this);
+ return Any();
+}
+
+sal_Int16 SAL_CALL OResultSet::getShort(sal_Int32 column)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+ checkBordersAndEnsureFetched(column);
+ if (checkNull(column))
+ return 0;
+
+ OString sVal = m_aRows[m_nRowPosition][column - 1];
+ return sVal.toInt32();
+}
+
+OUString SAL_CALL OResultSet::getString(sal_Int32 column)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+ checkBordersAndEnsureFetched(column);
+ if (checkNull(column))
+ return rtl::OUString{};
+
+ OString sVal = m_aRows[m_nRowPosition][column - 1];
+ return OStringToOUString(sVal, m_encoding);
+}
+
+Time SAL_CALL OResultSet::getTime(sal_Int32 column)
+{
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+ MutexGuard aGuard(m_aMutex);
+ checkBordersAndEnsureFetched(column);
+
+ Time t;
+ if (checkNull(column))
+ return t;
+
+ const OString& sVal = m_aRows[m_nRowPosition][column - 1];
+ std::string_view timeString{ sVal.getStr(), o3tl::make_unsigned(getDataLength(column)) };
+ sal_Int32 nIndex, i = 0;
+
+ size_t idx = timeString.find(' ');
+ if (idx == std::string_view::npos)
+ nIndex = 0;
+ else
+ nIndex = idx + 1;
+ do
+ {
+ std::string_view token = o3tl::getToken(timeString, 0, ':', nIndex);
+ switch (i)
+ {
+ case 0:
+ t.Hours = static_cast<sal_uInt16>(o3tl::toUInt32(token));
+ break;
+ case 1:
+ t.Minutes = static_cast<sal_uInt16>(o3tl::toUInt32(token));
+ break;
+ case 2:
+ t.Seconds = static_cast<sal_uInt16>(o3tl::toUInt32(token));
+ break;
+ }
+ i++;
+ } while (nIndex >= 0);
+
+ return t;
+}
+
+DateTime SAL_CALL OResultSet::getTimestamp(sal_Int32 column)
+{
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+ MutexGuard aGuard(m_aMutex);
+ checkBordersAndEnsureFetched(column);
+
+ if (checkNull(column))
+ return DateTime{};
+
+ OString sVal = m_aRows[m_nRowPosition][column - 1];
+
+ // YY-MM-DD HH:MM:SS
+ std::vector<OString> dateAndTime = lcl_split(sVal.subView(0, getDataLength(column)), ' ');
+
+ auto dateParts = lcl_split(dateAndTime.at(0), '-');
+ auto timeParts = lcl_split(dateAndTime.at(1), ':');
+
+ if (dateParts.size() < 2 || timeParts.size() < 2)
+ throw SQLException("Timestamp has a wrong format", *this, OUString(), 1, Any());
+
+ DateTime dt;
+
+ dt.Year = dateParts.at(0).toUInt32();
+ dt.Month = dateParts.at(1).toUInt32();
+ dt.Day = dateParts.at(2).toUInt32();
+ dt.Hours = timeParts.at(0).toUInt32();
+ dt.Minutes = timeParts.at(1).toUInt32();
+ dt.Seconds = timeParts.at(2).toUInt32();
+ return dt;
+}
+
+sal_Bool SAL_CALL OResultSet::isBeforeFirst()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ return m_nRowPosition < 0;
+}
+
+sal_Bool SAL_CALL OResultSet::isAfterLast()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+ ensureFieldInfoFetched();
+
+ return m_nRowPosition >= m_nRowCount;
+}
+
+sal_Bool SAL_CALL OResultSet::isFirst()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+ ensureFieldInfoFetched();
+
+ return m_nRowPosition == 0 && !isAfterLast();
+}
+
+sal_Bool SAL_CALL OResultSet::isLast()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+ ensureFieldInfoFetched();
+
+ return m_nRowPosition == m_nRowCount - 1;
+}
+
+void SAL_CALL OResultSet::beforeFirst()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+ m_nRowPosition = -1;
+}
+
+void SAL_CALL OResultSet::afterLast()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+ ensureFieldInfoFetched();
+ m_nRowPosition = m_nRowCount;
+}
+
+void SAL_CALL OResultSet::close()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ if (m_pResult != nullptr)
+ {
+ mysql_free_result(m_pResult);
+ m_pResult = nullptr;
+ }
+ dispose();
+}
+
+sal_Bool SAL_CALL OResultSet::first()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+ m_nRowPosition = 0;
+
+ return true;
+}
+
+sal_Bool SAL_CALL OResultSet::last()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+ ensureFieldInfoFetched();
+ m_nRowPosition = m_nRowCount - 1;
+
+ return true;
+}
+
+sal_Bool SAL_CALL OResultSet::absolute(sal_Int32 row)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+ ensureFieldInfoFetched();
+
+ sal_Int32 nToGo = row < 0 ? (m_nRowCount - 1) - row : row - 1;
+
+ if (nToGo >= m_nRowCount)
+ nToGo = m_nRowCount - 1;
+ if (nToGo < 0)
+ nToGo = 0;
+
+ m_nRowPosition = nToGo;
+
+ return true;
+}
+
+sal_Bool SAL_CALL OResultSet::relative(sal_Int32 row)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+ ensureFieldInfoFetched();
+
+ if (row == 0)
+ return true;
+
+ sal_Int32 nToGo = m_nRowPosition + row;
+ if (nToGo >= m_nRowCount)
+ nToGo = m_nRowCount - 1;
+ if (nToGo < 0)
+ nToGo = 0;
+
+ m_nRowPosition = nToGo;
+
+ return true;
+}
+
+sal_Bool SAL_CALL OResultSet::previous()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ if (m_nRowPosition == 0)
+ {
+ m_nRowPosition--;
+ return false;
+ }
+ else if (m_nRowPosition < 0)
+ {
+ return false;
+ }
+
+ m_nRowPosition--;
+ return true;
+}
+
+uno::Reference<uno::XInterface> SAL_CALL OResultSet::getStatement()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ return m_aStatement.get();
+}
+
+sal_Bool SAL_CALL OResultSet::rowDeleted()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ return false;
+}
+
+sal_Bool SAL_CALL OResultSet::rowInserted()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ return false;
+}
+
+sal_Bool SAL_CALL OResultSet::rowUpdated()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ return false;
+}
+
+sal_Bool SAL_CALL OResultSet::next()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+ ensureFieldInfoFetched();
+ if (m_nRowPosition + 1 > m_nRowCount) // afterlast
+ return false;
+ if (m_nRowPosition + 1 == m_nRowCount) // last
+ {
+ // return false but take it to afterlast anyway
+ ++m_nRowPosition;
+ return false;
+ }
+ ++m_nRowPosition;
+ return true;
+}
+
+sal_Bool SAL_CALL OResultSet::wasNull()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ return m_bWasNull;
+}
+
+void SAL_CALL OResultSet::cancel()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+}
+
+void SAL_CALL OResultSet::clearWarnings() {}
+
+Any SAL_CALL OResultSet::getWarnings() { return Any(); }
+
+void SAL_CALL OResultSet::insertRow()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+ // you only have to implement this if you want to insert new rows
+ mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::insertRow", *this);
+}
+
+void SAL_CALL OResultSet::updateRow()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ // only when you allow updates
+ mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::updateRow", *this);
+}
+
+void SAL_CALL OResultSet::deleteRow()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+ mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::deleteRow", *this);
+}
+
+void SAL_CALL OResultSet::cancelRowUpdates()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+ mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::cancelRowUpdates", *this);
+}
+
+void SAL_CALL OResultSet::moveToInsertRow()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ // only when you allow insert's
+ mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::moveToInsertRow", *this);
+}
+
+void SAL_CALL OResultSet::moveToCurrentRow()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+}
+
+void SAL_CALL OResultSet::updateNull(sal_Int32 column)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+ checkColumnIndex(column);
+ checkRowIndex();
+ mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::updateNull", *this);
+}
+
+void SAL_CALL OResultSet::updateBoolean(sal_Int32 column, sal_Bool /* x */)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+ checkColumnIndex(column);
+ checkRowIndex();
+ mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::updateBoolean", *this);
+}
+
+void SAL_CALL OResultSet::updateByte(sal_Int32 column, sal_Int8 /* x */)
+{
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+ MutexGuard aGuard(m_aMutex);
+ checkColumnIndex(column);
+ checkRowIndex();
+ mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::updateByte", *this);
+}
+
+void SAL_CALL OResultSet::updateShort(sal_Int32 column, sal_Int16 /* x */)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+ checkColumnIndex(column);
+ checkRowIndex();
+ mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::updateShort", *this);
+}
+
+void SAL_CALL OResultSet::updateInt(sal_Int32 column, sal_Int32 /* x */)
+{
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+ MutexGuard aGuard(m_aMutex);
+ checkColumnIndex(column);
+ checkRowIndex();
+ mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::updateInt", *this);
+}
+
+void SAL_CALL OResultSet::updateLong(sal_Int32 column, sal_Int64 /* x */)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+ checkColumnIndex(column);
+ checkRowIndex();
+ mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::updateLong", *this);
+}
+
+void SAL_CALL OResultSet::updateFloat(sal_Int32 column, float /* x */)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+ checkColumnIndex(column);
+ checkRowIndex();
+ mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::updateFloat", *this);
+}
+
+void SAL_CALL OResultSet::updateDouble(sal_Int32 column, double /* x */)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+ checkColumnIndex(column);
+ checkRowIndex();
+ mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::updateDouble", *this);
+}
+
+void SAL_CALL OResultSet::updateString(sal_Int32 column, const OUString& /* x */)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+ checkColumnIndex(column);
+ checkRowIndex();
+ mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::updateString", *this);
+}
+
+void SAL_CALL OResultSet::updateBytes(sal_Int32 column, const uno::Sequence<sal_Int8>& /* x */)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+ checkColumnIndex(column);
+ checkRowIndex();
+ mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::updateBytes", *this);
+}
+
+void SAL_CALL OResultSet::updateDate(sal_Int32 column, const Date& /* x */)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+ checkColumnIndex(column);
+ checkRowIndex();
+ mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::updateDate", *this);
+}
+
+void SAL_CALL OResultSet::updateTime(sal_Int32 column, const Time& /* x */)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+ checkColumnIndex(column);
+ checkRowIndex();
+ mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::updateTime", *this);
+}
+
+void SAL_CALL OResultSet::updateTimestamp(sal_Int32 column, const DateTime& /* x */)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+ checkColumnIndex(column);
+ checkRowIndex();
+ mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::updateTimestamp", *this);
+}
+
+void SAL_CALL OResultSet::updateBinaryStream(sal_Int32 column,
+ const uno::Reference<XInputStream>& /* x */,
+ sal_Int32 /* length */)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+ checkColumnIndex(column);
+ checkRowIndex();
+ mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::updateBinaryStream",
+ *this);
+}
+
+void SAL_CALL OResultSet::updateCharacterStream(sal_Int32 column,
+ const uno::Reference<XInputStream>& /* x */,
+ sal_Int32 /* length */)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+ checkColumnIndex(column);
+ checkRowIndex();
+ mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::updateCharacterStream",
+ *this);
+}
+
+void SAL_CALL OResultSet::refreshRow()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+ mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::refreshRow", *this);
+}
+
+void SAL_CALL OResultSet::updateObject(sal_Int32 column, const Any& /* x */)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+ checkColumnIndex(column);
+ checkRowIndex();
+ mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::updateObject", *this);
+}
+
+void SAL_CALL OResultSet::updateNumericObject(sal_Int32 column, const Any& /* x */,
+ sal_Int32 /* scale */)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+ checkColumnIndex(column);
+ checkRowIndex();
+ mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::updateNumericObject",
+ *this);
+}
+
+// XRowLocate
+Any SAL_CALL OResultSet::getBookmark()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ // if you don't want to support bookmark you must remove the XRowLocate interface
+ mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::getBookmark", *this);
+
+ return Any();
+}
+
+sal_Bool SAL_CALL OResultSet::moveToBookmark(const Any& /* bookmark */)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ return false;
+}
+
+sal_Bool SAL_CALL OResultSet::moveRelativeToBookmark(const Any& /* bookmark */,
+ sal_Int32 /* rows */)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::moveRelativeToBookmark",
+ *this);
+ return false;
+}
+
+sal_Int32 SAL_CALL OResultSet::compareBookmarks(const Any& /* n1 */, const Any& /* n2 */)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::compareBookmarks", *this);
+
+ return CompareBookmark::NOT_EQUAL;
+}
+
+sal_Bool SAL_CALL OResultSet::hasOrderedBookmarks() { return false; }
+
+sal_Int32 SAL_CALL OResultSet::hashBookmark(const Any& /* bookmark */)
+{
+ mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::hashBookmark", *this);
+ return 0;
+}
+
+// XDeleteRows
+uno::Sequence<sal_Int32> SAL_CALL OResultSet::deleteRows(const uno::Sequence<Any>& /* rows */)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::deleteRows", *this);
+ return uno::Sequence<sal_Int32>();
+}
+
+IPropertyArrayHelper* OResultSet::createArrayHelper() const
+{
+ return new OPropertyArrayHelper{
+ { { "FetchDirection", PROPERTY_ID_FETCHDIRECTION, cppu::UnoType<sal_Int32>::get(), 0 },
+ { "FetchSize", PROPERTY_ID_FETCHSIZE, cppu::UnoType<sal_Int32>::get(), 0 },
+ { "IsBookmarkable", PROPERTY_ID_ISBOOKMARKABLE, cppu::UnoType<bool>::get(),
+ PropertyAttribute::READONLY },
+ { "ResultSetConcurrency", PROPERTY_ID_RESULTSETCONCURRENCY,
+ cppu::UnoType<sal_Int32>::get(), PropertyAttribute::READONLY },
+ { "ResultSetType", PROPERTY_ID_RESULTSETTYPE, cppu::UnoType<sal_Int32>::get(),
+ PropertyAttribute::READONLY } }
+ };
+}
+
+IPropertyArrayHelper& OResultSet::getInfoHelper() { return *getArrayHelper(); }
+
+sal_Bool OResultSet::convertFastPropertyValue(Any& /* rConvertedValue */, Any& /* rOldValue */,
+ sal_Int32 nHandle, const Any& /* rValue */)
+{
+ switch (nHandle)
+ {
+ case PROPERTY_ID_ISBOOKMARKABLE:
+ case PROPERTY_ID_CURSORNAME:
+ case PROPERTY_ID_RESULTSETCONCURRENCY:
+ case PROPERTY_ID_RESULTSETTYPE:
+ throw css::lang::IllegalArgumentException();
+ case PROPERTY_ID_FETCHDIRECTION:
+ case PROPERTY_ID_FETCHSIZE:
+ default:;
+ }
+ return false;
+}
+
+void OResultSet::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle, const Any& /* rValue */)
+{
+ switch (nHandle)
+ {
+ case PROPERTY_ID_ISBOOKMARKABLE:
+ case PROPERTY_ID_CURSORNAME:
+ case PROPERTY_ID_RESULTSETCONCURRENCY:
+ case PROPERTY_ID_RESULTSETTYPE:
+ throw uno::Exception("cannot set prop " + OUString::number(nHandle), nullptr);
+ case PROPERTY_ID_FETCHDIRECTION:
+ break;
+ case PROPERTY_ID_FETCHSIZE:
+ break;
+ default:;
+ }
+}
+
+void OResultSet::getFastPropertyValue(Any& _rValue, sal_Int32 nHandle) const
+{
+ switch (nHandle)
+ {
+ case PROPERTY_ID_ISBOOKMARKABLE:
+ _rValue <<= false;
+ break;
+ case PROPERTY_ID_CURSORNAME:
+ break;
+ case PROPERTY_ID_RESULTSETCONCURRENCY:
+ _rValue <<= ResultSetConcurrency::READ_ONLY;
+ break;
+ case PROPERTY_ID_RESULTSETTYPE:
+ _rValue <<= ResultSetType::SCROLL_INSENSITIVE;
+ break;
+ case PROPERTY_ID_FETCHDIRECTION:
+ _rValue <<= FetchDirection::FORWARD;
+ break;
+ case PROPERTY_ID_FETCHSIZE:
+ _rValue <<= sal_Int32(50);
+ break;
+ ;
+ default:;
+ }
+}
+
+void SAL_CALL OResultSet::acquire() noexcept { OResultSet_BASE::acquire(); }
+
+void SAL_CALL OResultSet::release() noexcept { OResultSet_BASE::release(); }
+
+css::uno::Reference<css::beans::XPropertySetInfo> SAL_CALL OResultSet::getPropertySetInfo()
+{
+ return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper());
+}
+
+void OResultSet::checkColumnIndex(sal_Int32 index)
+{
+ if (index < 1 || o3tl::make_unsigned(index) > m_aFields.size())
+ {
+ /* static object for efficiency or thread safety is a problem ? */
+ throw SQLException("index out of range", *this, OUString(), 1, Any());
+ }
+}
+
+void OResultSet::checkBordersAndEnsureFetched(sal_Int32 index)
+{
+ ensureResultFetched();
+ checkColumnIndex(index);
+ checkRowIndex();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/mysqlc/mysqlc_resultset.hxx b/connectivity/source/drivers/mysqlc/mysqlc_resultset.hxx
new file mode 100644
index 0000000000..3e43853d36
--- /dev/null
+++ b/connectivity/source/drivers/mysqlc/mysqlc_resultset.hxx
@@ -0,0 +1,273 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "mysqlc_preparedstatement.hxx"
+#include "mysqlc_statement.hxx"
+#include "mysqlc_subcomponent.hxx"
+#include "mysqlc_connection.hxx"
+
+#include <com/sun/star/sdbc/XCloseable.hpp>
+#include <com/sun/star/sdbc/XColumnLocate.hpp>
+#include <com/sun/star/sdbc/XResultSet.hpp>
+#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
+#include <com/sun/star/sdbc/XResultSetUpdate.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XRowUpdate.hpp>
+#include <com/sun/star/sdbc/XWarningsSupplier.hpp>
+#include <com/sun/star/sdbcx/XDeleteRows.hpp>
+#include <com/sun/star/sdbcx/XRowLocate.hpp>
+#include <com/sun/star/util/XCancellable.hpp>
+
+#include <cppuhelper/compbase12.hxx>
+
+namespace connectivity::mysqlc
+{
+using ::com::sun::star::uno::Any;
+
+/*
+ ** OResultSet
+ */
+typedef ::cppu::WeakComponentImplHelper12<
+ css::sdbc::XResultSet, css::sdbc::XRow, css::sdbc::XResultSetMetaDataSupplier,
+ css::util::XCancellable, css::sdbc::XWarningsSupplier, css::sdbc::XResultSetUpdate,
+ css::sdbc::XRowUpdate, css::sdbcx::XRowLocate, css::sdbcx::XDeleteRows, css::sdbc::XCloseable,
+ css::sdbc::XColumnLocate, css::lang::XServiceInfo>
+ OResultSet_BASE;
+
+class OResultSet final : public cppu::BaseMutex,
+ public OResultSet_BASE,
+ public ::cppu::OPropertySetHelper,
+ public OPropertyArrayUsageHelper<OResultSet>
+{
+ using DataFields = std::vector<OString>;
+ std::vector<DataFields> m_aRows;
+ std::vector<OUString> m_aFields;
+ MYSQL* m_pMysql = nullptr;
+ css::uno::WeakReferenceHelper m_aStatement;
+ css::uno::Reference<css::sdbc::XResultSetMetaData> m_xMetaData;
+ MYSQL_RES* m_pResult;
+ rtl_TextEncoding m_encoding;
+ bool m_bWasNull = false; // did the last getXXX result null?
+
+ sal_Int32 getDataLength(sal_Int32 column)
+ {
+ return m_aRows[m_nRowPosition][column - 1].getLength();
+ }
+ bool checkNull(sal_Int32 column);
+
+ /**
+ * Position of cursor indexed from 0
+ */
+ sal_Int32 m_nRowPosition = -1;
+ sal_Int32 m_nRowCount = 0;
+
+ // OPropertyArrayUsageHelper
+ ::cppu::IPropertyArrayHelper* createArrayHelper() const override;
+ // OPropertySetHelper
+ ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override;
+
+ sal_Bool SAL_CALL convertFastPropertyValue(Any& rConvertedValue, Any& rOldValue,
+ sal_Int32 nHandle, const Any& rValue) override;
+
+ void SAL_CALL setFastPropertyValue_NoBroadcast(sal_Int32 nHandle, const Any& rValue) override;
+
+ void SAL_CALL getFastPropertyValue(Any& rValue, sal_Int32 nHandle) const override;
+
+ virtual ~OResultSet() override = default;
+
+ /**
+ * Ensures that the results of the query has already been fetched.
+ */
+ void ensureResultFetched();
+
+ /**
+ * Ensures that meta data of the corresponding result set has been already
+ * queried. It should be called before freeing the result set, unless the
+ * information is lost.
+ */
+ void ensureFieldInfoFetched();
+
+ /**
+ * Check the following things:
+ * - cursor is out of range. Throws exception if true.
+ * - column index is out of range. Throws exception if true.
+ * - result set is fetched. If no, then it fetches the result.
+ */
+ void checkBordersAndEnsureFetched(sal_Int32 index);
+
+ /**
+ * Fetches all the data from the MYSQL_RES object related to the class. It
+ * frees the MYSQL_RES object afterwards, so it cannot be used anymore.
+ */
+ void fetchResult();
+
+public:
+ virtual OUString SAL_CALL getImplementationName() override;
+
+ virtual sal_Bool SAL_CALL supportsService(OUString const& ServiceName) override;
+
+ virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override;
+
+ OResultSet(OConnection& rConn, OCommonStatement* pStmt, MYSQL_RES* pResult,
+ rtl_TextEncoding _encoding);
+
+ // ::cppu::OComponentHelper
+ void SAL_CALL disposing() override;
+
+ // XInterface
+ Any SAL_CALL queryInterface(const css::uno::Type& rType) override;
+
+ void SAL_CALL acquire() noexcept override;
+ void SAL_CALL release() noexcept override;
+
+ //XTypeProvider
+ css::uno::Sequence<css::uno::Type> SAL_CALL getTypes() override;
+
+ // XPropertySet
+ css::uno::Reference<css::beans::XPropertySetInfo> SAL_CALL getPropertySetInfo() override;
+
+ // XResultSet
+ sal_Bool SAL_CALL next() override;
+ sal_Bool SAL_CALL isBeforeFirst() override;
+ sal_Bool SAL_CALL isAfterLast() override;
+ sal_Bool SAL_CALL isFirst() override;
+ sal_Bool SAL_CALL isLast() override;
+
+ void SAL_CALL beforeFirst() override;
+ void SAL_CALL afterLast() override;
+
+ sal_Bool SAL_CALL first() override;
+ sal_Bool SAL_CALL last() override;
+
+ sal_Int32 SAL_CALL getRow() override;
+
+ sal_Bool SAL_CALL absolute(sal_Int32 row) override;
+ sal_Bool SAL_CALL relative(sal_Int32 rows) override;
+ sal_Bool SAL_CALL previous() override;
+
+ void SAL_CALL refreshRow() override;
+
+ sal_Bool SAL_CALL rowUpdated() override;
+ sal_Bool SAL_CALL rowInserted() override;
+ sal_Bool SAL_CALL rowDeleted() override;
+
+ css::uno::Reference<css::uno::XInterface> SAL_CALL getStatement() override;
+ // XRow
+ sal_Bool SAL_CALL wasNull() override;
+
+ OUString SAL_CALL getString(sal_Int32 column) override;
+
+ sal_Bool SAL_CALL getBoolean(sal_Int32 column) override;
+ sal_Int8 SAL_CALL getByte(sal_Int32 column) override;
+ sal_Int16 SAL_CALL getShort(sal_Int32 column) override;
+ sal_Int32 SAL_CALL getInt(sal_Int32 column) override;
+ sal_Int64 SAL_CALL getLong(sal_Int32 column) override;
+
+ float SAL_CALL getFloat(sal_Int32 column) override;
+ double SAL_CALL getDouble(sal_Int32 column) override;
+
+ css::uno::Sequence<sal_Int8> SAL_CALL getBytes(sal_Int32 column) override;
+ css::util::Date SAL_CALL getDate(sal_Int32 column) override;
+ css::util::Time SAL_CALL getTime(sal_Int32 column) override;
+ css::util::DateTime SAL_CALL getTimestamp(sal_Int32 column) override;
+
+ css::uno::Reference<css::io::XInputStream> SAL_CALL getBinaryStream(sal_Int32 column) override;
+ css::uno::Reference<css::io::XInputStream>
+ SAL_CALL getCharacterStream(sal_Int32 column) override;
+
+ Any SAL_CALL getObject(
+ sal_Int32 column, const css::uno::Reference<css::container::XNameAccess>& typeMap) override;
+
+ css::uno::Reference<css::sdbc::XRef> SAL_CALL getRef(sal_Int32 column) override;
+ css::uno::Reference<css::sdbc::XBlob> SAL_CALL getBlob(sal_Int32 column) override;
+ css::uno::Reference<css::sdbc::XClob> SAL_CALL getClob(sal_Int32 column) override;
+ css::uno::Reference<css::sdbc::XArray> SAL_CALL getArray(sal_Int32 column) override;
+
+ // XResultSetMetaDataSupplier
+ css::uno::Reference<css::sdbc::XResultSetMetaData> SAL_CALL getMetaData() override;
+
+ // XCancellable
+ void SAL_CALL cancel() override;
+
+ // XCloseable
+ void SAL_CALL close() override;
+
+ // XWarningsSupplier
+ Any SAL_CALL getWarnings() override;
+
+ void SAL_CALL clearWarnings() override;
+
+ // XResultSetUpdate
+ void SAL_CALL insertRow() override;
+ void SAL_CALL updateRow() override;
+ void SAL_CALL deleteRow() override;
+ void SAL_CALL cancelRowUpdates() override;
+ void SAL_CALL moveToInsertRow() override;
+ void SAL_CALL moveToCurrentRow() override;
+
+ // XRowUpdate
+ void SAL_CALL updateNull(sal_Int32 column) override;
+ void SAL_CALL updateBoolean(sal_Int32 column, sal_Bool x) override;
+ void SAL_CALL updateByte(sal_Int32 column, sal_Int8 x) override;
+ void SAL_CALL updateShort(sal_Int32 column, sal_Int16 x) override;
+ void SAL_CALL updateInt(sal_Int32 column, sal_Int32 x) override;
+ void SAL_CALL updateLong(sal_Int32 column, sal_Int64 x) override;
+ void SAL_CALL updateFloat(sal_Int32 column, float x) override;
+ void SAL_CALL updateDouble(sal_Int32 column, double x) override;
+ void SAL_CALL updateString(sal_Int32 column, const OUString& x) override;
+ void SAL_CALL updateBytes(sal_Int32 column, const css::uno::Sequence<sal_Int8>& x) override;
+ void SAL_CALL updateDate(sal_Int32 column, const css::util::Date& x) override;
+ void SAL_CALL updateTime(sal_Int32 column, const css::util::Time& x) override;
+ void SAL_CALL updateTimestamp(sal_Int32 column, const css::util::DateTime& x) override;
+ void SAL_CALL updateBinaryStream(sal_Int32 column,
+ const css::uno::Reference<css::io::XInputStream>& x,
+ sal_Int32 length) override;
+ void SAL_CALL updateCharacterStream(sal_Int32 column,
+ const css::uno::Reference<css::io::XInputStream>& x,
+ sal_Int32 length) override;
+ void SAL_CALL updateObject(sal_Int32 column, const Any& x) override;
+ void SAL_CALL updateNumericObject(sal_Int32 column, const Any& x, sal_Int32 scale) override;
+
+ // XColumnLocate
+ sal_Int32 SAL_CALL findColumn(const OUString& columnName) override;
+
+ // XRowLocate
+ Any SAL_CALL getBookmark() override;
+
+ sal_Bool SAL_CALL moveToBookmark(const Any& bookmark) override;
+ sal_Bool SAL_CALL moveRelativeToBookmark(const Any& bookmark, sal_Int32 rows) override;
+ sal_Int32 SAL_CALL compareBookmarks(const Any& first, const Any& second) override;
+ sal_Bool SAL_CALL hasOrderedBookmarks() override;
+ sal_Int32 SAL_CALL hashBookmark(const Any& bookmark) override;
+
+ // XDeleteRows
+ css::uno::Sequence<sal_Int32> SAL_CALL deleteRows(const css::uno::Sequence<Any>& rows) override;
+
+ void checkColumnIndex(sal_Int32 index);
+ void checkRowIndex();
+
+private:
+ using ::cppu::OPropertySetHelper::getFastPropertyValue;
+};
+
+} /* connectivity::mysqlc */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/mysqlc/mysqlc_resultsetmetadata.cxx b/connectivity/source/drivers/mysqlc/mysqlc_resultsetmetadata.cxx
new file mode 100644
index 0000000000..84cd6be2a3
--- /dev/null
+++ b/connectivity/source/drivers/mysqlc/mysqlc_resultsetmetadata.cxx
@@ -0,0 +1,212 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "mysqlc_resultsetmetadata.hxx"
+#include "mysqlc_general.hxx"
+
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
+#include <o3tl/safeint.hxx>
+
+using namespace connectivity::mysqlc;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::sdbc;
+
+OResultSetMetaData::OResultSetMetaData(OConnection& rConn, MYSQL_RES* pResult)
+ : m_rConnection(rConn)
+{
+ MYSQL_FIELD* fields = mysql_fetch_field(pResult);
+ unsigned nFieldCount = mysql_num_fields(pResult);
+ for (unsigned i = 0; i < nFieldCount; ++i)
+ {
+ MySqlFieldInfo fieldInfo;
+ {
+ fieldInfo.columnName
+ = OUString{ fields[i].name, static_cast<sal_Int32>(fields[i].name_length),
+ m_rConnection.getConnectionEncoding() };
+ fieldInfo.length = static_cast<sal_Int32>(fields[i].length);
+ fieldInfo.type
+ = mysqlc_sdbc_driver::mysqlToOOOType(fields[i].type, fields[i].charsetnr);
+ fieldInfo.mysql_type = fields[i].type;
+ fieldInfo.charsetNumber = fields[i].charsetnr;
+ fieldInfo.flags = fields[i].flags;
+ fieldInfo.schemaName
+ = OUString{ fields[i].db, static_cast<sal_Int32>(fields[i].db_length),
+ m_rConnection.getConnectionEncoding() };
+ fieldInfo.tableName
+ = OUString{ fields[i].table, static_cast<sal_Int32>(fields[i].table_length),
+ m_rConnection.getConnectionEncoding() };
+ fieldInfo.catalogName
+ = OUString{ fields[i].catalog, static_cast<sal_Int32>(fields[i].catalog_length),
+ m_rConnection.getConnectionEncoding() };
+ fieldInfo.decimals = static_cast<sal_Int32>(fields[i].decimals);
+ fieldInfo.max_length = static_cast<sal_Int32>(fields[i].max_length);
+ }
+ m_fields.push_back(std::move(fieldInfo));
+ }
+}
+
+sal_Int32 SAL_CALL OResultSetMetaData::getColumnDisplaySize(sal_Int32 column)
+{
+ checkColumnIndex(column);
+ return m_fields.at(column - 1).length;
+}
+
+sal_Int32 SAL_CALL OResultSetMetaData::getColumnType(sal_Int32 column)
+{
+ checkColumnIndex(column);
+ return m_fields.at(column - 1).type;
+}
+
+sal_Int32 SAL_CALL OResultSetMetaData::getColumnCount() { return m_fields.size(); }
+
+sal_Bool SAL_CALL OResultSetMetaData::isCaseSensitive(sal_Int32 column)
+{
+ // MYSQL_FIELD::charsetnr is the collation identifier
+ // _ci postfix means it's insensitive
+ OUString sql
+ = "SHOW COLLATION WHERE Id =" + OUString::number(m_fields.at(column - 1).charsetNumber);
+
+ Reference<XStatement> stmt = m_rConnection.createStatement();
+ Reference<XResultSet> rs = stmt->executeQuery(sql);
+ Reference<XRow> xRow(rs, UNO_QUERY_THROW);
+
+ if (!rs->next()) // fetch first and only row
+ return false;
+
+ OUString sColName = xRow->getString(1); // first column is Collation name
+
+ return !sColName.isEmpty() && !sColName.endsWith("_ci");
+}
+
+OUString SAL_CALL OResultSetMetaData::getSchemaName(sal_Int32 column)
+{
+ checkColumnIndex(column);
+ return m_fields.at(column - 1).schemaName;
+}
+
+OUString SAL_CALL OResultSetMetaData::getColumnName(sal_Int32 column)
+{
+ checkColumnIndex(column);
+ return m_fields.at(column - 1).columnName;
+}
+
+OUString SAL_CALL OResultSetMetaData::getTableName(sal_Int32 column)
+{
+ checkColumnIndex(column);
+ return m_fields.at(column - 1).tableName;
+}
+
+OUString SAL_CALL OResultSetMetaData::getCatalogName(sal_Int32 column)
+{
+ checkColumnIndex(column);
+ return m_fields.at(column - 1).catalogName;
+}
+
+OUString SAL_CALL OResultSetMetaData::getColumnTypeName(sal_Int32 column)
+{
+ checkColumnIndex(column);
+ return mysqlc_sdbc_driver::mysqlTypeToStr(m_fields.at(column - 1).mysql_type,
+ m_fields.at(column - 1).flags);
+}
+
+OUString SAL_CALL OResultSetMetaData::getColumnLabel(sal_Int32 column)
+{
+ checkColumnIndex(column);
+ return getColumnName(column);
+}
+
+OUString SAL_CALL OResultSetMetaData::getColumnServiceName(sal_Int32 /*column*/)
+{
+ return OUString{};
+}
+
+sal_Bool SAL_CALL OResultSetMetaData::isCurrency(sal_Int32 /*column*/)
+{
+ return false; // TODO
+}
+
+sal_Bool SAL_CALL OResultSetMetaData::isAutoIncrement(sal_Int32 column)
+{
+ checkColumnIndex(column);
+ return (m_fields.at(column - 1).flags & AUTO_INCREMENT_FLAG) != 0;
+}
+
+sal_Bool SAL_CALL OResultSetMetaData::isSigned(sal_Int32 column)
+{
+ checkColumnIndex(column);
+ return !(m_fields.at(column - 1).flags & UNSIGNED_FLAG);
+}
+
+sal_Int32 SAL_CALL OResultSetMetaData::getPrecision(sal_Int32 column)
+{
+ checkColumnIndex(column);
+ return m_fields.at(column - 1).max_length - m_fields.at(column - 1).decimals;
+}
+
+sal_Int32 SAL_CALL OResultSetMetaData::getScale(sal_Int32 column)
+{
+ checkColumnIndex(column);
+ return m_fields.at(column - 1).decimals;
+}
+
+sal_Int32 SAL_CALL OResultSetMetaData::isNullable(sal_Int32 column)
+{
+ checkColumnIndex(column);
+ return (m_fields.at(column - 1).flags & NOT_NULL_FLAG) ? 0 : 1;
+}
+
+sal_Bool SAL_CALL OResultSetMetaData::isSearchable(sal_Int32 column)
+{
+ checkColumnIndex(column);
+ return true;
+}
+
+sal_Bool SAL_CALL OResultSetMetaData::isReadOnly(sal_Int32 column)
+{
+ checkColumnIndex(column);
+ return m_fields.at(column - 1).schemaName.isEmpty();
+}
+
+sal_Bool SAL_CALL OResultSetMetaData::isDefinitelyWritable(sal_Int32 column)
+{
+ checkColumnIndex(column);
+ return !isReadOnly(column);
+}
+
+sal_Bool SAL_CALL OResultSetMetaData::isWritable(sal_Int32 column)
+{
+ checkColumnIndex(column);
+ return !isReadOnly(column);
+}
+
+void OResultSetMetaData::checkColumnIndex(sal_Int32 columnIndex)
+{
+ auto nColCount = m_fields.size();
+ if (columnIndex < 1 || o3tl::make_unsigned(columnIndex) > nColCount)
+ {
+ OUString str = "Column index out of range (expected 1 to "
+ + OUString::number(sal_Int32(nColCount)) + ", got "
+ + OUString::number(columnIndex) + ".";
+ throw SQLException(str, *this, OUString(), 1, Any());
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/mysqlc/mysqlc_resultsetmetadata.hxx b/connectivity/source/drivers/mysqlc/mysqlc_resultsetmetadata.hxx
new file mode 100644
index 0000000000..aa84ac0558
--- /dev/null
+++ b/connectivity/source/drivers/mysqlc/mysqlc_resultsetmetadata.hxx
@@ -0,0 +1,99 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "mysqlc_connection.hxx"
+
+#include <com/sun/star/sdbc/XResultSetMetaData.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
+
+#include <cppuhelper/implbase1.hxx>
+#include <mysql.h>
+
+namespace connectivity::mysqlc
+{
+struct MySqlFieldInfo
+{
+ OUString columnName;
+ sal_Int32 length = 0;
+ sal_Int32 type = 0;
+ enum_field_types mysql_type = {};
+ unsigned charsetNumber = 0;
+ unsigned flags = 0;
+ OUString schemaName;
+ OUString tableName;
+ OUString catalogName;
+ sal_Int32 decimals;
+ sal_Int32 max_length;
+};
+
+//************ Class: ResultSetMetaData
+
+typedef ::cppu::WeakImplHelper1<css::sdbc::XResultSetMetaData> OResultSetMetaData_BASE;
+
+class OResultSetMetaData final : public OResultSetMetaData_BASE
+{
+private:
+ OConnection& m_rConnection;
+ std::vector<MySqlFieldInfo> m_fields;
+
+ void checkColumnIndex(sal_Int32 columnIndex);
+ virtual ~OResultSetMetaData() override = default;
+
+public:
+ OResultSetMetaData(OConnection& rConn, MYSQL_RES* pResult);
+
+ sal_Int32 SAL_CALL getColumnCount() override;
+
+ sal_Bool SAL_CALL isAutoIncrement(sal_Int32 column) override;
+ sal_Bool SAL_CALL isCaseSensitive(sal_Int32 column) override;
+ sal_Bool SAL_CALL isSearchable(sal_Int32 column) override;
+ sal_Bool SAL_CALL isCurrency(sal_Int32 column) override;
+
+ sal_Int32 SAL_CALL isNullable(sal_Int32 column) override;
+
+ sal_Bool SAL_CALL isSigned(sal_Int32 column) override;
+
+ sal_Int32 SAL_CALL getColumnDisplaySize(sal_Int32 column) override;
+
+ OUString SAL_CALL getColumnLabel(sal_Int32 column) override;
+ OUString SAL_CALL getColumnName(sal_Int32 column) override;
+ OUString SAL_CALL getSchemaName(sal_Int32 column) override;
+
+ sal_Int32 SAL_CALL getPrecision(sal_Int32 column) override;
+ sal_Int32 SAL_CALL getScale(sal_Int32 column) override;
+
+ OUString SAL_CALL getTableName(sal_Int32 column) override;
+ OUString SAL_CALL getCatalogName(sal_Int32 column) override;
+
+ sal_Int32 SAL_CALL getColumnType(sal_Int32 column) override;
+
+ OUString SAL_CALL getColumnTypeName(sal_Int32 column) override;
+
+ sal_Bool SAL_CALL isReadOnly(sal_Int32 column) override;
+ sal_Bool SAL_CALL isWritable(sal_Int32 column) override;
+ sal_Bool SAL_CALL isDefinitelyWritable(sal_Int32 column) override;
+
+ OUString SAL_CALL getColumnServiceName(sal_Int32 column) override;
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/mysqlc/mysqlc_services.cxx b/connectivity/source/drivers/mysqlc/mysqlc_services.cxx
new file mode 100644
index 0000000000..6e4e2fbb5e
--- /dev/null
+++ b/connectivity/source/drivers/mysqlc/mysqlc_services.cxx
@@ -0,0 +1,110 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "mysqlc_driver.hxx"
+
+#include <cppuhelper/factory.hxx>
+#include <uno/lbnames.h>
+#include <com/sun/star/lang/XSingleServiceFactory.hpp>
+
+using namespace connectivity::mysqlc;
+using ::com::sun::star::lang::XMultiServiceFactory;
+using ::com::sun::star::lang::XSingleServiceFactory;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::Sequence;
+
+typedef Reference<XSingleServiceFactory> (*createFactoryFunc)(
+ const Reference<XMultiServiceFactory>& rServiceManager, const OUString& rComponentName,
+ ::cppu::ComponentInstantiation pCreateFunction, const Sequence<OUString>& rServiceNames,
+ rtl_ModuleCount*);
+
+namespace
+{
+struct ProviderRequest
+{
+ Reference<XSingleServiceFactory> xRet;
+ Reference<XMultiServiceFactory> const xServiceManager;
+ OUString const sImplementationName;
+
+ ProviderRequest(void* pServiceManager, char const* pImplementationName)
+ : xServiceManager(static_cast<XMultiServiceFactory*>(pServiceManager))
+ , sImplementationName(OUString::createFromAscii(pImplementationName))
+ {
+ }
+
+ bool CREATE_PROVIDER(std::u16string_view Implname, const Sequence<OUString>& Services,
+ ::cppu::ComponentInstantiation Factory, createFactoryFunc creator)
+ {
+ if (!xRet.is() && (Implname == sImplementationName))
+ {
+ try
+ {
+ xRet = creator(xServiceManager, sImplementationName, Factory, Services, nullptr);
+ }
+ catch (...)
+ {
+ }
+ }
+ return xRet.is();
+ }
+
+ void* getProvider() const { return xRet.get(); }
+};
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT void* component_getFactory(const char* pImplementationName,
+ void* pServiceManager,
+ void* /* pRegistryKey */)
+{
+ void* pRet = nullptr;
+ if (pServiceManager)
+ {
+ ProviderRequest aReq(pServiceManager, pImplementationName);
+
+ aReq.CREATE_PROVIDER(MysqlCDriver::getImplementationName_Static(),
+ MysqlCDriver::getSupportedServiceNames_Static(),
+ MysqlCDriver_CreateInstance, ::cppu::createSingleFactory);
+
+ if (aReq.xRet.is())
+ {
+ aReq.xRet->acquire();
+ }
+
+ pRet = aReq.getProvider();
+ }
+
+ return pRet;
+};
+
+extern "C" SAL_DLLPUBLIC_EXPORT void
+component_getImplementationEnvironment(char const** ppEnvTypeName, uno_Environment**)
+{
+ *ppEnvTypeName = CPPU_CURRENT_LANGUAGE_BINDING_NAME;
+}
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/mysqlc/mysqlc_statement.cxx b/connectivity/source/drivers/mysqlc/mysqlc_statement.cxx
new file mode 100644
index 0000000000..ea3783a95c
--- /dev/null
+++ b/connectivity/source/drivers/mysqlc/mysqlc_statement.cxx
@@ -0,0 +1,390 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include "mysqlc_connection.hxx"
+#include "mysqlc_propertyids.hxx"
+#include "mysqlc_resultset.hxx"
+#include "mysqlc_statement.hxx"
+#include "mysqlc_general.hxx"
+
+#include <cppuhelper/typeprovider.hxx>
+#include <cppuhelper/supportsservice.hxx>
+
+using namespace connectivity::mysqlc;
+
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::sdbc;
+using namespace com::sun::star::sdbcx;
+using namespace com::sun::star::container;
+using namespace com::sun::star::io;
+using namespace com::sun::star::util;
+using ::osl::MutexGuard;
+
+OCommonStatement::OCommonStatement(OConnection* _pConnection)
+ : OCommonStatement_IBase(m_aMutex)
+ , OPropertySetHelper(OCommonStatement_IBase::rBHelper)
+ , m_xConnection(_pConnection)
+{
+}
+
+OCommonStatement::~OCommonStatement() {}
+
+void OCommonStatement::closeResultSet()
+{
+ if (m_xResultSet.is())
+ {
+ css::uno::Reference<css::sdbc::XCloseable> xClose(m_xResultSet, UNO_QUERY_THROW);
+ xClose->close();
+ m_xResultSet.clear();
+ }
+}
+
+void OCommonStatement::disposing()
+{
+ MutexGuard aGuard(m_aMutex);
+
+ m_xConnection.clear();
+ OCommonStatement_IBase::disposing();
+}
+
+Any SAL_CALL OCommonStatement::queryInterface(const Type& rType)
+{
+ Any aRet = OCommonStatement_IBase::queryInterface(rType);
+ if (!aRet.hasValue())
+ {
+ aRet = OPropertySetHelper::queryInterface(rType);
+ }
+ return aRet;
+}
+
+Sequence<Type> SAL_CALL OCommonStatement::getTypes()
+{
+ ::cppu::OTypeCollection aTypes(cppu::UnoType<XMultiPropertySet>::get(),
+ cppu::UnoType<XFastPropertySet>::get(),
+ cppu::UnoType<XPropertySet>::get());
+
+ return concatSequences(aTypes.getTypes(), OCommonStatement_IBase::getTypes());
+}
+
+Sequence<Type> SAL_CALL OStatement::getTypes()
+{
+ return concatSequences(OStatement_BASE::getTypes(), OCommonStatement::getTypes());
+}
+
+void SAL_CALL OCommonStatement::cancel()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(rBHelper.bDisposed);
+ // cancel the current sql statement
+}
+
+void SAL_CALL OCommonStatement::close()
+{
+ /*
+ We need a block for the checkDisposed call.
+ After the check we can call dispose() as we are not under lock ??
+ */
+ {
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(rBHelper.bDisposed);
+ }
+ dispose();
+ closeResultSet();
+}
+
+// void SAL_CALL OStatement::clearBatch()
+// {
+// mysqlc_sdbc_driver::throwFeatureNotImplementedException("com:sun:star:sdbc:XBatchExecution");
+// }
+
+sal_Bool SAL_CALL OStatement::execute(const OUString& sql)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(rBHelper.bDisposed);
+
+ closeResultSet();
+ m_nAffectedRows = -1;
+
+ OString toExec = OUStringToOString(sql, m_xConnection->getConnectionSettings().encoding);
+
+ MYSQL* pMySql = m_xConnection->getMysqlConnection();
+
+ // NOTE: differs from MySQL C API, where mysql_real_escape_string_quote()
+ // should be used.
+ // toExec = mysqlc_sdbc_driver::escapeSql(toExec);
+ int failure = mysql_real_query(pMySql, toExec.getStr(), toExec.getLength());
+
+ if (failure || mysql_errno(pMySql))
+ mysqlc_sdbc_driver::throwSQLExceptionWithMsg(mysql_error(pMySql), mysql_sqlstate(pMySql),
+ mysql_errno(pMySql), *this,
+ m_xConnection->getConnectionEncoding());
+
+ return getResult();
+}
+
+Reference<XResultSet> SAL_CALL OStatement::executeQuery(const OUString& sql)
+{
+ bool isRS(execute(sql));
+ // if a MySQL error occurred, it was already thrown and the below is not executed
+ assert(isRS == m_xResultSet.is());
+ if (!isRS)
+ mysqlc_sdbc_driver::throwSQLExceptionWithMsg(
+ "executeQuery called on SQL command that does not return a ResultSet", "02000", 0,
+ *this);
+ if (!m_xResultSet.is())
+ mysqlc_sdbc_driver::throwSQLExceptionWithMsg(
+ "internal MySQL-SDBC error: executeQuery: no ResultSet after execute() returned true.",
+ "02000", 0, *this);
+
+ return m_xResultSet;
+}
+
+Reference<XConnection> SAL_CALL OStatement::getConnection()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(rBHelper.bDisposed);
+
+ // just return our connection here
+ return m_xConnection;
+}
+
+sal_Int32 SAL_CALL OStatement::getUpdateCount() { return m_nAffectedRows; }
+
+Any SAL_CALL OStatement::queryInterface(const Type& rType)
+{
+ Any aRet = OCommonStatement::queryInterface(rType);
+ if (!aRet.hasValue())
+ {
+ aRet = OStatement_BASE::queryInterface(rType);
+ }
+ return aRet;
+}
+
+// void SAL_CALL OStatement::addBatch(const OUString&)
+// {
+// MutexGuard aGuard(m_aMutex);
+// checkDisposed(rBHelper.bDisposed);
+
+// mysqlc_sdbc_driver::throwFeatureNotImplementedException("com:sun:star:sdbc:XBatchExecution");
+// }
+
+// Sequence<sal_Int32> SAL_CALL OStatement::executeBatch()
+// {
+// MutexGuard aGuard(m_aMutex);
+// checkDisposed(rBHelper.bDisposed);
+
+// mysqlc_sdbc_driver::throwFeatureNotImplementedException("com:sun:star:sdbc:XBatchExecution");
+// }
+
+sal_Int32 SAL_CALL OStatement::executeUpdate(const OUString& sql)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(rBHelper.bDisposed);
+
+ execute(sql);
+ return m_nAffectedRows;
+}
+
+Reference<XResultSet> SAL_CALL OStatement::getResultSet()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(rBHelper.bDisposed);
+
+ return m_xResultSet;
+}
+
+bool OStatement::getResult()
+{
+ // all callers already reset that
+ assert(!m_xResultSet.is());
+ assert(m_nAffectedRows == -1);
+
+ MYSQL* pMySql = m_xConnection->getMysqlConnection();
+ MYSQL_RES* pMysqlResult = mysql_store_result(pMySql);
+ if (pMysqlResult != nullptr)
+ {
+ // MariaDB/MySQL will return the number of rows in the ResultSet from mysql_affected_rows();
+ // sdbc mandates -1 when the command (query) returns a ResultSet
+ assert(m_nAffectedRows == -1);
+ m_xResultSet = new OResultSet(*getOwnConnection(), this, pMysqlResult,
+ m_xConnection->getConnectionEncoding());
+ return true;
+ }
+ else if (mysql_field_count(pMySql) == 0)
+ {
+ m_nAffectedRows = mysql_affected_rows(pMySql);
+ return false;
+ }
+ else
+ {
+ mysqlc_sdbc_driver::throwSQLExceptionWithMsg(
+ "mysql_store_result indicated success and SQL command was supposed to return a "
+ "ResultSet, but did not.",
+ "02000", 0, *this);
+ }
+ //unreachable
+ assert(false);
+ // keep -Werror=return-type happy
+ return false;
+}
+
+sal_Bool SAL_CALL OStatement::getMoreResults()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(rBHelper.bDisposed);
+
+ closeResultSet();
+ m_nAffectedRows = -1;
+
+ MYSQL* pMySql = m_xConnection->getMysqlConnection();
+ int status = mysql_next_result(pMySql);
+
+ if (status > 0 || mysql_errno(pMySql))
+ mysqlc_sdbc_driver::throwSQLExceptionWithMsg(mysql_error(pMySql), mysql_sqlstate(pMySql),
+ mysql_errno(pMySql), *this,
+ m_xConnection->getConnectionEncoding());
+
+ if (status == -1)
+ return false;
+
+ if (status != 0)
+ {
+ const OUString errMsg("mysql_next_result returned unexpected value: "
+ + OUString::number(status));
+ mysqlc_sdbc_driver::throwSQLExceptionWithMsg(errMsg, "02000", 0, *this);
+ }
+
+ return getResult();
+}
+
+Any SAL_CALL OCommonStatement::getWarnings()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(rBHelper.bDisposed);
+
+ return Any(m_aLastWarning);
+}
+
+void SAL_CALL OCommonStatement::clearWarnings()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(rBHelper.bDisposed);
+
+ m_aLastWarning = SQLWarning();
+}
+
+::cppu::IPropertyArrayHelper* OCommonStatement::createArrayHelper() const
+{
+ // this properties are define by the service statement
+ // they must in alphabetic order
+ return new ::cppu::OPropertyArrayHelper{
+ { { "CursorName", PROPERTY_ID_CURSORNAME, cppu::UnoType<OUString>::get(), 0 },
+ { "EscapeProcessing", PROPERTY_ID_ESCAPEPROCESSING, cppu::UnoType<bool>::get(), 0 },
+ { "FetchDirection", PROPERTY_ID_FETCHDIRECTION, cppu::UnoType<sal_Int32>::get(), 0 },
+ { "FetchSize", PROPERTY_ID_FETCHSIZE, cppu::UnoType<sal_Int32>::get(), 0 },
+ { "MaxFieldSize", PROPERTY_ID_MAXFIELDSIZE, cppu::UnoType<sal_Int32>::get(), 0 },
+ { "MaxRows", PROPERTY_ID_MAXROWS, cppu::UnoType<sal_Int32>::get(), 0 },
+ { "QueryTimeOut", PROPERTY_ID_QUERYTIMEOUT, cppu::UnoType<sal_Int32>::get(), 0 },
+ { "ResultSetConcurrency", PROPERTY_ID_RESULTSETCONCURRENCY,
+ cppu::UnoType<sal_Int32>::get(), 0 },
+ { "ResultSetType", PROPERTY_ID_RESULTSETTYPE, cppu::UnoType<sal_Int32>::get(), 0 },
+ { "UseBookmarks", PROPERTY_ID_USEBOOKMARKS, cppu::UnoType<bool>::get(), 0 } }
+ };
+}
+
+::cppu::IPropertyArrayHelper& OCommonStatement::getInfoHelper() { return *getArrayHelper(); }
+
+sal_Bool OCommonStatement::convertFastPropertyValue(Any& /* rConvertedValue */,
+ Any& /* rOldValue */, sal_Int32 /* nHandle */,
+ const Any& /* rValue */)
+{
+ // here we have to try to convert
+ return false;
+}
+
+void OCommonStatement::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle, const Any& /* rValue */)
+{
+ // set the value to whatever is necessary
+ switch (nHandle)
+ {
+ case PROPERTY_ID_QUERYTIMEOUT:
+ case PROPERTY_ID_MAXFIELDSIZE:
+ case PROPERTY_ID_MAXROWS:
+ case PROPERTY_ID_CURSORNAME:
+ case PROPERTY_ID_RESULTSETCONCURRENCY:
+ case PROPERTY_ID_RESULTSETTYPE:
+ case PROPERTY_ID_FETCHDIRECTION:
+ case PROPERTY_ID_FETCHSIZE:
+ case PROPERTY_ID_ESCAPEPROCESSING:
+ case PROPERTY_ID_USEBOOKMARKS:
+ default:;
+ }
+}
+
+void OCommonStatement::getFastPropertyValue(Any& _rValue, sal_Int32 nHandle) const
+{
+ switch (nHandle)
+ {
+ case PROPERTY_ID_QUERYTIMEOUT:
+ case PROPERTY_ID_MAXFIELDSIZE:
+ case PROPERTY_ID_MAXROWS:
+ case PROPERTY_ID_CURSORNAME:
+ case PROPERTY_ID_RESULTSETCONCURRENCY:
+ case PROPERTY_ID_RESULTSETTYPE:
+ case PROPERTY_ID_FETCHDIRECTION:
+ case PROPERTY_ID_FETCHSIZE:
+ case PROPERTY_ID_ESCAPEPROCESSING:
+ break;
+ case PROPERTY_ID_USEBOOKMARKS:
+ _rValue <<= false;
+ break;
+ default:;
+ }
+}
+
+OUString OStatement::getImplementationName() { return "com.sun.star.sdbcx.OStatement"; }
+
+css::uno::Sequence<OUString> OStatement::getSupportedServiceNames()
+{
+ return { "com.sun.star.sdbc.Statement" };
+}
+
+sal_Bool OStatement::supportsService(OUString const& ServiceName)
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+void SAL_CALL OCommonStatement::acquire() noexcept { OCommonStatement_IBase::acquire(); }
+
+void SAL_CALL OCommonStatement::release() noexcept { OCommonStatement_IBase::release(); }
+
+void SAL_CALL OStatement::acquire() noexcept { OCommonStatement::acquire(); }
+
+void SAL_CALL OStatement::release() noexcept { OCommonStatement::release(); }
+
+Reference<css::beans::XPropertySetInfo> SAL_CALL OCommonStatement::getPropertySetInfo()
+{
+ return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper());
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/mysqlc/mysqlc_statement.hxx b/connectivity/source/drivers/mysqlc/mysqlc_statement.hxx
new file mode 100644
index 0000000000..c710b0b46a
--- /dev/null
+++ b/connectivity/source/drivers/mysqlc/mysqlc_statement.hxx
@@ -0,0 +1,173 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "mysqlc_connection.hxx"
+#include "mysqlc_subcomponent.hxx"
+
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/sdbc/SQLWarning.hpp>
+#include <com/sun/star/sdbc/XBatchExecution.hpp>
+#include <com/sun/star/sdbc/XCloseable.hpp>
+#include <com/sun/star/sdbc/XMultipleResults.hpp>
+#include <com/sun/star/sdbc/XStatement.hpp>
+#include <com/sun/star/sdbc/XWarningsSupplier.hpp>
+#include <com/sun/star/util/XCancellable.hpp>
+
+#include <cppuhelper/compbase3.hxx>
+#include <rtl/ref.hxx>
+
+namespace connectivity::mysqlc
+{
+using ::com::sun::star::sdbc::SQLWarning;
+using ::com::sun::star::uno::Any;
+using ::com::sun::star::uno::Type;
+
+typedef ::cppu::WeakComponentImplHelper3<css::sdbc::XWarningsSupplier, css::util::XCancellable,
+ css::sdbc::XCloseable>
+ OCommonStatement_IBase;
+
+//************ Class: OCommonStatement
+// is a base class for the normal statement and for the prepared statement
+
+class OCommonStatement : public cppu::BaseMutex,
+ public OCommonStatement_IBase,
+ public ::cppu::OPropertySetHelper,
+ public OPropertyArrayUsageHelper<OCommonStatement>
+
+{
+private:
+ SQLWarning m_aLastWarning;
+
+protected:
+ rtl::Reference<OConnection> m_xConnection; // The owning Connection object
+
+ css::uno::Reference<css::sdbc::XResultSet> m_xResultSet;
+
+ // number of rows affected by an UPDATE, DELETE or INSERT statement.
+ sal_Int32 m_nAffectedRows = 0;
+
+protected:
+ void closeResultSet();
+
+ // OPropertyArrayUsageHelper
+ ::cppu::IPropertyArrayHelper* createArrayHelper() const override;
+
+ // OPropertySetHelper
+ ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override;
+ sal_Bool SAL_CALL convertFastPropertyValue(Any& rConvertedValue, Any& rOldValue,
+ sal_Int32 nHandle, const Any& rValue) override;
+
+ void SAL_CALL setFastPropertyValue_NoBroadcast(sal_Int32 nHandle, const Any& rValue) override;
+
+ void SAL_CALL getFastPropertyValue(Any& rValue, sal_Int32 nHandle) const override;
+ virtual ~OCommonStatement() override;
+
+protected:
+ OCommonStatement(OConnection* _pConnection);
+
+public:
+ using OCommonStatement_IBase::rBHelper;
+ using OCommonStatement_IBase::operator css::uno::Reference<css::uno::XInterface>;
+
+ // OComponentHelper
+ void SAL_CALL disposing() override;
+
+ // XInterface
+ void SAL_CALL release() noexcept override;
+ void SAL_CALL acquire() noexcept override;
+ Any SAL_CALL queryInterface(const css::uno::Type& rType) override;
+
+ //XTypeProvider
+ css::uno::Sequence<css::uno::Type> SAL_CALL getTypes() override;
+
+ // XPropertySet
+ css::uno::Reference<css::beans::XPropertySetInfo> SAL_CALL getPropertySetInfo() override;
+
+ // XWarningsSupplier
+ Any SAL_CALL getWarnings() override;
+
+ void SAL_CALL clearWarnings() override;
+
+ // XCancellable
+ void SAL_CALL cancel() override;
+
+ // XCloseable
+ void SAL_CALL close() override;
+
+ // other methods
+ OConnection* getOwnConnection() const { return m_xConnection.get(); }
+
+private:
+ using ::cppu::OPropertySetHelper::getFastPropertyValue;
+};
+
+typedef ::cppu::ImplHelper3<css::lang::XServiceInfo, css::sdbc::XMultipleResults,
+ css::sdbc::XStatement>
+ OStatement_BASE;
+
+class OStatement final : public OCommonStatement, public OStatement_BASE
+{
+ virtual ~OStatement() override = default;
+
+ bool getResult();
+
+public:
+ // A constructor which is required for the return of the objects
+ OStatement(OConnection* _pConnection)
+ : OCommonStatement(_pConnection)
+ {
+ }
+
+ virtual OUString SAL_CALL getImplementationName() override;
+
+ virtual sal_Bool SAL_CALL supportsService(OUString const& ServiceName) override;
+
+ virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override;
+
+ //XInterface
+ Any SAL_CALL queryInterface(const css::uno::Type& rType) override;
+ void SAL_CALL acquire() noexcept override;
+ void SAL_CALL release() noexcept override;
+
+ //XTypeProvider
+ css::uno::Sequence<Type> SAL_CALL getTypes() override;
+
+ // XStatement
+ css::uno::Reference<css::sdbc::XResultSet> SAL_CALL executeQuery(const OUString& sql) override;
+ sal_Int32 SAL_CALL executeUpdate(const OUString& sql) override;
+ sal_Bool SAL_CALL execute(const OUString& sql) override;
+ css::uno::Reference<css::sdbc::XConnection> SAL_CALL getConnection() override;
+
+ // XMultipleResults
+ css::uno::Reference<css::sdbc::XResultSet> SAL_CALL getResultSet() override;
+ sal_Int32 SAL_CALL getUpdateCount() override;
+ sal_Bool SAL_CALL getMoreResults() override;
+
+ // XBatchExecution
+ // void SAL_CALL addBatch(const OUString& sql) override;
+
+ // void SAL_CALL clearBatch() override;
+
+ // css::uno::Sequence<sal_Int32> SAL_CALL executeBatch() override;
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/mysqlc/mysqlc_subcomponent.hxx b/connectivity/source/drivers/mysqlc/mysqlc_subcomponent.hxx
new file mode 100644
index 0000000000..edba70a935
--- /dev/null
+++ b/connectivity/source/drivers/mysqlc/mysqlc_subcomponent.hxx
@@ -0,0 +1,138 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <cppuhelper/propshlp.hxx>
+#include <osl/diagnose.h>
+#include <osl/mutex.hxx>
+
+namespace cppu
+{
+class IPropertyArrayHelper;
+}
+namespace com::sun::star::lang
+{
+class XComponent;
+}
+
+namespace connectivity::mysqlc
+{
+/// @throws css::lang::DisposedException
+void checkDisposed(bool _bThrow);
+
+template <class TYPE> class OPropertyArrayUsageHelper
+{
+protected:
+ static sal_Int32 s_nRefCount;
+ static ::cppu::IPropertyArrayHelper* s_pProps;
+ static ::osl::Mutex s_aMutex;
+
+public:
+ OPropertyArrayUsageHelper();
+ virtual ~OPropertyArrayUsageHelper();
+
+ /** call this in the getInfoHelper method of your derived class. The method returns the array helper of the
+ class, which is created if necessary.
+ */
+ ::cppu::IPropertyArrayHelper* getArrayHelper();
+
+protected:
+ /** used to implement the creation of the array helper which is shared amongst all instances of the class.
+ This method needs to be implemented in derived classes.
+ <BR>
+ The method gets called with s_aMutex acquired.
+ @return a pointer to the newly created array helper. Must not be NULL.
+ */
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper() const = 0;
+};
+
+template <class TYPE> sal_Int32 OPropertyArrayUsageHelper<TYPE>::s_nRefCount = 0;
+
+template <class TYPE>
+::cppu::IPropertyArrayHelper* OPropertyArrayUsageHelper<TYPE>::s_pProps = nullptr;
+
+template <class TYPE>::osl::Mutex OPropertyArrayUsageHelper<TYPE>::s_aMutex;
+
+template <class TYPE> OPropertyArrayUsageHelper<TYPE>::OPropertyArrayUsageHelper()
+{
+ ::osl::MutexGuard aGuard(s_aMutex);
+ ++s_nRefCount;
+}
+
+template <class TYPE> OPropertyArrayUsageHelper<TYPE>::~OPropertyArrayUsageHelper()
+{
+ ::osl::MutexGuard aGuard(s_aMutex);
+ OSL_ENSURE(s_nRefCount > 0, "OPropertyArrayUsageHelper::~OPropertyArrayUsageHelper : "
+ "suspicious call : have a refcount of 0 !");
+ if (!--s_nRefCount)
+ {
+ delete s_pProps;
+ s_pProps = nullptr;
+ }
+}
+
+template <class TYPE>::cppu::IPropertyArrayHelper* OPropertyArrayUsageHelper<TYPE>::getArrayHelper()
+{
+ OSL_ENSURE(
+ s_nRefCount,
+ "OPropertyArrayUsageHelper::getArrayHelper : suspicious call : have a refcount of 0 !");
+ if (!s_pProps)
+ {
+ ::osl::MutexGuard aGuard(s_aMutex);
+ if (!s_pProps)
+ {
+ s_pProps = createArrayHelper();
+ OSL_ENSURE(s_pProps, "OPropertyArrayUsageHelper::getArrayHelper : createArrayHelper "
+ "returned nonsense !");
+ }
+ }
+ return s_pProps;
+}
+
+namespace internal
+{
+template <class T> void implCopySequence(const T* _pSource, T*& _pDest, sal_Int32 _nSourceLen)
+{
+ for (sal_Int32 i = 0; i < _nSourceLen; ++i, ++_pSource, ++_pDest)
+ *_pDest = *_pSource;
+}
+}
+
+/// concat two sequences
+template <class T>
+css::uno::Sequence<T> concatSequences(const css::uno::Sequence<T>& _rLeft,
+ const css::uno::Sequence<T>& _rRight)
+{
+ sal_Int32 nLeft(_rLeft.getLength()), nRight(_rRight.getLength());
+ const T* pLeft = _rLeft.getConstArray();
+ const T* pRight = _rRight.getConstArray();
+
+ sal_Int32 nReturnLen(nLeft + nRight);
+ css::uno::Sequence<T> aReturn(nReturnLen);
+ T* pReturn = aReturn.getArray();
+
+ internal::implCopySequence(pLeft, pReturn, nLeft);
+ internal::implCopySequence(pRight, pReturn, nRight);
+
+ return aReturn;
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/mysqlc/mysqlc_table.cxx b/connectivity/source/drivers/mysqlc/mysqlc_table.cxx
new file mode 100644
index 0000000000..eedcb35d61
--- /dev/null
+++ b/connectivity/source/drivers/mysqlc/mysqlc_table.cxx
@@ -0,0 +1,167 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "mysqlc_columns.hxx"
+#include "mysqlc_indexes.hxx"
+#include "mysqlc_keys.hxx"
+#include "mysqlc_table.hxx"
+
+#include <TConnection.hxx>
+
+#include <comphelper/types.hxx>
+#include <connectivity/dbtools.hxx>
+
+#include <com/sun/star/sdbcx/Privilege.hpp>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+
+connectivity::mysqlc::Table::Table(
+ Tables* pTables, osl::Mutex& rMutex,
+ const css::uno::Reference<OMetaConnection::XConnection>& rConnection)
+ : OTableHelper(pTables, rConnection, true)
+ , m_rMutex(rMutex)
+ , m_nPrivileges(0)
+{
+ construct();
+}
+
+connectivity::mysqlc::Table::Table(
+ Tables* pTables, osl::Mutex& rMutex,
+ const css::uno::Reference<OMetaConnection::XConnection>& rConnection, const OUString& rCatalog,
+ const OUString& rSchema, const OUString& rName, const OUString& rType,
+ const OUString& rDescription)
+ : OTableHelper(pTables, rConnection, true, rName, rType, rDescription, rSchema, rCatalog)
+ , m_rMutex(rMutex)
+ , m_nPrivileges(0)
+{
+ construct();
+}
+
+void connectivity::mysqlc::Table::construct()
+{
+ OTableHelper::construct();
+ if (isNew())
+ return;
+
+ // TODO: get privileges when in non-embedded mode.
+ m_nPrivileges = css::sdbcx::Privilege::DROP | css::sdbcx::Privilege::REFERENCE
+ | css::sdbcx::Privilege::ALTER | css::sdbcx::Privilege::CREATE
+ | css::sdbcx::Privilege::READ | css::sdbcx::Privilege::DELETE
+ | css::sdbcx::Privilege::UPDATE | css::sdbcx::Privilege::INSERT
+ | css::sdbcx::Privilege::SELECT;
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PRIVILEGES),
+ PROPERTY_ID_PRIVILEGES, css::beans::PropertyAttribute::READONLY,
+ &m_nPrivileges, cppu::UnoType<decltype(m_nPrivileges)>::get());
+}
+//----- OTableHelper ---------------------------------------------------------
+connectivity::sdbcx::OCollection*
+connectivity::mysqlc::Table::createColumns(const ::std::vector<OUString>& rNames)
+{
+ return new Columns(*this, m_rMutex, rNames);
+}
+
+connectivity::sdbcx::OCollection*
+connectivity::mysqlc::Table::createKeys(const ::std::vector<OUString>& rNames)
+{
+ return new Keys(this, m_rMutex, rNames);
+}
+
+connectivity::sdbcx::OCollection*
+connectivity::mysqlc::Table::createIndexes(const ::std::vector<OUString>& rNames)
+{
+ return new Indexes(this, m_rMutex, rNames);
+}
+
+//----- XAlterTable -----------------------------------------------------------
+void SAL_CALL connectivity::mysqlc::Table::alterColumnByName(
+ const OUString& rColName, const css::uno::Reference<XPropertySet>& rDescriptor)
+{
+ osl::MutexGuard aGuard(m_rMutex);
+ checkDisposed(WeakComponentImplHelperBase::rBHelper.bDisposed);
+
+ css::uno::Reference<XPropertySet> xColumn(m_xColumns->getByName(rColName), css::uno::UNO_QUERY);
+
+ // sdbcx::Descriptor
+ const bool bNameChanged
+ = xColumn->getPropertyValue("Name") != rDescriptor->getPropertyValue("Name");
+ // sdbcx::ColumnDescriptor
+ const bool bTypeChanged
+ = xColumn->getPropertyValue("Type") != rDescriptor->getPropertyValue("Type");
+ const bool bTypeNameChanged = !comphelper::getString(xColumn->getPropertyValue("TypeName"))
+ .equalsIgnoreAsciiCase(comphelper::getString(
+ rDescriptor->getPropertyValue("TypeName")));
+ const bool bPrecisionChanged
+ = xColumn->getPropertyValue("Precision") != rDescriptor->getPropertyValue("Precision");
+ const bool bScaleChanged
+ = xColumn->getPropertyValue("Scale") != rDescriptor->getPropertyValue("Scale");
+
+ const bool bIsNullableChanged
+ = xColumn->getPropertyValue("IsNullable") != rDescriptor->getPropertyValue("IsNullable");
+
+ const bool bIsAutoIncrementChanged = xColumn->getPropertyValue("IsAutoIncrement")
+ != rDescriptor->getPropertyValue("IsAutoIncrement");
+
+ // there's also DefaultValue but not related to database directly, it seems completely internal to LO
+ // so no need to test it
+ // TODO: remainder -- these are all "optional" so have to detect presence and change.
+ if (bTypeChanged || bTypeNameChanged || bPrecisionChanged || bScaleChanged || bIsNullableChanged
+ || bIsAutoIncrementChanged)
+ {
+ // If bPrecisionChanged this will only succeed if we have increased the
+ // precision, otherwise an exception is thrown -- however the base
+ // gui then offers to delete and recreate the column.
+ OUStringBuffer sSql(300);
+ sSql.append(getAlterTableColumnPart() + " MODIFY COLUMN `" + rColName + "` "
+ + ::dbtools::createStandardTypePart(rDescriptor, getConnection()));
+
+ if (comphelper::getBOOL(rDescriptor->getPropertyValue("IsAutoIncrement")))
+ sSql.append(" auto_increment");
+
+ // see ColumnValue: NO_NULLS = 0, NULLABLE = 1, NULLABLE_UNKNOWN
+ // so entry required = yes corresponds to NO_NULLS = 0 and only in this case
+ // NOT NULL
+ if (comphelper::getINT32(rDescriptor->getPropertyValue("IsNullable")) == 0)
+ sSql.append(" NOT NULL");
+
+ getConnection()->createStatement()->execute(sSql.makeStringAndClear());
+ }
+
+ if (bNameChanged)
+ {
+ OUString sNewColName;
+ rDescriptor->getPropertyValue("Name") >>= sNewColName;
+ OUString sSql(getAlterTableColumnPart() + " RENAME COLUMN `" + rColName + "` TO `"
+ + sNewColName + "`");
+
+ getConnection()->createStatement()->execute(sSql);
+ }
+
+ m_xColumns->refresh();
+}
+
+void SAL_CALL connectivity::mysqlc::Table::alterColumnByIndex(
+ sal_Int32 index, const css::uno::Reference<css::beans::XPropertySet>& descriptor)
+{
+ osl::MutexGuard aGuard(m_rMutex);
+ css::uno::Reference<XPropertySet> xColumn(m_xColumns->getByIndex(index),
+ css::uno::UNO_QUERY_THROW);
+ alterColumnByName(comphelper::getString(xColumn->getPropertyValue(
+ OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME))),
+ descriptor);
+}
+
+OUString connectivity::mysqlc::Table::getAlterTableColumnPart() const
+{
+ return "ALTER TABLE "
+ + ::dbtools::composeTableName(getMetaData(), m_CatalogName, m_SchemaName, m_Name, true,
+ ::dbtools::EComposeRule::InTableDefinitions);
+}
+
+OUString connectivity::mysqlc::Table::getRenameStart() const { return "RENAME TABLE "; }
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/connectivity/source/drivers/mysqlc/mysqlc_table.hxx b/connectivity/source/drivers/mysqlc/mysqlc_table.hxx
new file mode 100644
index 0000000000..7487f1bc7b
--- /dev/null
+++ b/connectivity/source/drivers/mysqlc/mysqlc_table.hxx
@@ -0,0 +1,69 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include "mysqlc_tables.hxx"
+
+#include <connectivity/TTableHelper.hxx>
+
+namespace connectivity::mysqlc
+{
+class Table : public OTableHelper
+{
+private:
+ ::osl::Mutex& m_rMutex;
+ sal_Int32 m_nPrivileges;
+
+protected:
+ void construct() override;
+
+public:
+ Table(Tables* pTables, ::osl::Mutex& rMutex,
+ const css::uno::Reference<css::sdbc::XConnection>& _xConnection);
+ Table(Tables* pTables, ::osl::Mutex& rMutex,
+ const css::uno::Reference<css::sdbc::XConnection>& _xConnection, const OUString& rCatalog,
+ const OUString& rSchema, const OUString& rName, const OUString& rType,
+ const OUString& rDescription);
+
+ // OTableHelper
+ virtual ::connectivity::sdbcx::OCollection*
+ createColumns(const ::std::vector<OUString>& rNames) override;
+ virtual ::connectivity::sdbcx::OCollection*
+ createKeys(const ::std::vector<OUString>& rNames) override;
+ virtual ::connectivity::sdbcx::OCollection*
+ createIndexes(const ::std::vector<OUString>& rNames) override;
+
+ /** Returns always "RENAME TABLE " even for views.
+ *
+ * \return The start of the rename statement.
+ * @see http://dev.mysql.com/doc/refman/5.1/de/rename-table.html
+ */
+ virtual OUString getRenameStart() const override;
+
+ // XAlterTable
+ /**
+ * See css::sdbcx::ColumnDescriptor for details of
+ * rDescriptor.
+ */
+ virtual void SAL_CALL
+ alterColumnByName(const OUString& rColName,
+ const css::uno::Reference<css::beans::XPropertySet>& rDescriptor) override;
+
+ virtual void SAL_CALL alterColumnByIndex(
+ sal_Int32 index, const css::uno::Reference<css::beans::XPropertySet>& descriptor) override;
+
+ /** returns the ALTER TABLE XXX statement
+ */
+ OUString getAlterTableColumnPart() const;
+};
+
+} // namespace connectivity::mysqlc
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/connectivity/source/drivers/mysqlc/mysqlc_tables.cxx b/connectivity/source/drivers/mysqlc/mysqlc_tables.cxx
new file mode 100644
index 0000000000..81498978d3
--- /dev/null
+++ b/connectivity/source/drivers/mysqlc/mysqlc_tables.cxx
@@ -0,0 +1,157 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "mysqlc_table.hxx"
+#include "mysqlc_tables.hxx"
+#include "mysqlc_catalog.hxx"
+
+#include <TConnection.hxx>
+
+#include <connectivity/dbtools.hxx>
+
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/ColumnValue.hpp>
+#include <comphelper/types.hxx>
+
+//----- OCollection -----------------------------------------------------------
+void connectivity::mysqlc::Tables::impl_refresh()
+{
+ static_cast<Catalog&>(m_rParent).refreshTables();
+}
+
+static void lcl_unescape(OUString& rName)
+{
+ // Remove ending ` if there's one
+ sal_Int32 nLastIndexBacktick = rName.lastIndexOf("`");
+ if ((nLastIndexBacktick > 0) && (nLastIndexBacktick == (rName.getLength() - 1)))
+ {
+ rName = rName.copy(0, nLastIndexBacktick);
+ }
+
+ // Remove beginning `
+ nLastIndexBacktick = rName.indexOf("`");
+ if (nLastIndexBacktick == 0)
+ {
+ rName = rName.copy(1, rName.getLength() - 1);
+ }
+
+ // Replace double ` by simple `
+ rName = rName.replaceAll("``", "`");
+}
+
+connectivity::sdbcx::ObjectType connectivity::mysqlc::Tables::createObject(const OUString& rName)
+{
+ OUString sCatalog, sSchema, sTable;
+ ::dbtools::qualifiedNameComponents(m_xMetaData, rName, sCatalog, sSchema, sTable,
+ ::dbtools::EComposeRule::InDataManipulation);
+
+ css::uno::Any aCatalog;
+ if (!sCatalog.isEmpty())
+ {
+ lcl_unescape(sCatalog);
+ aCatalog <<= sCatalog;
+ }
+
+ lcl_unescape(sSchema);
+ lcl_unescape(sTable);
+
+ // Only retrieving a single table, so table type is irrelevant (param 4)
+ css::uno::Reference<css::sdbc::XResultSet> xTables
+ = m_xMetaData->getTables(aCatalog, sSchema, sTable, css::uno::Sequence<OUString>());
+
+ if (!xTables.is())
+ throw css::uno::RuntimeException("Could not acquire table.");
+
+ css::uno::Reference<css::sdbc::XRow> xRow(xTables, css::uno::UNO_QUERY_THROW);
+
+ if (!xTables->next())
+ throw css::uno::RuntimeException();
+
+ connectivity::sdbcx::ObjectType xRet(
+ new Table(this, m_rMutex, m_xMetaData->getConnection(),
+ xRow->getString(1), // Catalog
+ xRow->getString(2), // Schema
+ xRow->getString(3), // Name
+ xRow->getString(4), // Type
+ xRow->getString(5))); // Description / Remarks / Comments
+
+ if (xTables->next())
+ throw css::uno::RuntimeException("Found more tables than expected.");
+
+ return xRet;
+}
+
+css::uno::Reference<css::beans::XPropertySet> connectivity::mysqlc::Tables::createDescriptor()
+{
+ // There is some internal magic so that the same class can be used as either
+ // a descriptor or as a normal table. See VTable.cxx for the details. In our
+ // case we just need to ensure we use the correct constructor.
+ return new Table(this, m_rMutex, m_xMetaData->getConnection());
+}
+
+//----- XAppend ---------------------------------------------------------------
+void connectivity::mysqlc::Tables::createTable(
+ const css::uno::Reference<css::beans::XPropertySet>& descriptor)
+{
+ const css::uno::Reference<css::sdbc::XConnection> xConnection = m_xMetaData->getConnection();
+ OUString aSql = ::dbtools::createSqlCreateTableStatement(descriptor, xConnection);
+
+ css::uno::Reference<css::sdbc::XStatement> xStmt = xConnection->createStatement();
+ if (xStmt.is())
+ {
+ xStmt->execute(aSql);
+ ::comphelper::disposeComponent(xStmt);
+ }
+}
+
+// XAppend
+connectivity::sdbcx::ObjectType connectivity::mysqlc::Tables::appendObject(
+ const OUString& _rForName, const css::uno::Reference<css::beans::XPropertySet>& descriptor)
+{
+ createTable(descriptor);
+ return createObject(_rForName);
+}
+
+void connectivity::mysqlc::Tables::appendNew(const OUString& _rsNewTable)
+{
+ insertElement(_rsNewTable, nullptr);
+
+ // notify our container listeners
+ css::container::ContainerEvent aEvent(static_cast<XContainer*>(this),
+ css::uno::Any(_rsNewTable), css::uno::Any(),
+ css::uno::Any());
+ comphelper::OInterfaceIteratorHelper3 aListenerLoop(m_aContainerListeners);
+ while (aListenerLoop.hasMoreElements())
+ aListenerLoop.next()->elementInserted(aEvent);
+}
+
+OUString
+connectivity::mysqlc::Tables::getNameForObject(const connectivity::sdbcx::ObjectType& _xObject)
+{
+ OSL_ENSURE(_xObject.is(), "OTables::getNameForObject: Object is NULL!");
+ return ::dbtools::composeTableName(m_xMetaData, _xObject,
+ ::dbtools::EComposeRule::InDataManipulation, false)
+ .replaceAll(u"`", u"̀ `");
+}
+
+//----- XDrop -----------------------------------------------------------------
+void connectivity::mysqlc::Tables::dropObject(sal_Int32 nPosition, const OUString& sName)
+{
+ css::uno::Reference<css::beans::XPropertySet> xTable(getObject(nPosition));
+
+ if (connectivity::sdbcx::ODescriptor::isNew(xTable))
+ return;
+
+ OUString sType;
+ xTable->getPropertyValue("Type") >>= sType;
+
+ m_xMetaData->getConnection()->createStatement()->execute("DROP " + sType + " " + sName);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/connectivity/source/drivers/mysqlc/mysqlc_tables.hxx b/connectivity/source/drivers/mysqlc/mysqlc_tables.hxx
new file mode 100644
index 0000000000..8b05c5afaf
--- /dev/null
+++ b/connectivity/source/drivers/mysqlc/mysqlc_tables.hxx
@@ -0,0 +1,57 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include <com/sun/star/sdbc/XDatabaseMetaData.hpp>
+
+#include <connectivity/sdbcx/VCollection.hxx>
+#include <utility>
+
+namespace connectivity::mysqlc
+{
+/**
+* This implements com.sun.star.sdbcx.Container, which seems to be
+* also known by the name of Tables and Collection.
+*/
+class Tables : public ::connectivity::sdbcx::OCollection
+{
+protected:
+ css::uno::Reference<css::sdbc::XDatabaseMetaData> m_xMetaData;
+
+ // OCollection
+ virtual void impl_refresh() override;
+ virtual ::connectivity::sdbcx::ObjectType createObject(const OUString& rName) override;
+ virtual css::uno::Reference<css::beans::XPropertySet> createDescriptor() override;
+ virtual ::connectivity::sdbcx::ObjectType
+ appendObject(const OUString& rName,
+ const css::uno::Reference<css::beans::XPropertySet>& rDescriptor) override;
+
+ void createTable(const css::uno::Reference<css::beans::XPropertySet>& descriptor);
+ virtual OUString getNameForObject(const sdbcx::ObjectType& _xObject) override;
+ // XDrop
+ virtual void dropObject(sal_Int32 nPosition, const OUString& rName) override;
+
+public:
+ Tables(css::uno::Reference<css::sdbc::XDatabaseMetaData> xMetaData,
+ ::cppu::OWeakObject& rParent, ::osl::Mutex& rMutex,
+ ::std::vector<OUString> const& rNames)
+ : sdbcx::OCollection(rParent, true, rMutex, rNames)
+ , m_xMetaData(std::move(xMetaData))
+ {
+ }
+
+ void appendNew(const OUString& _rsNewTable);
+ // TODO: should we also implement XDataDescriptorFactory, XRefreshable,
+ // XAppend, etc. ?
+};
+
+} // namespace connectivity::mysqlc
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/connectivity/source/drivers/mysqlc/mysqlc_types.cxx b/connectivity/source/drivers/mysqlc/mysqlc_types.cxx
new file mode 100644
index 0000000000..ca473cebd8
--- /dev/null
+++ b/connectivity/source/drivers/mysqlc/mysqlc_types.cxx
@@ -0,0 +1,700 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <com/sun/star/sdbc/ColumnValue.hpp>
+#include <com/sun/star/sdbc/ColumnSearch.hpp>
+#include "mysqlc_types.hxx"
+
+using namespace com::sun::star::sdbc;
+
+TypeInfoDef const mysqlc_types[] = {
+
+ // ------------- MySQL-Type: BIT. SDBC-Type: Bit -------------
+ {
+ "BIT", // Typename
+ com::sun::star::sdbc::DataType::BIT, // sdbc-type
+ 1, // Precision
+ "", // Literal prefix
+ "", // Literal suffix
+ "", // Create params
+ com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable
+ true, // case sensitive
+ com::sun::star::sdbc::ColumnSearch::FULL, // searchable
+ false, // unsignable
+ false, // fixed_prec_scale
+ false, // auto_increment
+ "BIT", // local type name
+ 0, // minimum scale
+ 0 // maximum scale
+ },
+
+ // ------------ MySQL-Type: BOOL. SDBC-Type: Bit -------------
+ {
+ "BOOL", // Typename
+ com::sun::star::sdbc::DataType::BIT, // sdbc-type
+ 1, // Precision
+ "", // Literal prefix
+ "", // Literal suffix
+ "", // Create params
+ com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable
+ true, // case sensitive
+ com::sun::star::sdbc::ColumnSearch::FULL, // searchable
+ false, // unsignable
+ false, // fixed_prec_scale
+ false, // auto_increment
+ "BOOL", // local type name
+ 0, // minimum scale
+ 0 // maximum scale
+ },
+
+ // --------- MySQL-Type: TINYINT SDBC-Type: TINYINT ----------
+ {
+ "TINYINT", // Typename
+ com::sun::star::sdbc::DataType::TINYINT, // sdbc-type
+ 3, // Precision
+ "", // Literal prefix
+ "", // Literal suffix
+ "[(M)] [UNSIGNED] [ZEROFILL]", // Create params
+ com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable
+ false, // case sensitive
+ com::sun::star::sdbc::ColumnSearch::FULL, // searchable
+ true, // unsignable
+ false, // fixed_prec_scale
+ true, // auto_increment
+ "TINYINT", // local type name
+ 0, // minimum scale
+ 0 // maximum scale
+ },
+
+ // ----------- MySQL-Type: BIGINT SDBC-Type: BIGINT ----------
+ {
+ "BIGINT", // Typename
+ com::sun::star::sdbc::DataType::BIGINT, // sdbc-type
+ 19, // Precision
+ "", // Literal prefix
+ "", // Literal suffix
+ "[(M)] [UNSIGNED] [ZEROFILL]", // Create params
+ com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable
+ false, // case sensitive
+ com::sun::star::sdbc::ColumnSearch::FULL, // searchable
+ true, // unsignable
+ false, // fixed_prec_scale
+ true, // auto_increment
+ "BIGINT", // local type name
+ 0, // minimum scale
+ 0 // maximum scale
+ },
+
+ // ----------- MySQL-Type: LONG VARBINARY SDBC-Type: LONGVARBINARY ----------
+ {
+ "LONG VARBINARY", // Typename
+ com::sun::star::sdbc::DataType::LONGVARBINARY, // sdbc-type
+ 16777215, // Precision
+ "'", // Literal prefix
+ "'", // Literal suffix
+ "", // Create params
+ com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable
+ true, // case sensitive
+ com::sun::star::sdbc::ColumnSearch::FULL, // searchable
+ false, // unsignable
+ false, // fixed_prec_scale
+ false, // auto_increment
+ "LONG VARBINARY", // local type name
+ 0, // minimum scale
+ 0 // maximum scale
+ },
+
+ // ----------- MySQL-Type: MEDIUMBLOB SDBC-Type: LONGVARBINARY ----------
+ {
+ "MEDIUMBLOB", // Typename
+ com::sun::star::sdbc::DataType::LONGVARBINARY, // sdbc-type
+ 16777215, // Precision
+ "'", // Literal prefix
+ "'", // Literal suffix
+ "", // Create params
+ com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable
+ true, // case sensitive
+ com::sun::star::sdbc::ColumnSearch::FULL, // searchable
+ false, // unsignable
+ false, // fixed_prec_scale
+ false, // auto_increment
+ "MEDIUMBLOB", // local type name
+ 0, // minimum scale
+ 0 // maximum scale
+ },
+
+ // ----------- MySQL-Type: LONGBLOB SDBC-Type: LONGVARBINARY ----------
+ {
+ "LONGBLOB", // Typename
+ com::sun::star::sdbc::DataType::LONGVARBINARY, // sdbc-type
+ -1, // Precision
+ "'", // Literal prefix
+ "'", // Literal suffix
+ "", // Create params
+ com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable
+ true, // case sensitive
+ com::sun::star::sdbc::ColumnSearch::FULL, // searchable
+ false, // unsignable
+ false, // fixed_prec_scale
+ false, // auto_increment
+ "LONGBLOB", // local type name
+ 0, // minimum scale
+ 0 // maximum scale
+ },
+
+ // ----------- MySQL-Type: BLOB SDBC-Type: LONGVARBINARY ----------
+ {
+ "BLOB", // Typename
+ com::sun::star::sdbc::DataType::LONGVARBINARY, // sdbc-type
+ 0xFFFF, // Precision
+ "'", // Literal prefix
+ "'", // Literal suffix
+ "", // Create params
+ com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable
+ true, // case sensitive
+ com::sun::star::sdbc::ColumnSearch::FULL, // searchable
+ false, // unsignable
+ false, // fixed_prec_scale
+ false, // auto_increment
+ "BLOB", // local type name
+ 0, // minimum scale
+ 0 // maximum scale
+ },
+
+ // ----------- MySQL-Type: TINYBLOB SDBC-Type: LONGVARBINARY ----------
+ {
+ "TINYBLOB", // Typename
+ com::sun::star::sdbc::DataType::LONGVARBINARY, // sdbc-type
+ 0xFF, // Precision
+ "'", // Literal prefix
+ "'", // Literal suffix
+ "", // Create params
+ com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable
+ true, // case sensitive
+ com::sun::star::sdbc::ColumnSearch::FULL, // searchable
+ false, // unsignable
+ false, // fixed_prec_scale
+ false, // auto_increment
+ "TINYBLOB", // local type name
+ 0, // minimum scale
+ 0 // maximum scale
+ },
+
+ // ----------- MySQL-Type: VARBINARY SDBC-Type: VARBINARY ----------
+ {
+ "VARBINARY", // Typename
+ com::sun::star::sdbc::DataType::VARBINARY, // sdbc-type
+ 0xFF, // Precision
+ "'", // Literal prefix
+ "'", // Literal suffix
+ "(M)", // Create params
+ com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable
+ true, // case sensitive
+ com::sun::star::sdbc::ColumnSearch::FULL, // searchable
+ false, // unsignable
+ false, // fixed_prec_scale
+ false, // auto_increment
+ "VARBINARY", // local type name
+ 0, // minimum scale
+ 0 // maximum scale
+ },
+
+ // ----------- MySQL-Type: BINARY SDBC-Type: BINARY ----------
+ {
+ "BINARY", // Typename
+ com::sun::star::sdbc::DataType::BINARY, // sdbc-type
+ 0xFF, // Precision
+ "'", // Literal prefix
+ "'", // Literal suffix
+ "(M)", // Create params
+ com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable
+ true, // case sensitive
+ com::sun::star::sdbc::ColumnSearch::FULL, // searchable
+ false, // unsignable
+ false, // fixed_prec_scale
+ false, // auto_increment
+ "VARBINARY", // local type name
+ 0, // minimum scale
+ 0 // maximum scale
+ },
+
+ // ----------- MySQL-Type: LONG VARCHAR SDBC-Type: LONG VARCHAR ----------
+ {
+ "LONG VARCHAR", // Typename
+ com::sun::star::sdbc::DataType::LONGVARCHAR, // sdbc-type
+ 0xFFFFFF, // Precision
+ "'", // Literal prefix
+ "'", // Literal suffix
+ "", // Create params
+ com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable
+ false, // case sensitive
+ com::sun::star::sdbc::ColumnSearch::FULL, // searchable
+ false, // unsignable
+ false, // fixed_prec_scale
+ false, // auto_increment
+ "LONG VARCHAR", // local type name
+ 0, // minimum scale
+ 0 // maximum scale
+ },
+
+ // ----------- MySQL-Type: MEDIUMTEXT SDBC-Type: LONG VARCHAR ----------
+ {
+ "MEDIUMTEXT", // Typename
+ com::sun::star::sdbc::DataType::LONGVARCHAR, // sdbc-type
+ 0xFFFFFF, // Precision
+ "'", // Literal prefix
+ "'", // Literal suffix
+ "", // Create params
+ com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable
+ false, // case sensitive
+ com::sun::star::sdbc::ColumnSearch::FULL, // searchable
+ false, // unsignable
+ false, // fixed_prec_scale
+ false, // auto_increment
+ "MEDIUMTEXT", // local type name
+ 0, // minimum scale
+ 0 // maximum scale
+ },
+
+ // ----------- MySQL-Type: LONGTEXT SDBC-Type: LONG VARCHAR ----------
+ {
+ "LONGTEXT", // Typename
+ com::sun::star::sdbc::DataType::LONGVARCHAR, // sdbc-type
+ 0xFFFFFF, // Precision
+ "'", // Literal prefix
+ "'", // Literal suffix
+ "", // Create params
+ com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable
+ false, // case sensitive
+ com::sun::star::sdbc::ColumnSearch::FULL, // searchable
+ false, // unsignable
+ false, // fixed_prec_scale
+ false, // auto_increment
+ "LONGTEXT", // local type name
+ 0, // minimum scale
+ 0 // maximum scale
+ },
+
+ // ----------- MySQL-Type: TEXT SDBC-Type: LONG VARCHAR ----------
+ {
+ "TEXT", // Typename
+ com::sun::star::sdbc::DataType::LONGVARCHAR, // sdbc-type
+ 0xFFFF, // Precision
+ "'", // Literal prefix
+ "'", // Literal suffix
+ "", // Create params
+ com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable
+ false, // case sensitive
+ com::sun::star::sdbc::ColumnSearch::FULL, // searchable
+ false, // unsignable
+ false, // fixed_prec_scale
+ false, // auto_increment
+ "TEXT", // local type name
+ 0, // minimum scale
+ 0 // maximum scale
+ },
+
+ // ----------- MySQL-Type: TINYTEXT SDBC-Type: LONG VARCHAR ----------
+ {
+ "TINYTEXT", // Typename
+ com::sun::star::sdbc::DataType::LONGVARCHAR, // sdbc-type
+ 0xFF, // Precision
+ "'", // Literal prefix
+ "'", // Literal suffix
+ "", // Create params
+ com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable
+ false, // case sensitive
+ com::sun::star::sdbc::ColumnSearch::FULL, // searchable
+ false, // unsignable
+ false, // fixed_prec_scale
+ false, // auto_increment
+ "TINYTEXT", // local type name
+ 0, // minimum scale
+ 0 // maximum scale
+ },
+
+ // ----------- MySQL-Type: CHAR SDBC-Type: CHAR ----------
+ {
+ "CHAR", // Typename
+ com::sun::star::sdbc::DataType::CHAR, // sdbc-type
+ 0xFF, // Precision
+ "'", // Literal prefix
+ "'", // Literal suffix
+ "(M)", // Create params
+ com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable
+ false, // case sensitive
+ com::sun::star::sdbc::ColumnSearch::FULL, // searchable
+ false, // unsignable
+ false, // fixed_prec_scale
+ false, // auto_increment
+ "NUMERIC", // local type name
+ 0, // minimum scale
+ 0 // maximum scale
+ },
+
+ // ----------- MySQL-Type: DECIMAL SDBC-Type: DECIMAL ----------
+ {
+ "DECIMAL", // Typename
+ com::sun::star::sdbc::DataType::DECIMAL, // sdbc-type
+ 17, // Precision
+ "", // Literal prefix
+ "", // Literal suffix
+ "[(M[,D])] [ZEROFILL]", // Create params
+ com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable
+ false, // case sensitive
+ com::sun::star::sdbc::ColumnSearch::FULL, // searchable
+ false, // unsignable
+ false, // fixed_prec_scale
+ true, // auto_increment
+ "DECIMAL", // local type name
+ -308, // minimum scale
+ 308 // maximum scale
+ },
+
+ // ----------- MySQL-Type: NUMERIC SDBC-Type: NUMERIC ----------
+ {
+ "NUMERIC", // Typename
+ com::sun::star::sdbc::DataType::NUMERIC, // sdbc-type
+ 17, // Precision
+ "", // Literal prefix
+ "", // Literal suffix
+ "[(M[,D])] [ZEROFILL]", // Create params
+ com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable
+ false, // case sensitive
+ com::sun::star::sdbc::ColumnSearch::FULL, // searchable
+ false, // unsignable
+ false, // fixed_prec_scale
+ true, // auto_increment
+ "NUMERIC", // local type name
+ -308, // minimum scale
+ 308 // maximum scale
+ },
+
+ // ----------- MySQL-Type: INTEGER SDBC-Type: INTEGER ----------
+ {
+ "INTEGER", // Typename
+ com::sun::star::sdbc::DataType::INTEGER, // sdbc-type
+ 10, // Precision
+ "", // Literal prefix
+ "", // Literal suffix
+ "[(M)] [UNSIGNED] [ZEROFILL]", // Create params
+ com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable
+ false, // case sensitive
+ com::sun::star::sdbc::ColumnSearch::FULL, // searchable
+ true, // unsignable
+ false, // fixed_prec_scale
+ true, // auto_increment
+ "INTEGER", // local type name
+ 0, // minimum scale
+ 0 // maximum scale
+ },
+
+ // ----------- MySQL-Type: INT SDBC-Type: INTEGER ----------
+ {
+ "INT", // Typename
+ com::sun::star::sdbc::DataType::INTEGER, // sdbc-type
+ 10, // Precision
+ "", // Literal prefix
+ "", // Literal suffix
+ "[(M)] [UNSIGNED] [ZEROFILL]", // Create params
+ com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable
+ false, // case sensitive
+ com::sun::star::sdbc::ColumnSearch::FULL, // searchable
+ true, // unsignable
+ false, // fixed_prec_scale
+ true, // auto_increment
+ "INT", // local type name
+ 0, // minimum scale
+ 0 // maximum scale
+ },
+
+ // ----------- MySQL-Type: MEDIUMINT SDBC-Type: INTEGER ----------
+ {
+ "MEDIUMINT", // Typename
+ com::sun::star::sdbc::DataType::INTEGER, // sdbc-type
+ 7, // Precision
+ "", // Literal prefix
+ "", // Literal suffix
+ "[(M)] [UNSIGNED] [ZEROFILL]", // Create params
+ com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable
+ false, // case sensitive
+ com::sun::star::sdbc::ColumnSearch::FULL, // searchable
+ true, // unsignable
+ false, // fixed_prec_scale
+ true, // auto_increment
+ "MEDIUMINT", // local type name
+ 0, // minimum scale
+ 0 // maximum scale
+ },
+
+ // ----------- MySQL-Type: SMALLINT SDBC-Type: INTEGER ----------
+ {
+ "SMALLINT", // Typename
+ com::sun::star::sdbc::DataType::SMALLINT, // sdbc-type
+ 5, // Precision
+ "", // Literal prefix
+ "", // Literal suffix
+ "[(M)] [UNSIGNED] [ZEROFILL]", // Create params
+ com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable
+ false, // case sensitive
+ com::sun::star::sdbc::ColumnSearch::FULL, // searchable
+ true, // unsignable
+ false, // fixed_prec_scale
+ true, // auto_increment
+ "SMALLINT", // local type name
+ 0, // minimum scale
+ 0 // maximum scale
+ },
+
+ // ----------- MySQL-Type: FLOAT SDBC-Type: REAL ----------
+ {
+ "FLOAT", // Typename
+ com::sun::star::sdbc::DataType::REAL, // sdbc-type
+ 10, // Precision
+ "", // Literal prefix
+ "", // Literal suffix
+ "[(M,D)] [ZEROFILL]", // Create params
+ com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable
+ false, // case sensitive
+ com::sun::star::sdbc::ColumnSearch::FULL, // searchable
+ false, // unsignable
+ false, // fixed_prec_scale
+ true, // auto_increment
+ "FLOAT", // local type name
+ -38, // minimum scale
+ 38 // maximum scale
+ },
+
+ // ----------- MySQL-Type: DOUBLE SDBC-Type: DOUBLE ----------
+ {
+ "DOUBLE", // Typename
+ com::sun::star::sdbc::DataType::DOUBLE, // sdbc-type
+ 17, // Precision
+ "", // Literal prefix
+ "", // Literal suffix
+ "[(M,D)] [ZEROFILL]", // Create params
+ com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable
+ false, // case sensitive
+ com::sun::star::sdbc::ColumnSearch::FULL, // searchable
+ false, // unsignable
+ false, // fixed_prec_scale
+ true, // auto_increment
+ "DOUBLE", // local type name
+ -308, // minimum scale
+ 308 // maximum scale
+ },
+
+ // ----------- MySQL-Type: DOUBLE PRECISION SDBC-Type: DOUBLE ----------
+ {
+ "DOUBLE PRECISION", // Typename
+ com::sun::star::sdbc::DataType::DOUBLE, // sdbc-type
+ 17, // Precision
+ "", // Literal prefix
+ "", // Literal suffix
+ "[(M,D)] [ZEROFILL]", // Create params
+ com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable
+ false, // case sensitive
+ com::sun::star::sdbc::ColumnSearch::FULL, // searchable
+ false, // unsignable
+ false, // fixed_prec_scale
+ true, // auto_increment
+ "DOUBLE PRECISION", // local type name
+ -308, // minimum scale
+ 308 // maximum scale
+ },
+
+ // ----------- MySQL-Type: REAL SDBC-Type: DOUBLE ----------
+ {
+ "REAL", // Typename
+ com::sun::star::sdbc::DataType::DOUBLE, // sdbc-type
+ 17, // Precision
+ "", // Literal prefix
+ "", // Literal suffix
+ "[(M,D)] [ZEROFILL]", // Create params
+ com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable
+ false, // case sensitive
+ com::sun::star::sdbc::ColumnSearch::FULL, // searchable
+ false, // unsignable
+ false, // fixed_prec_scale
+ true, // auto_increment
+ "REAL", // local type name
+ -308, // minimum scale
+ 308 // maximum scale
+ },
+
+ // ----------- MySQL-Type: VARCHAR SDBC-Type: VARCHAR ----------
+ {
+ "VARCHAR", // Typename
+ com::sun::star::sdbc::DataType::VARCHAR, // sdbc-type
+ 255, // Precision
+ "'", // Literal prefix
+ "'", // Literal suffix
+ "(M)", // Create params
+ com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable
+ false, // case sensitive
+ com::sun::star::sdbc::ColumnSearch::FULL, // searchable
+ false, // unsignable
+ false, // fixed_prec_scale
+ false, // auto_increment
+ "VARCHAR", // local type name
+ 0, // minimum scale
+ 0 // maximum scale
+ },
+
+ // ----------- MySQL-Type: ENUM SDBC-Type: VARCHAR ----------
+ {
+ "ENUM", // Typename
+ com::sun::star::sdbc::DataType::VARCHAR, // sdbc-type
+ 0xFFFF, // Precision
+ "'", // Literal prefix
+ "'", // Literal suffix
+ "", // Create params
+ com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable
+ false, // case sensitive
+ com::sun::star::sdbc::ColumnSearch::FULL, // searchable
+ false, // unsignable
+ false, // fixed_prec_scale
+ false, // auto_increment
+ "ENUM", // local type name
+ 0, // minimum scale
+ 0 // maximum scale
+ },
+
+ // ----------- MySQL-Type: SET SDBC-Type: VARCHAR ----------
+ {
+ "SET", // Typename
+ com::sun::star::sdbc::DataType::VARCHAR, // sdbc-type
+ 64, // Precision
+ "'", // Literal prefix
+ "'", // Literal suffix
+ "", // Create params
+ com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable
+ false, // case sensitive
+ com::sun::star::sdbc::ColumnSearch::FULL, // searchable
+ false, // unsignable
+ false, // fixed_prec_scale
+ false, // auto_increment
+ "SET", // local type name
+ 0, // minimum scale
+ 0 // maximum scale
+ },
+
+ // ----------- MySQL-Type: DATE SDBC-Type: DATE ----------
+ {
+ "DATE", // Typename
+ com::sun::star::sdbc::DataType::DATE, // sdbc-type
+ 0, // Precision
+ "'", // Literal prefix
+ "'", // Literal suffix
+ "", // Create params
+ com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable
+ false, // case sensitive
+ com::sun::star::sdbc::ColumnSearch::FULL, // searchable
+ false, // unsignable
+ false, // fixed_prec_scale
+ false, // auto_increment
+ "DATE", // local type name
+ 0, // minimum scale
+ 0 // maximum scale
+ },
+
+ // ----------- MySQL-Type: TIME SDBC-Type: TIME ----------
+ {
+ "TIME", // Typename
+ com::sun::star::sdbc::DataType::TIME, // sdbc-type
+ 0, // Precision
+ "'", // Literal prefix
+ "'", // Literal suffix
+ "", // Create params
+ com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable
+ false, // case sensitive
+ com::sun::star::sdbc::ColumnSearch::FULL, // searchable
+ false, // unsignable
+ false, // fixed_prec_scale
+ false, // auto_increment
+ "TIME", // local type name
+ 0, // minimum scale
+ 0 // maximum scale
+ },
+
+ // ----------- MySQL-Type: DATETIME SDBC-Type: TIMESTAMP ----------
+ {
+ "DATETIME", // Typename
+ com::sun::star::sdbc::DataType::TIMESTAMP, // sdbc-type
+ 0, // Precision
+ "'", // Literal prefix
+ "'", // Literal suffix
+ "", // Create params
+ com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable
+ false, // case sensitive
+ com::sun::star::sdbc::ColumnSearch::FULL, // searchable
+ false, // unsignable
+ false, // fixed_prec_scale
+ false, // auto_increment
+ "DATETIME", // local type name
+ 0, // minimum scale
+ 0 // maximum scale
+ },
+
+ // ----------- MySQL-Type: TIMESTAMP SDBC-Type: TIMESTAMP ----------
+ {
+ "TIMESTAMP", // Typename
+ com::sun::star::sdbc::DataType::TIMESTAMP, // sdbc-type
+ 0, // Precision
+ "'", // Literal prefix
+ "'", // Literal suffix
+ "[(M)]", // Create params
+ com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable
+ false, // case sensitive
+ com::sun::star::sdbc::ColumnSearch::FULL, // searchable
+ false, // unsignable
+ false, // fixed_prec_scale
+ false, // auto_increment
+ "TIMESTAMP", // local type name
+ 0, // minimum scale
+ 0 // maximum scale
+ },
+
+ // ----------- MySQL-Type: TIMESTAMP SDBC-Type: TIMESTAMP ----------
+
+ // ----------- MySQL-Type: YEAR SDBC-Type: INTEGER ----------
+ {
+ "YEAR", // Typename
+ com::sun::star::sdbc::DataType::SMALLINT, // sdbc-type
+ 10, // Precision
+ "", // Literal prefix
+ "", // Literal suffix
+ "[(M)] [UNSIGNED] [ZEROFILL]", // Create params
+ com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable
+ false, // case sensitive
+ com::sun::star::sdbc::ColumnSearch::FULL, // searchable
+ true, // unsignable
+ false, // fixed_prec_scale
+ true, // auto_increment
+ "YEAR", // local type name
+ 0, // minimum scale
+ 0 // maximum scale
+ },
+
+ // ----------- MySQL-Type: YEAR SDBC-Type: INTEGER ----------
+ { nullptr, 0, 0, nullptr, nullptr, nullptr, 0, false, 0, false, false, false, nullptr, 0, 0 }
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/mysqlc/mysqlc_types.hxx b/connectivity/source/drivers/mysqlc/mysqlc_types.hxx
new file mode 100644
index 0000000000..9f2db7715f
--- /dev/null
+++ b/connectivity/source/drivers/mysqlc/mysqlc_types.hxx
@@ -0,0 +1,45 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/types.h>
+
+struct TypeInfoDef
+{
+ const char* typeName;
+ sal_Int32 dataType;
+ sal_Int32 precision;
+ const char* literalPrefix;
+ const char* literalSuffix;
+ const char* createParams;
+ sal_Int16 nullable;
+ bool caseSensitive;
+ sal_Int16 searchable;
+ bool isUnsigned;
+ bool fixedPrecScale;
+ bool autoIncrement;
+ const char* localTypeName;
+ sal_Int32 minScale;
+ sal_Int32 maxScale;
+};
+
+extern TypeInfoDef const mysqlc_types[];
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/mysqlc/mysqlc_user.cxx b/connectivity/source/drivers/mysqlc/mysqlc_user.cxx
new file mode 100644
index 0000000000..6e8c3d734a
--- /dev/null
+++ b/connectivity/source/drivers/mysqlc/mysqlc_user.cxx
@@ -0,0 +1,211 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <utility>
+
+#include "mysqlc_user.hxx"
+#include <comphelper/types.hxx>
+#include <connectivity/dbtools.hxx>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbcx/Privilege.hpp>
+#include <com/sun/star/sdbcx/PrivilegeObject.hpp>
+#include <TConnection.hxx>
+
+using namespace ::connectivity;
+using namespace ::connectivity::mysqlc;
+using namespace ::connectivity::sdbcx;
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdbcx;
+
+User::User(css::uno::Reference<css::sdbc::XConnection> xConnection)
+ : OUser(true) // Case Sensitive
+ , m_xConnection(std::move(xConnection))
+{
+}
+
+User::User(css::uno::Reference<css::sdbc::XConnection> xConnection, const OUString& rName)
+ : OUser(rName,
+ true) // Case Sensitive
+ , m_xConnection(std::move(xConnection))
+{
+}
+
+OUserExtend::OUserExtend(const css::uno::Reference<css::sdbc::XConnection>& xConnection,
+ const OUString& rName)
+ : User(xConnection, rName)
+{
+ construct();
+}
+
+void OUserExtend::construct()
+{
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME),
+ PROPERTY_ID_NAME, 0, &m_Name, ::cppu::UnoType<OUString>::get());
+
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PASSWORD),
+ PROPERTY_ID_PASSWORD, 0, &m_Password, ::cppu::UnoType<OUString>::get());
+}
+
+void User::changePassword(const OUString& /* oldPassword */, const OUString& newPassword)
+{
+ css::uno::Reference<XStatement> statement = m_xConnection->createStatement();
+ statement->execute("SET PASSWORD FOR " + m_Name + " = PASSWORD('" + newPassword + "')");
+ ::comphelper::disposeComponent(statement);
+}
+
+cppu::IPropertyArrayHelper* OUserExtend::createArrayHelper() const
+{
+ css::uno::Sequence<css::beans::Property> aProps;
+ describeProperties(aProps);
+ return new cppu::OPropertyArrayHelper(aProps);
+}
+
+cppu::IPropertyArrayHelper& OUserExtend::getInfoHelper()
+{
+ return *OUserExtend_PROP::getArrayHelper();
+}
+
+typedef connectivity::sdbcx::OUser_BASE OUser_BASE_RBHELPER;
+
+sal_Int32 SAL_CALL User::getPrivileges(const OUString& objName, sal_Int32 objType)
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(OUser_BASE_RBHELPER::rBHelper.bDisposed);
+
+ sal_Int32 nRights, nRightsWithGrant;
+ findPrivilegesAndGrantPrivileges(objName, objType, nRights, nRightsWithGrant);
+ return nRights;
+}
+
+void User::findPrivilegesAndGrantPrivileges(const OUString& objName, sal_Int32 objType,
+ sal_Int32& nRights, sal_Int32& nRightsWithGrant)
+{
+ nRightsWithGrant = nRights = 0;
+ // first we need to create the sql stmt to select the privs
+ css::uno::Reference<XDatabaseMetaData> xMeta = m_xConnection->getMetaData();
+ OUString sCatalog, sSchema, sTable;
+ ::dbtools::qualifiedNameComponents(xMeta, objName, sCatalog, sSchema, sTable,
+ ::dbtools::EComposeRule::InDataManipulation);
+ css::uno::Reference<XResultSet> xRes;
+ switch (objType)
+ {
+ case css::sdbcx::PrivilegeObject::TABLE:
+ case css::sdbcx::PrivilegeObject::VIEW:
+ {
+ css::uno::Any aCatalog;
+ if (!sCatalog.isEmpty())
+ aCatalog <<= sCatalog;
+ xRes = xMeta->getTablePrivileges(aCatalog, sSchema, sTable);
+ }
+ break;
+
+ case css::sdbcx::PrivilegeObject::COLUMN:
+ {
+ css::uno::Any aCatalog;
+ if (!sCatalog.isEmpty())
+ aCatalog <<= sCatalog;
+ xRes = xMeta->getColumnPrivileges(aCatalog, sSchema, sTable, "%");
+ }
+ break;
+ }
+
+ if (!xRes.is())
+ return;
+
+ static const char sYes[] = "YES";
+
+ nRightsWithGrant = nRights = 0;
+
+ css::uno::Reference<XRow> xCurrentRow(xRes, css::uno::UNO_QUERY);
+ while (xCurrentRow.is() && xRes->next())
+ {
+ OUString sGrantee = xCurrentRow->getString(5);
+ OUString sPrivilege = xCurrentRow->getString(6);
+ OUString sGrantable = xCurrentRow->getString(7);
+
+ if (!m_Name.equalsIgnoreAsciiCase(sGrantee))
+ continue;
+
+ if (sPrivilege.equalsIgnoreAsciiCase("SELECT"))
+ {
+ nRights |= Privilege::SELECT;
+ if (sGrantable.equalsIgnoreAsciiCase(sYes))
+ nRightsWithGrant |= Privilege::SELECT;
+ }
+ else if (sPrivilege.equalsIgnoreAsciiCase("INSERT"))
+ {
+ nRights |= Privilege::INSERT;
+ if (sGrantable.equalsIgnoreAsciiCase(sYes))
+ nRightsWithGrant |= Privilege::INSERT;
+ }
+ else if (sPrivilege.equalsIgnoreAsciiCase("UPDATE"))
+ {
+ nRights |= Privilege::UPDATE;
+ if (sGrantable.equalsIgnoreAsciiCase(sYes))
+ nRightsWithGrant |= Privilege::UPDATE;
+ }
+ else if (sPrivilege.equalsIgnoreAsciiCase("DELETE"))
+ {
+ nRights |= Privilege::DELETE;
+ if (sGrantable.equalsIgnoreAsciiCase(sYes))
+ nRightsWithGrant |= Privilege::DELETE;
+ }
+ else if (sPrivilege.equalsIgnoreAsciiCase("READ"))
+ {
+ nRights |= Privilege::READ;
+ if (sGrantable.equalsIgnoreAsciiCase(sYes))
+ nRightsWithGrant |= Privilege::READ;
+ }
+ else if (sPrivilege.equalsIgnoreAsciiCase("CREATE"))
+ {
+ nRights |= Privilege::CREATE;
+ if (sGrantable.equalsIgnoreAsciiCase(sYes))
+ nRightsWithGrant |= Privilege::CREATE;
+ }
+ else if (sPrivilege.equalsIgnoreAsciiCase("ALTER"))
+ {
+ nRights |= Privilege::ALTER;
+ if (sGrantable.equalsIgnoreAsciiCase(sYes))
+ nRightsWithGrant |= Privilege::ALTER;
+ }
+ else if (sPrivilege.equalsIgnoreAsciiCase("REFERENCES"))
+ {
+ nRights |= Privilege::REFERENCE;
+ if (sGrantable.equalsIgnoreAsciiCase(sYes))
+ nRightsWithGrant |= Privilege::REFERENCE;
+ }
+ else if (sPrivilege.equalsIgnoreAsciiCase("DROP"))
+ {
+ nRights |= Privilege::DROP;
+ if (sGrantable.equalsIgnoreAsciiCase(sYes))
+ nRightsWithGrant |= Privilege::DROP;
+ }
+ }
+ ::comphelper::disposeComponent(xRes);
+}
+
+sal_Int32 SAL_CALL User::getGrantablePrivileges(const OUString& objName, sal_Int32 objType)
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(OUser_BASE_RBHELPER::rBHelper.bDisposed);
+
+ sal_Int32 nRights, nRightsWithGrant;
+ findPrivilegesAndGrantPrivileges(objName, objType, nRights, nRightsWithGrant);
+ return nRightsWithGrant;
+}
+
+//----- IRefreshableGroups ----------------------------------------------------
+void User::refreshGroups()
+{
+ // TODO: implement.
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/connectivity/source/drivers/mysqlc/mysqlc_user.hxx b/connectivity/source/drivers/mysqlc/mysqlc_user.hxx
new file mode 100644
index 0000000000..6bebbaa64a
--- /dev/null
+++ b/connectivity/source/drivers/mysqlc/mysqlc_user.hxx
@@ -0,0 +1,71 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include <sdbcx/VUser.hxx>
+#include <com/sun/star/sdbc/XConnection.hpp>
+
+namespace connectivity::mysqlc
+{
+/**
+* This implements com.sun.star.sdbcx.Container.
+*/
+class User : public ::connectivity::sdbcx::OUser
+{
+ css::uno::Reference<css::sdbc::XConnection> m_xConnection;
+
+public:
+ /**
+ * Create a "new" descriptor, which isn't yet in the database.
+ */
+ User(css::uno::Reference<css::sdbc::XConnection> xConnection);
+ /**
+ * For a user that already exists in the db.
+ */
+ User(css::uno::Reference<css::sdbc::XConnection> xConnection, const OUString& rName);
+
+ // XAuthorizable
+ virtual void SAL_CALL changePassword(const OUString&, const OUString& newPassword) override;
+ virtual sal_Int32 SAL_CALL getPrivileges(const OUString&, sal_Int32) override;
+ // return the privileges and additional the grant rights
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void findPrivilegesAndGrantPrivileges(const OUString& objName, sal_Int32 objType,
+ sal_Int32& nRights, sal_Int32& nRightsWithGrant);
+
+ virtual sal_Int32 SAL_CALL getGrantablePrivileges(const OUString&, sal_Int32) override;
+
+ // IRefreshableGroups::
+ virtual void refreshGroups() override;
+};
+
+class OUserExtend;
+typedef ::comphelper::OPropertyArrayUsageHelper<OUserExtend> OUserExtend_PROP;
+
+class OUserExtend : public User, public OUserExtend_PROP
+{
+ OUString m_Password;
+
+protected:
+ // OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper() const override;
+ // OPropertySetHelper
+ virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override;
+
+public:
+ OUserExtend(const css::uno::Reference<css::sdbc::XConnection>& _xConnection,
+ const OUString& rName);
+
+ virtual void construct() override;
+};
+
+} // namespace connectivity::mysqlc
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/connectivity/source/drivers/mysqlc/mysqlc_users.cxx b/connectivity/source/drivers/mysqlc/mysqlc_users.cxx
new file mode 100644
index 0000000000..5e494226a9
--- /dev/null
+++ b/connectivity/source/drivers/mysqlc/mysqlc_users.cxx
@@ -0,0 +1,95 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <utility>
+
+#include "mysqlc_user.hxx"
+#include "mysqlc_users.hxx"
+#include <comphelper/types.hxx>
+#include <connectivity/dbtools.hxx>
+#include <TConnection.hxx>
+
+using namespace ::connectivity;
+using namespace ::connectivity::mysqlc;
+using namespace ::connectivity::sdbcx;
+using namespace ::cppu;
+using namespace ::osl;
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::uno;
+
+Users::Users(const uno::Reference<XDatabaseMetaData>& rMetaData, OWeakObject& rParent,
+ Mutex& rMutex, ::std::vector<OUString> const& rNames)
+ : OCollection(rParent, true, rMutex, rNames)
+ , m_xMetaData(rMetaData)
+{
+}
+
+//----- OCollection -----------------------------------------------------------
+void Users::impl_refresh()
+{
+ // TODO: IMPLEMENT ME
+}
+
+ObjectType Users::createObject(const OUString& rName)
+{
+ return new OUserExtend(m_xMetaData->getConnection(), rName);
+}
+
+uno::Reference<XPropertySet> Users::createDescriptor()
+{
+ // There is some internal magic so that the same class can be used as either
+ // a descriptor or as a normal user. See VUser.cxx for the details. In our
+ // case we just need to ensure we use the correct constructor.
+ return new OUserExtend(m_xMetaData->getConnection(), "");
+}
+
+//----- XAppend ---------------------------------------------------------------
+ObjectType Users::appendObject(const OUString& rName,
+ const uno::Reference<XPropertySet>& descriptor)
+{
+ OUString aSql("GRANT USAGE ON * TO ");
+ OUString aQuote = m_xMetaData->getIdentifierQuoteString();
+ aSql += ::dbtools::quoteName(aQuote, rName) + " @\"%\" ";
+ OUString sPassword;
+ descriptor->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PASSWORD))
+ >>= sPassword;
+ if (!sPassword.isEmpty())
+ {
+ aSql += " IDENTIFIED BY '" + sPassword + "'";
+ }
+
+ Reference<XStatement> statement = m_xMetaData->getConnection()->createStatement();
+ if (statement.is())
+ statement->execute(aSql);
+ ::comphelper::disposeComponent(statement);
+
+ return createObject(rName);
+}
+
+//----- XDrop -----------------------------------------------------------------
+void Users::dropObject(sal_Int32 nPosition, const OUString& rName)
+{
+ uno::Reference<XPropertySet> xUser(getObject(nPosition));
+
+ if (!ODescriptor::isNew(xUser))
+ {
+ Reference<XStatement> statement = m_xMetaData->getConnection()->createStatement();
+ if (statement.is())
+ {
+ statement->execute("DROP USER " + rName);
+ ::comphelper::disposeComponent(statement);
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/connectivity/source/drivers/mysqlc/mysqlc_users.hxx b/connectivity/source/drivers/mysqlc/mysqlc_users.hxx
new file mode 100644
index 0000000000..d4c4d3558e
--- /dev/null
+++ b/connectivity/source/drivers/mysqlc/mysqlc_users.hxx
@@ -0,0 +1,43 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include <connectivity/sdbcx/VCollection.hxx>
+#include <com/sun/star/sdbc/XDatabaseMetaData.hpp>
+
+namespace connectivity::mysqlc
+{
+class Users : public ::connectivity::sdbcx::OCollection
+{
+ css::uno::Reference<css::sdbc::XDatabaseMetaData> m_xMetaData;
+
+protected:
+ // OCollection
+ virtual void impl_refresh() override;
+ virtual ::connectivity::sdbcx::ObjectType createObject(const OUString& rName) override;
+ virtual css::uno::Reference<css::beans::XPropertySet> createDescriptor() override;
+ virtual ::connectivity::sdbcx::ObjectType
+ appendObject(const OUString& rName,
+ const css::uno::Reference<css::beans::XPropertySet>& rDescriptor) override;
+
+public:
+ Users(const css::uno::Reference<css::sdbc::XDatabaseMetaData>& rMetaData,
+ ::cppu::OWeakObject& rParent, ::osl::Mutex& rMutex,
+ ::std::vector<OUString> const& rNames);
+
+ // TODO: we should also implement XDataDescriptorFactory, XRefreshable,
+ // XAppend, etc., but all are optional.
+
+ // XDrop
+ virtual void dropObject(sal_Int32 nPosition, const OUString& rName) override;
+};
+} // namespace connectivity::mysqlc
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/connectivity/source/drivers/mysqlc/mysqlc_view.cxx b/connectivity/source/drivers/mysqlc/mysqlc_view.cxx
new file mode 100644
index 0000000000..86837381d2
--- /dev/null
+++ b/connectivity/source/drivers/mysqlc/mysqlc_view.cxx
@@ -0,0 +1,98 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "mysqlc_view.hxx"
+
+#include <propertyids.hxx>
+
+#include <com/sun/star/sdbc/XRow.hpp>
+
+namespace connectivity::mysqlc
+{
+View::View(const css::uno::Reference<css::sdbc::XConnection>& _rxConnection, bool _bCaseSensitive,
+ const OUString& _rSchemaName, const OUString& _rName)
+ : View_Base(_bCaseSensitive, _rName, _rxConnection->getMetaData(), OUString(), _rSchemaName,
+ OUString())
+ , m_xConnection(_rxConnection)
+{
+}
+
+View::~View() {}
+
+void SAL_CALL View::acquire() noexcept { View_Base::acquire(); };
+void SAL_CALL View::release() noexcept { View_Base::release(); };
+css::uno::Any SAL_CALL View::queryInterface(const css::uno::Type& _rType)
+{
+ css::uno::Any aReturn = View_Base::queryInterface(_rType);
+ if (!aReturn.hasValue())
+ aReturn = View_IBASE::queryInterface(_rType);
+ return aReturn;
+}
+
+css::uno::Sequence<css::uno::Type> SAL_CALL View::getTypes()
+{
+ return ::comphelper::concatSequences(View_Base::getTypes(), View_IBASE::getTypes());
+}
+
+css::uno::Sequence<sal_Int8> SAL_CALL View::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+void SAL_CALL View::alterCommand(const OUString& _rNewCommand)
+{
+ OUString aCommand = "ALTER VIEW " + m_SchemaName + "." + m_Name + " AS " + _rNewCommand;
+ m_xMetaData->getConnection()->createStatement()->execute(aCommand);
+}
+
+void SAL_CALL View::getFastPropertyValue(css::uno::Any& _rValue, sal_Int32 _nHandle) const
+{
+ if (_nHandle == PROPERTY_ID_COMMAND)
+ {
+ // retrieve the very current command, don't rely on the base classes cached value
+ // (which we initialized empty, anyway)
+ _rValue <<= impl_getCommand();
+ return;
+ }
+
+ View_Base::getFastPropertyValue(_rValue, _nHandle);
+}
+
+OUString View::impl_getCommand() const
+{
+ OUString aCommand("SELECT VIEW_DEFINITION FROM INFORMATION_SCHEMA.VIEWS WHERE TABLE_SCHEMA = '"
+ + m_SchemaName + "' AND TABLE_NAME = '" + m_Name + "'");
+ //::utl::SharedUNOComponent< XStatement > xStatement; xStatement.set( m_xConnection->createStatement(), UNO_QUERY_THROW );
+ css::uno::Reference<css::sdbc::XResultSet> xResult(
+ m_xMetaData->getConnection()->createStatement()->executeQuery(aCommand),
+ css::uno::UNO_SET_THROW);
+ if (!xResult->next())
+ {
+ // hmm. There is no view the name as we know it. Can only mean some other instance
+ // dropped this view meanwhile...
+ std::abort();
+ }
+
+ css::uno::Reference<css::sdbc::XRow> xRow(xResult, css::uno::UNO_QUERY_THROW);
+ return xRow->getString(1);
+}
+
+} // namespace connectivity::mysqlc
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/mysqlc/mysqlc_view.hxx b/connectivity/source/drivers/mysqlc/mysqlc_view.hxx
new file mode 100644
index 0000000000..8450152499
--- /dev/null
+++ b/connectivity/source/drivers/mysqlc/mysqlc_view.hxx
@@ -0,0 +1,72 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <connectivity/sdbcx/VView.hxx>
+
+#include <com/sun/star/sdbcx/XAlterView.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+
+#include <comphelper/sequence.hxx>
+#include <cppuhelper/implbase1.hxx>
+
+namespace connectivity::mysqlc
+{
+typedef ::connectivity::sdbcx::OView View_Base;
+typedef ::cppu::ImplHelper1<css::sdbcx::XAlterView> View_IBASE;
+
+class View : public View_Base, public View_IBASE
+{
+public:
+ View(const css::uno::Reference<css::sdbc::XConnection>& _rxConnection, bool _bCaseSensitive,
+ const OUString& _rSchemaName, const OUString& _rName);
+
+ // UNO
+ virtual css::uno::Any SAL_CALL queryInterface(const css::uno::Type& aType) override;
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+
+ virtual css::uno::Sequence<css::uno::Type> SAL_CALL getTypes() override;
+ virtual css::uno::Sequence<sal_Int8> SAL_CALL getImplementationId() override;
+
+ // XAlterView
+ virtual void SAL_CALL alterCommand(const OUString& NewCommand) override;
+
+protected:
+ virtual ~View() override;
+
+protected:
+ // OPropertyContainer
+ virtual void SAL_CALL getFastPropertyValue(css::uno::Any& _rValue,
+ sal_Int32 _nHandle) const override;
+
+private:
+ /** retrieves the current command of the View */
+ OUString impl_getCommand() const;
+
+private:
+ css::uno::Reference<css::sdbc::XConnection> m_xConnection;
+
+ using View_Base::getFastPropertyValue;
+};
+
+} // namespace connectivity::mysqlc
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/mysqlc/mysqlc_views.cxx b/connectivity/source/drivers/mysqlc/mysqlc_views.cxx
new file mode 100644
index 0000000000..1c79c9225d
--- /dev/null
+++ b/connectivity/source/drivers/mysqlc/mysqlc_views.cxx
@@ -0,0 +1,113 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "mysqlc_tables.hxx"
+#include "mysqlc_views.hxx"
+#include "mysqlc_view.hxx"
+#include "mysqlc_catalog.hxx"
+#include <connectivity/dbtools.hxx>
+#include <comphelper/types.hxx>
+#include <TConnection.hxx>
+
+connectivity::mysqlc::Views::Views(const css::uno::Reference<css::sdbc::XConnection>& _rxConnection,
+ ::cppu::OWeakObject& _rParent, ::osl::Mutex& _rMutex,
+ const ::std::vector<OUString>& _rVector)
+ : sdbcx::OCollection(_rParent, true, _rMutex, _rVector)
+ , m_xConnection(_rxConnection)
+ , m_xMetaData(_rxConnection->getMetaData())
+{
+}
+
+connectivity::sdbcx::ObjectType connectivity::mysqlc::Views::createObject(const OUString& _rName)
+{
+ OUString sCatalog, sSchema, sTable;
+ ::dbtools::qualifiedNameComponents(m_xMetaData, _rName, sCatalog, sSchema, sTable,
+ ::dbtools::EComposeRule::InDataManipulation);
+ return new View(m_xConnection, isCaseSensitive(), sSchema, sTable);
+}
+
+void connectivity::mysqlc::Views::impl_refresh()
+{
+ static_cast<Catalog&>(m_rParent).refreshViews();
+}
+
+css::uno::Reference<css::beans::XPropertySet> connectivity::mysqlc::Views::createDescriptor()
+{
+ return new connectivity::sdbcx::OView(true, m_xMetaData);
+}
+
+// XAppend
+connectivity::sdbcx::ObjectType connectivity::mysqlc::Views::appendObject(
+ const OUString& _rForName, const css::uno::Reference<css::beans::XPropertySet>& descriptor)
+{
+ createView(descriptor);
+ return createObject(_rForName);
+}
+
+// XDrop
+void connectivity::mysqlc::Views::dropObject(sal_Int32 _nPos, const OUString& /*_sElementName*/)
+{
+ css::uno::Reference<XInterface> xObject(getObject(_nPos));
+ bool bIsNew = connectivity::sdbcx::ODescriptor::isNew(xObject);
+ if (!bIsNew)
+ {
+ OUString aSql("DROP VIEW");
+
+ css::uno::Reference<css::beans::XPropertySet> xProp(xObject, css::uno::UNO_QUERY);
+ aSql += ::dbtools::composeTableName(m_xMetaData, xProp,
+ ::dbtools::EComposeRule::InTableDefinitions, true);
+
+ css::uno::Reference<css::sdbc::XConnection> xConnection = m_xMetaData->getConnection();
+ css::uno::Reference<css::sdbc::XStatement> xStmt = xConnection->createStatement();
+ xStmt->execute(aSql);
+ ::comphelper::disposeComponent(xStmt);
+ }
+}
+
+void connectivity::mysqlc::Views::createView(
+ const css::uno::Reference<css::beans::XPropertySet>& descriptor)
+{
+ css::uno::Reference<css::sdbc::XConnection> xConnection = m_xMetaData->getConnection();
+
+ OUString sCommand;
+ descriptor->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_COMMAND))
+ >>= sCommand;
+
+ OUString aSql = "CREATE VIEW "
+ + ::dbtools::composeTableName(m_xMetaData, descriptor,
+ ::dbtools::EComposeRule::InTableDefinitions, true)
+ + " AS " + sCommand;
+
+ css::uno::Reference<css::sdbc::XStatement> xStmt = xConnection->createStatement();
+ if (xStmt.is())
+ {
+ xStmt->execute(aSql);
+ ::comphelper::disposeComponent(xStmt);
+ }
+ connectivity::mysqlc::Tables* pTables = static_cast<connectivity::mysqlc::Tables*>(
+ static_cast<connectivity::mysqlc::Catalog&>(m_rParent).getPrivateTables());
+ if (pTables)
+ {
+ OUString sName = ::dbtools::composeTableName(
+ m_xMetaData, descriptor, ::dbtools::EComposeRule::InDataManipulation, false);
+ pTables->appendNew(sName);
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/mysqlc/mysqlc_views.hxx b/connectivity/source/drivers/mysqlc/mysqlc_views.hxx
new file mode 100644
index 0000000000..14570fc8d9
--- /dev/null
+++ b/connectivity/source/drivers/mysqlc/mysqlc_views.hxx
@@ -0,0 +1,50 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <connectivity/sdbcx/VCollection.hxx>
+#include <com/sun/star/sdbc/XDatabaseMetaData.hpp>
+namespace connectivity::mysqlc
+{
+class Views final : public connectivity::sdbcx::OCollection
+{
+ css::uno::Reference<css::sdbc::XConnection> m_xConnection;
+ css::uno::Reference<css::sdbc::XDatabaseMetaData> m_xMetaData;
+
+ // OCollection
+ virtual connectivity::sdbcx::ObjectType createObject(const OUString& _rName) override;
+ virtual void impl_refresh() override;
+ virtual css::uno::Reference<css::beans::XPropertySet> createDescriptor() override;
+ virtual sdbcx::ObjectType
+ appendObject(const OUString& _rForName,
+ const css::uno::Reference<css::beans::XPropertySet>& descriptor) override;
+
+ void createView(const css::uno::Reference<css::beans::XPropertySet>& descriptor);
+
+public:
+ Views(const css::uno::Reference<css::sdbc::XConnection>& _rxConnection,
+ ::cppu::OWeakObject& _rParent, ::osl::Mutex& _rMutex,
+ const ::std::vector<OUString>& _rVector);
+
+ // XDrop
+ virtual void dropObject(sal_Int32 _nPos, const OUString& _sElementName) override;
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/odbc/OConnection.cxx b/connectivity/source/drivers/odbc/OConnection.cxx
new file mode 100644
index 0000000000..7ae8c46802
--- /dev/null
+++ b/connectivity/source/drivers/odbc/OConnection.cxx
@@ -0,0 +1,547 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <odbc/OTools.hxx>
+#include <odbc/OConnection.hxx>
+#include <odbc/ODatabaseMetaData.hxx>
+#include <odbc/OFunctions.hxx>
+#include <odbc/ODriver.hxx>
+#include <odbc/OStatement.hxx>
+#include <odbc/OPreparedStatement.hxx>
+#include <connectivity/dbcharset.hxx>
+#include <connectivity/dbexception.hxx>
+
+#include <sal/log.hxx>
+
+#include <string.h>
+
+using namespace connectivity::odbc;
+using namespace connectivity;
+using namespace dbtools;
+
+
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::sdbc;
+
+OConnection::OConnection(const SQLHANDLE _pDriverHandle,ODBCDriver* _pDriver)
+ :m_xDriver(_pDriver)
+ ,m_aConnectionHandle(nullptr)
+ ,m_pDriverHandleCopy(_pDriverHandle)
+ ,m_nStatementCount(0)
+ ,m_bClosed(false)
+ ,m_bUseCatalog(false)
+ ,m_bUseOldDateFormat(false)
+ ,m_bIgnoreDriverPrivileges(false)
+ ,m_bPreventGetVersionColumns(false)
+ ,m_bReadOnly(true)
+{
+}
+
+OConnection::~OConnection()
+{
+ if(!isClosed( ))
+ close();
+
+ if ( SQL_NULL_HANDLE == m_aConnectionHandle )
+ return;
+
+ SQLRETURN rc;
+
+ if (!m_bClosed)
+ {
+ rc = N3SQLDisconnect( m_aConnectionHandle );
+ OSL_ENSURE( rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO, "Failure from SQLDisconnect" );
+ }
+
+ rc = N3SQLFreeHandle( SQL_HANDLE_DBC, m_aConnectionHandle );
+ OSL_ENSURE( rc == SQL_SUCCESS , "Failure from SQLFreeHandle for connection");
+
+ m_aConnectionHandle = SQL_NULL_HANDLE;
+}
+
+oslGenericFunction OConnection::getOdbcFunction(ODBC3SQLFunctionId _nIndex) const
+{
+ OSL_ENSURE(m_xDriver, "OConnection::getOdbcFunction: m_xDriver is null!");
+ return m_xDriver->getOdbcFunction(_nIndex);
+}
+
+SQLRETURN OConnection::OpenConnection(const OUString& aConnectStr, sal_Int32 nTimeOut, bool bSilent)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ if (m_aConnectionHandle == SQL_NULL_HANDLE)
+ return -1;
+
+ SQLRETURN nSQLRETURN = 0;
+ SDB_ODBC_CHAR szConnStrOut[4096] = {};
+ SDB_ODBC_CHAR szConnStrIn[2048] = {};
+ SQLSMALLINT cbConnStrOut;
+ OString aConStr(OUStringToOString(aConnectStr,getTextEncoding()));
+ memcpy(szConnStrIn, aConStr.getStr(), std::min<sal_Int32>(sal_Int32(2048),aConStr.getLength()));
+
+#ifndef MACOSX
+ N3SQLSetConnectAttr(m_aConnectionHandle,SQL_ATTR_LOGIN_TIMEOUT,reinterpret_cast<SQLPOINTER>(nTimeOut),SQL_IS_UINTEGER);
+#else
+ (void)nTimeOut; /* WaE */
+#endif
+
+#ifdef LINUX
+ (void) bSilent;
+ nSQLRETURN = N3SQLDriverConnect(m_aConnectionHandle,
+ nullptr,
+ szConnStrIn,
+ static_cast<SQLSMALLINT>(std::min(sal_Int32(2048),aConStr.getLength())),
+ szConnStrOut,
+ SQLSMALLINT(sizeof(szConnStrOut)/sizeof(SDB_ODBC_CHAR)) -1,
+ &cbConnStrOut,
+ SQL_DRIVER_NOPROMPT);
+ if (nSQLRETURN == SQL_ERROR || nSQLRETURN == SQL_NO_DATA || SQL_SUCCESS_WITH_INFO == nSQLRETURN)
+ return nSQLRETURN;
+#else
+
+ SQLUSMALLINT nSilent = bSilent ? SQL_DRIVER_NOPROMPT : SQL_DRIVER_COMPLETE;
+ nSQLRETURN = N3SQLDriverConnect(m_aConnectionHandle,
+ nullptr,
+ szConnStrIn,
+ static_cast<SQLSMALLINT>(std::min<sal_Int32>(sal_Int32(2048),aConStr.getLength())),
+ szConnStrOut,
+ SQLSMALLINT(sizeof szConnStrOut),
+ &cbConnStrOut,
+ nSilent);
+ if (nSQLRETURN == SQL_ERROR || nSQLRETURN == SQL_NO_DATA)
+ return nSQLRETURN;
+
+ m_bClosed = false;
+
+#endif //LINUX
+
+ try
+ {
+ OUString aVal;
+ OTools::GetInfo(this,m_aConnectionHandle,SQL_DATA_SOURCE_READ_ONLY,aVal,*this,getTextEncoding());
+ m_bReadOnly = aVal == "Y";
+ }
+ catch(Exception&)
+ {
+ m_bReadOnly = true;
+ }
+ try
+ {
+ OUString sVersion;
+ OTools::GetInfo(this,m_aConnectionHandle,SQL_DRIVER_ODBC_VER,sVersion,*this,getTextEncoding());
+ m_bUseOldDateFormat = sVersion == "02.50" || sVersion == "02.00";
+ }
+ catch(Exception&)
+ {
+ }
+
+
+ // autocommit is always default
+
+ if (!m_bReadOnly)
+ N3SQLSetConnectAttr(m_aConnectionHandle,SQL_ATTR_AUTOCOMMIT, reinterpret_cast<SQLPOINTER>(SQL_AUTOCOMMIT_ON),SQL_IS_INTEGER);
+
+ return nSQLRETURN;
+}
+
+SQLRETURN OConnection::Construct(const OUString& url,const Sequence< PropertyValue >& info)
+{
+ m_aConnectionHandle = SQL_NULL_HANDLE;
+ m_sURL = url;
+ setConnectionInfo(info);
+
+ N3SQLAllocHandle(SQL_HANDLE_DBC,m_pDriverHandleCopy,&m_aConnectionHandle);
+ if(m_aConnectionHandle == SQL_NULL_HANDLE)
+ throw SQLException();
+
+ sal_Int32 nLen = url.indexOf(':');
+ nLen = url.indexOf(':',nLen+2);
+ OUString aDSN("DSN="), aUID, aPWD, aSysDrvSettings;
+ aDSN += url.subView(nLen+1);
+
+ sal_Int32 nTimeout = 20;
+ bool bSilent = true;
+ const PropertyValue *pBegin = info.getConstArray();
+ const PropertyValue *pEnd = pBegin + info.getLength();
+ for(;pBegin != pEnd;++pBegin)
+ {
+ if( pBegin->Name == "Timeout")
+ {
+ if( ! (pBegin->Value >>= nTimeout) )
+ SAL_WARN("connectivity.odbc", "Construct: unable to get property Timeout");
+ }
+ else if( pBegin->Name == "Silent")
+ {
+ if( ! (pBegin->Value >>= bSilent) )
+ SAL_WARN("connectivity.odbc", "Construct: unable to get property Silent");
+ }
+ else if( pBegin->Name == "IgnoreDriverPrivileges")
+ {
+ if( ! (pBegin->Value >>= m_bIgnoreDriverPrivileges) )
+ SAL_WARN("connectivity.odbc", "Construct: unable to get property IgnoreDriverPrivileges");
+ }
+ else if( pBegin->Name == "PreventGetVersionColumns")
+ {
+ if( ! (pBegin->Value >>= m_bPreventGetVersionColumns) )
+ SAL_WARN("connectivity.odbc", "Construct: unable to get property PreventGetVersionColumns");
+ }
+ else if( pBegin->Name == "IsAutoRetrievingEnabled")
+ {
+ bool bAutoRetrievingEnabled = false;
+ if( ! (pBegin->Value >>= bAutoRetrievingEnabled) )
+ SAL_WARN("connectivity.odbc", "Construct: unable to get property IsAutoRetrievingEnabled");
+ enableAutoRetrievingEnabled(bAutoRetrievingEnabled);
+ }
+ else if( pBegin->Name == "AutoRetrievingStatement")
+ {
+ OUString sGeneratedValueStatement;
+ if( ! (pBegin->Value >>= sGeneratedValueStatement) )
+ SAL_WARN("connectivity.odbc", "Construct: unable to get property AutoRetrievingStatement");
+ setAutoRetrievingStatement(sGeneratedValueStatement);
+ }
+ else if( pBegin->Name == "user")
+ {
+ if( ! (pBegin->Value >>= aUID) )
+ SAL_WARN("connectivity.odbc", "Construct: unable to get property user");
+ aDSN += ";UID=" + aUID;
+ }
+ else if( pBegin->Name == "password")
+ {
+ if( ! (pBegin->Value >>= aPWD) )
+ SAL_WARN("connectivity.odbc", "Construct: unable to get property password");
+ aDSN += ";PWD=" + aPWD;
+ }
+ else if( pBegin->Name == "UseCatalog")
+ {
+ if( !( pBegin->Value >>= m_bUseCatalog) )
+ SAL_WARN("connectivity.odbc", "Construct: unable to get property UseCatalog");
+ }
+ else if( pBegin->Name == "SystemDriverSettings")
+ {
+ if( ! (pBegin->Value >>= aSysDrvSettings) )
+ SAL_WARN("connectivity.odbc", "Construct: unable to get property SystemDriverSettings");
+ aDSN += ";" + aSysDrvSettings;
+ }
+ else if( pBegin->Name == "CharSet")
+ {
+ OUString sIanaName;
+ if( ! (pBegin->Value >>= sIanaName) )
+ SAL_WARN("connectivity.odbc", "Construct: unable to get property CharSet");
+
+ ::dbtools::OCharsetMap aLookupIanaName;
+ ::dbtools::OCharsetMap::const_iterator aLookup = aLookupIanaName.findIanaName(sIanaName);
+ if (aLookup != aLookupIanaName.end())
+ m_nTextEncoding = (*aLookup).getEncoding();
+ else
+ m_nTextEncoding = RTL_TEXTENCODING_DONTKNOW;
+ if(m_nTextEncoding == RTL_TEXTENCODING_DONTKNOW)
+ m_nTextEncoding = osl_getThreadTextEncoding();
+ }
+ }
+ m_sUser = aUID;
+
+ SQLRETURN nSQLRETURN = OpenConnection(aDSN,nTimeout, bSilent);
+ if (nSQLRETURN == SQL_ERROR || nSQLRETURN == SQL_NO_DATA)
+ {
+ OTools::ThrowException(this,nSQLRETURN,m_aConnectionHandle,SQL_HANDLE_DBC,*this,false);
+ }
+ return nSQLRETURN;
+}
+// XServiceInfo
+
+IMPLEMENT_SERVICE_INFO(OConnection, "com.sun.star.sdbc.drivers.odbc.OConnection", "com.sun.star.sdbc.Connection")
+
+
+Reference< XStatement > SAL_CALL OConnection::createStatement( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OConnection_BASE::rBHelper.bDisposed);
+
+ Reference< XStatement > xReturn = new OStatement(this);
+ m_aStatements.push_back(WeakReferenceHelper(xReturn));
+ return xReturn;
+}
+
+Reference< XPreparedStatement > SAL_CALL OConnection::prepareStatement( const OUString& sql )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OConnection_BASE::rBHelper.bDisposed);
+
+ Reference< XPreparedStatement > xReturn = new OPreparedStatement(this,sql);
+ m_aStatements.push_back(WeakReferenceHelper(xReturn));
+ return xReturn;
+}
+
+Reference< XPreparedStatement > SAL_CALL OConnection::prepareCall( const OUString& /*sql*/ )
+{
+ ::dbtools::throwFeatureNotImplementedSQLException( "XConnection::prepareCall", *this );
+ return nullptr;
+}
+
+OUString SAL_CALL OConnection::nativeSQL( const OUString& sql )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ OString aSql(OUStringToOString(sql,getTextEncoding()));
+ char pOut[2048];
+ SQLINTEGER nOutLen;
+ OTools::ThrowException(this,N3SQLNativeSql(m_aConnectionHandle,reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(aSql.getStr())),aSql.getLength(),reinterpret_cast<SDB_ODBC_CHAR*>(pOut),sizeof pOut - 1,&nOutLen),m_aConnectionHandle,SQL_HANDLE_DBC,*this);
+ return OUString(pOut,nOutLen,getTextEncoding());
+}
+
+void SAL_CALL OConnection::setAutoCommit( sal_Bool autoCommit )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OConnection_BASE::rBHelper.bDisposed);
+
+
+ OTools::ThrowException(this,N3SQLSetConnectAttr(m_aConnectionHandle,
+ SQL_ATTR_AUTOCOMMIT,
+ reinterpret_cast<SQLPOINTER>((autoCommit) ? SQL_AUTOCOMMIT_ON : SQL_AUTOCOMMIT_OFF) ,SQL_IS_INTEGER),
+ m_aConnectionHandle,SQL_HANDLE_DBC,*this);
+}
+
+sal_Bool SAL_CALL OConnection::getAutoCommit( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OConnection_BASE::rBHelper.bDisposed);
+
+
+ sal_uInt32 nOption = 0;
+ OTools::ThrowException(this,N3SQLGetConnectAttr(m_aConnectionHandle,
+ SQL_ATTR_AUTOCOMMIT, &nOption,0,nullptr),m_aConnectionHandle,SQL_HANDLE_DBC,*this);
+ return nOption == SQL_AUTOCOMMIT_ON ;
+}
+
+void SAL_CALL OConnection::commit( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OConnection_BASE::rBHelper.bDisposed);
+
+
+ OTools::ThrowException(this,N3SQLEndTran(SQL_HANDLE_DBC,m_aConnectionHandle,SQL_COMMIT),m_aConnectionHandle,SQL_HANDLE_DBC,*this);
+}
+
+void SAL_CALL OConnection::rollback( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OConnection_BASE::rBHelper.bDisposed);
+
+
+ OTools::ThrowException(this,N3SQLEndTran(SQL_HANDLE_DBC,m_aConnectionHandle,SQL_ROLLBACK),m_aConnectionHandle,SQL_HANDLE_DBC,*this);
+}
+
+sal_Bool SAL_CALL OConnection::isClosed( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ return OConnection_BASE::rBHelper.bDisposed;
+}
+
+Reference< XDatabaseMetaData > SAL_CALL OConnection::getMetaData( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OConnection_BASE::rBHelper.bDisposed);
+
+ Reference< XDatabaseMetaData > xMetaData = m_xMetaData;
+ if(!xMetaData.is())
+ {
+ xMetaData = new ODatabaseMetaData(m_aConnectionHandle,this);
+ m_xMetaData = xMetaData;
+ }
+
+ return xMetaData;
+}
+
+void SAL_CALL OConnection::setReadOnly( sal_Bool readOnly )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OConnection_BASE::rBHelper.bDisposed);
+
+
+ OTools::ThrowException(this,
+ N3SQLSetConnectAttr(m_aConnectionHandle,SQL_ATTR_ACCESS_MODE,reinterpret_cast< SQLPOINTER >( readOnly ),SQL_IS_INTEGER),
+ m_aConnectionHandle,SQL_HANDLE_DBC,*this);
+}
+
+sal_Bool SAL_CALL OConnection::isReadOnly()
+{
+ // const member which will initialized only once
+ return m_bReadOnly;
+}
+
+void SAL_CALL OConnection::setCatalog( const OUString& catalog )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OConnection_BASE::rBHelper.bDisposed);
+
+
+ OString aCat(OUStringToOString(catalog,getTextEncoding()));
+ OTools::ThrowException(this,
+ N3SQLSetConnectAttr(m_aConnectionHandle,SQL_ATTR_CURRENT_CATALOG,const_cast<char *>(aCat.getStr()),SQL_NTS),
+ m_aConnectionHandle,SQL_HANDLE_DBC,*this);
+}
+
+OUString SAL_CALL OConnection::getCatalog( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OConnection_BASE::rBHelper.bDisposed);
+
+
+ SQLINTEGER nValueLen;
+ char pCat[1024];
+ OTools::ThrowException(this,
+ N3SQLGetConnectAttr(m_aConnectionHandle,SQL_ATTR_CURRENT_CATALOG,pCat,(sizeof pCat)-1,&nValueLen),
+ m_aConnectionHandle,SQL_HANDLE_DBC,*this);
+
+ return OUString(pCat,nValueLen,getTextEncoding());
+}
+
+void SAL_CALL OConnection::setTransactionIsolation( sal_Int32 level )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OConnection_BASE::rBHelper.bDisposed);
+
+
+ OTools::ThrowException(this,N3SQLSetConnectAttr(m_aConnectionHandle,
+ SQL_ATTR_TXN_ISOLATION,
+ reinterpret_cast<SQLPOINTER>(level),SQL_IS_INTEGER),
+ m_aConnectionHandle,SQL_HANDLE_DBC,*this);
+}
+
+sal_Int32 SAL_CALL OConnection::getTransactionIsolation( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OConnection_BASE::rBHelper.bDisposed);
+
+
+ sal_Int32 nTxn = 0;
+ SQLINTEGER nValueLen;
+ OTools::ThrowException(this,
+ N3SQLGetConnectAttr(m_aConnectionHandle,SQL_ATTR_TXN_ISOLATION,&nTxn,sizeof nTxn,&nValueLen),
+ m_aConnectionHandle,SQL_HANDLE_DBC,*this);
+ return nTxn;
+}
+
+Reference< css::container::XNameAccess > SAL_CALL OConnection::getTypeMap( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OConnection_BASE::rBHelper.bDisposed);
+
+
+ return nullptr;
+}
+
+void SAL_CALL OConnection::setTypeMap( const Reference< css::container::XNameAccess >& /*typeMap*/ )
+{
+ ::dbtools::throwFeatureNotImplementedSQLException( "XConnection::setTypeMap", *this );
+}
+
+// XCloseable
+void SAL_CALL OConnection::close( )
+{
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OConnection_BASE::rBHelper.bDisposed);
+
+ }
+ dispose();
+}
+
+// XWarningsSupplier
+Any SAL_CALL OConnection::getWarnings( )
+{
+ return Any();
+}
+
+void SAL_CALL OConnection::clearWarnings( )
+{
+}
+
+void OConnection::disposing()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+
+ OConnection_BASE::disposing();
+
+ for (auto const& connection : m_aConnections)
+ connection.second->dispose();
+
+ m_aConnections.clear();
+
+ if(!m_bClosed)
+ N3SQLDisconnect(m_aConnectionHandle);
+ m_bClosed = true;
+}
+
+SQLHANDLE OConnection::createStatementHandle()
+{
+ rtl::Reference<OConnection> xConnectionTemp = this;
+ bool bNew = false;
+ try
+ {
+ sal_Int32 nMaxStatements = getMetaData()->getMaxStatements();
+ if(nMaxStatements && nMaxStatements <= m_nStatementCount)
+ {
+ rtl::Reference xConnection(new OConnection(m_pDriverHandleCopy,m_xDriver.get()));
+ xConnection->Construct(m_sURL,getConnectionInfo());
+ xConnectionTemp = xConnection;
+ bNew = true;
+ }
+ }
+ catch(SQLException&)
+ {
+ }
+
+ SQLHANDLE aStatementHandle = SQL_NULL_HANDLE;
+ N3SQLAllocHandle(SQL_HANDLE_STMT,xConnectionTemp->getConnection(),&aStatementHandle);
+ ++m_nStatementCount;
+ if(bNew)
+ m_aConnections.emplace(aStatementHandle,xConnectionTemp);
+
+ return aStatementHandle;
+
+}
+
+void OConnection::freeStatementHandle(SQLHANDLE& _pHandle)
+{
+ if( SQL_NULL_HANDLE == _pHandle )
+ return;
+
+ auto aFind = m_aConnections.find(_pHandle);
+
+ N3SQLFreeStmt(_pHandle,SQL_RESET_PARAMS);
+ N3SQLFreeStmt(_pHandle,SQL_UNBIND);
+ N3SQLFreeStmt(_pHandle,SQL_CLOSE);
+ N3SQLFreeHandle(SQL_HANDLE_STMT,_pHandle);
+
+ _pHandle = SQL_NULL_HANDLE;
+
+ if(aFind != m_aConnections.end())
+ {
+ aFind->second->dispose();
+ m_aConnections.erase(aFind);
+ }
+ --m_nStatementCount;
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/odbc/ODatabaseMetaData.cxx b/connectivity/source/drivers/odbc/ODatabaseMetaData.cxx
new file mode 100644
index 0000000000..ce3f107e28
--- /dev/null
+++ b/connectivity/source/drivers/odbc/ODatabaseMetaData.cxx
@@ -0,0 +1,1717 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <odbc/ODatabaseMetaData.hxx>
+#include <odbc/OTools.hxx>
+#include <odbc/ODatabaseMetaDataResultSet.hxx>
+#include <FDatabaseMetaDataResultSet.hxx>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <com/sun/star/sdbc/ResultSetType.hpp>
+#include <com/sun/star/sdbc/ResultSetConcurrency.hpp>
+#include <com/sun/star/sdbc/TransactionIsolation.hpp>
+#include <TPrivilegesResultSet.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <sal/log.hxx>
+#include <o3tl/string_view.hxx>
+
+using namespace connectivity::odbc;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::sdbc;
+
+ODatabaseMetaData::ODatabaseMetaData(const SQLHANDLE _pHandle,OConnection* _pCon)
+ : ::connectivity::ODatabaseMetaDataBase(_pCon,_pCon->getConnectionInfo())
+ ,m_aConnectionHandle(_pHandle)
+ ,m_pConnection(_pCon)
+ ,m_bUseCatalog(true)
+{
+ OSL_ENSURE(m_pConnection,"ODatabaseMetaData::ODatabaseMetaData: No connection set!");
+ if(!m_pConnection->isCatalogUsed())
+ {
+ osl_atomic_increment( &m_refCount );
+ try
+ {
+ m_bUseCatalog = !(usesLocalFiles() || usesLocalFilePerTable());
+ }
+ catch(SQLException& )
+ { // doesn't matter here
+ }
+ osl_atomic_decrement( &m_refCount );
+ }
+}
+
+ODatabaseMetaData::~ODatabaseMetaData()
+{
+}
+
+Reference< XResultSet > ODatabaseMetaData::impl_getTypeInfo_throw( )
+{
+ Reference< XResultSet > xRef;
+ try
+ {
+ rtl::Reference<ODatabaseMetaDataResultSet> pResult = new ODatabaseMetaDataResultSet(m_pConnection);
+ xRef = pResult;
+ pResult->openTypeInfo();
+ }
+ catch(SQLException&)
+ {
+ xRef = new ::connectivity::ODatabaseMetaDataResultSet(::connectivity::ODatabaseMetaDataResultSet::eTypeInfo);
+ }
+
+ return xRef;
+}
+
+Reference< XResultSet > SAL_CALL ODatabaseMetaData::getCatalogs( )
+{
+ Reference< XResultSet > xRef;
+ if(!m_bUseCatalog)
+ {
+ xRef = new ::connectivity::ODatabaseMetaDataResultSet(::connectivity::ODatabaseMetaDataResultSet::eCatalogs);
+ }
+ else
+ {
+ try
+ {
+ rtl::Reference<ODatabaseMetaDataResultSet> pResult = new ODatabaseMetaDataResultSet(m_pConnection);
+ xRef = pResult;
+ pResult->openCatalogs();
+ }
+ catch(SQLException&)
+ {
+ xRef = new ::connectivity::ODatabaseMetaDataResultSet(::connectivity::ODatabaseMetaDataResultSet::eCatalogs);
+ }
+ }
+
+ return xRef;
+}
+
+OUString ODatabaseMetaData::impl_getCatalogSeparator_throw( )
+{
+ OUString aVal;
+ if ( m_bUseCatalog )
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_CATALOG_NAME_SEPARATOR,aVal,*this,m_pConnection->getTextEncoding());
+
+ return aVal;
+}
+
+Reference< XResultSet > SAL_CALL ODatabaseMetaData::getSchemas( )
+{
+ Reference< XResultSet > xRef;
+ try
+ {
+ rtl::Reference<ODatabaseMetaDataResultSet> pResult = new ODatabaseMetaDataResultSet(m_pConnection);
+ xRef = pResult;
+ pResult->openSchemas();
+ }
+ catch(SQLException&)
+ {
+ xRef = new ::connectivity::ODatabaseMetaDataResultSet(::connectivity::ODatabaseMetaDataResultSet::eSchemas);
+ }
+ return xRef;
+}
+
+Reference< XResultSet > SAL_CALL ODatabaseMetaData::getColumnPrivileges(
+ const Any& catalog, const OUString& schema, const OUString& table,
+ const OUString& columnNamePattern )
+{
+ Reference< XResultSet > xRef;
+ try
+ {
+ rtl::Reference<ODatabaseMetaDataResultSet> pResult = new ODatabaseMetaDataResultSet(m_pConnection);
+ xRef = pResult;
+ pResult->openColumnPrivileges(m_bUseCatalog ? catalog : Any(),schema,table,columnNamePattern);
+ }
+ catch(SQLException&)
+ {
+ xRef = new ::connectivity::ODatabaseMetaDataResultSet(::connectivity::ODatabaseMetaDataResultSet::eColumnPrivileges);
+ }
+ return xRef;
+}
+
+Reference< XResultSet > SAL_CALL ODatabaseMetaData::getColumns(
+ const Any& catalog, const OUString& schemaPattern, const OUString& tableNamePattern,
+ const OUString& columnNamePattern )
+{
+ Reference< XResultSet > xRef;
+ try
+ {
+ rtl::Reference<ODatabaseMetaDataResultSet> pResult = new ODatabaseMetaDataResultSet(m_pConnection);
+ xRef = pResult;
+ pResult->openColumns(m_bUseCatalog ? catalog : Any(),schemaPattern,tableNamePattern,columnNamePattern);
+ }
+ catch(SQLException&)
+ {
+ xRef = new ::connectivity::ODatabaseMetaDataResultSet(::connectivity::ODatabaseMetaDataResultSet::eColumns);
+ }
+ return xRef;
+}
+
+Reference< XResultSet > SAL_CALL ODatabaseMetaData::getTables(
+ const Any& catalog, const OUString& schemaPattern,
+ const OUString& tableNamePattern, const Sequence< OUString >& types )
+{
+ Reference< XResultSet > xRef;
+ try
+ {
+ rtl::Reference<ODatabaseMetaDataResultSet> pResult = new ODatabaseMetaDataResultSet(m_pConnection);
+ xRef = pResult;
+ pResult->openTables(m_bUseCatalog ? catalog : Any(),schemaPattern,tableNamePattern,types);
+ }
+ catch(SQLException&)
+ {
+ xRef = new ::connectivity::ODatabaseMetaDataResultSet(::connectivity::ODatabaseMetaDataResultSet::eTables);
+ }
+ return xRef;
+}
+
+Reference< XResultSet > SAL_CALL ODatabaseMetaData::getProcedureColumns(
+ const Any& catalog, const OUString& schemaPattern,
+ const OUString& procedureNamePattern, const OUString& columnNamePattern )
+{
+ Reference< XResultSet > xRef;
+ try
+ {
+ rtl::Reference<ODatabaseMetaDataResultSet> pResult = new ODatabaseMetaDataResultSet(m_pConnection);
+ xRef = pResult;
+ pResult->openProcedureColumns(m_bUseCatalog ? catalog : Any(),schemaPattern,procedureNamePattern,columnNamePattern);
+ }
+ catch(SQLException&)
+ {
+ xRef = new ::connectivity::ODatabaseMetaDataResultSet(::connectivity::ODatabaseMetaDataResultSet::eProcedureColumns);
+ }
+ return xRef;
+}
+
+Reference< XResultSet > SAL_CALL ODatabaseMetaData::getProcedures(
+ const Any& catalog, const OUString& schemaPattern,
+ const OUString& procedureNamePattern )
+{
+ Reference< XResultSet > xRef;
+ try
+ {
+ rtl::Reference<ODatabaseMetaDataResultSet> pResult = new ODatabaseMetaDataResultSet(m_pConnection);
+ xRef = pResult;
+ pResult->openProcedures(m_bUseCatalog ? catalog : Any(),schemaPattern,procedureNamePattern);
+ }
+ catch(SQLException&)
+ {
+ xRef = new ::connectivity::ODatabaseMetaDataResultSet(::connectivity::ODatabaseMetaDataResultSet::eProcedures);
+ }
+ return xRef;
+}
+
+Reference< XResultSet > SAL_CALL ODatabaseMetaData::getVersionColumns(
+ const Any& catalog, const OUString& schema, const OUString& table )
+{
+ Reference< XResultSet > xRef;
+ bool bSuccess = false;
+ try
+ {
+ if ( !m_pConnection->preventGetVersionColumns() )
+ {
+ rtl::Reference<ODatabaseMetaDataResultSet> pResult = new ODatabaseMetaDataResultSet(m_pConnection);
+ xRef = pResult;
+ pResult->openVersionColumns(m_bUseCatalog ? catalog : Any(),schema,table);
+ bSuccess = true;
+ }
+ }
+ catch(SQLException&)
+ {
+ }
+
+ if ( !bSuccess )
+ {
+ xRef = new ::connectivity::ODatabaseMetaDataResultSet(::connectivity::ODatabaseMetaDataResultSet::eVersionColumns);
+ }
+
+ return xRef;
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxBinaryLiteralLength( )
+{
+ SQLUINTEGER nValue;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_MAX_BINARY_LITERAL_LEN,nValue,*this);
+ return nValue;
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxRowSize( )
+{
+ SQLUINTEGER nValue;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_MAX_ROW_SIZE,nValue,*this);
+ return nValue;
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxCatalogNameLength( )
+{
+ SQLUSMALLINT nValue;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_MAX_CATALOG_NAME_LEN,nValue,*this);
+ return nValue;
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxCharLiteralLength( )
+{
+ SQLUINTEGER nValue;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_MAX_CHAR_LITERAL_LEN,nValue,*this);
+ return nValue;
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxColumnNameLength( )
+{
+ SQLUSMALLINT nValue;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_MAX_COLUMN_NAME_LEN,nValue,*this);
+ return nValue;
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxColumnsInIndex( )
+{
+ SQLUSMALLINT nValue;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_MAX_COLUMNS_IN_INDEX,nValue,*this);
+ return nValue;
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxCursorNameLength( )
+{
+ SQLUSMALLINT nValue;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_MAX_CURSOR_NAME_LEN,nValue,*this);
+ return nValue;
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxConnections( )
+{
+ SQLUSMALLINT nValue;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_MAX_DRIVER_CONNECTIONS/*SQL_ACTIVE_CONNECTIONS*/,nValue,*this);
+ return nValue;
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxColumnsInTable( )
+{
+ SQLUSMALLINT nValue;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_MAX_COLUMNS_IN_TABLE,nValue,*this);
+ return nValue;
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxStatementLength( )
+{
+ SQLUINTEGER nValue;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_MAX_STATEMENT_LEN,nValue,*this);
+ return nValue;
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxTableNameLength( )
+{
+ SQLUSMALLINT nValue;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_MAX_TABLE_NAME_LEN,nValue,*this);
+ return nValue;
+}
+
+sal_Int32 ODatabaseMetaData::impl_getMaxTablesInSelect_throw( )
+{
+ SQLUSMALLINT nValue;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_MAX_TABLES_IN_SELECT,nValue,*this);
+ return nValue;
+}
+
+Reference< XResultSet > SAL_CALL ODatabaseMetaData::getExportedKeys(
+ const Any& catalog, const OUString& schema, const OUString& table )
+{
+ Reference< XResultSet > xRef;
+ try
+ {
+ rtl::Reference<ODatabaseMetaDataResultSet> pResult = new ODatabaseMetaDataResultSet(m_pConnection);
+ xRef = pResult;
+ pResult->openExportedKeys(m_bUseCatalog ? catalog : Any(),schema,table);
+ }
+ catch(SQLException&)
+ {
+ xRef = new ::connectivity::ODatabaseMetaDataResultSet(::connectivity::ODatabaseMetaDataResultSet::eExportedKeys);
+ }
+ return xRef;
+}
+
+Reference< XResultSet > SAL_CALL ODatabaseMetaData::getImportedKeys(
+ const Any& catalog, const OUString& schema, const OUString& table )
+{
+ Reference< XResultSet > xRef;
+ try
+ {
+ rtl::Reference<ODatabaseMetaDataResultSet> pResult = new ODatabaseMetaDataResultSet(m_pConnection);
+ xRef = pResult;
+ pResult->openImportedKeys(m_bUseCatalog ? catalog : Any(),schema,table);
+ }
+ catch(SQLException&)
+ {
+ xRef = new ::connectivity::ODatabaseMetaDataResultSet(::connectivity::ODatabaseMetaDataResultSet::eImportedKeys);
+ }
+ return xRef;
+}
+
+Reference< XResultSet > SAL_CALL ODatabaseMetaData::getPrimaryKeys(
+ const Any& catalog, const OUString& schema, const OUString& table )
+{
+ Reference< XResultSet > xRef;
+ try
+ {
+ rtl::Reference<ODatabaseMetaDataResultSet> pResult = new ODatabaseMetaDataResultSet(m_pConnection);
+ xRef = pResult;
+ pResult->openPrimaryKeys(m_bUseCatalog ? catalog : Any(),schema,table);
+ }
+ catch(SQLException&)
+ {
+ xRef = new ::connectivity::ODatabaseMetaDataResultSet(::connectivity::ODatabaseMetaDataResultSet::ePrimaryKeys);
+ }
+ return xRef;
+}
+
+Reference< XResultSet > SAL_CALL ODatabaseMetaData::getIndexInfo(
+ const Any& catalog, const OUString& schema, const OUString& table,
+ sal_Bool unique, sal_Bool approximate )
+{
+ Reference< XResultSet > xRef;
+ try
+ {
+ rtl::Reference<ODatabaseMetaDataResultSet> pResult = new ODatabaseMetaDataResultSet(m_pConnection);
+ xRef = pResult;
+ pResult->openIndexInfo(m_bUseCatalog ? catalog : Any(),schema,table,unique,approximate);
+ }
+ catch(SQLException&)
+ {
+ xRef = new ::connectivity::ODatabaseMetaDataResultSet(::connectivity::ODatabaseMetaDataResultSet::eIndexInfo);
+ }
+ return xRef;
+}
+
+Reference< XResultSet > SAL_CALL ODatabaseMetaData::getBestRowIdentifier(
+ const Any& catalog, const OUString& schema, const OUString& table, sal_Int32 scope,
+ sal_Bool nullable )
+{
+ Reference< XResultSet > xRef;
+ try
+ {
+ rtl::Reference<ODatabaseMetaDataResultSet> pResult = new ODatabaseMetaDataResultSet(m_pConnection);
+ xRef = pResult;
+ pResult->openBestRowIdentifier(m_bUseCatalog ? catalog : Any(),schema,table,scope,nullable);
+ }
+ catch(SQLException&)
+ {
+ xRef = new ::connectivity::ODatabaseMetaDataResultSet(::connectivity::ODatabaseMetaDataResultSet::eBestRowIdentifier);
+ }
+ return xRef;
+}
+
+Reference< XResultSet > SAL_CALL ODatabaseMetaData::getTablePrivileges(
+ const Any& catalog, const OUString& schemaPattern, const OUString& tableNamePattern )
+{
+ if ( m_pConnection->isIgnoreDriverPrivilegesEnabled() )
+ {
+ return new OResultSetPrivileges(this,catalog,schemaPattern,tableNamePattern);
+ }
+ rtl::Reference<ODatabaseMetaDataResultSet> pResult = new ODatabaseMetaDataResultSet(m_pConnection);
+ pResult->openTablePrivileges(m_bUseCatalog ? catalog : Any(),schemaPattern,tableNamePattern);
+ return pResult;
+}
+
+Reference< XResultSet > SAL_CALL ODatabaseMetaData::getCrossReference(
+ const Any& primaryCatalog, const OUString& primarySchema,
+ const OUString& primaryTable, const Any& foreignCatalog,
+ const OUString& foreignSchema, const OUString& foreignTable )
+{
+ Reference< XResultSet > xRef;
+ try
+ {
+ rtl::Reference<ODatabaseMetaDataResultSet> pResult = new ODatabaseMetaDataResultSet(m_pConnection);
+ xRef = pResult;
+ pResult->openForeignKeys(m_bUseCatalog ? primaryCatalog : Any(),primarySchema.toChar() == '%' ? &primarySchema : nullptr,&primaryTable,
+ m_bUseCatalog ? foreignCatalog : Any(), foreignSchema.toChar() == '%' ? &foreignSchema : nullptr,&foreignTable);
+ }
+ catch(SQLException&)
+ {
+ xRef = new ::connectivity::ODatabaseMetaDataResultSet(::connectivity::ODatabaseMetaDataResultSet::eCrossReference);
+ }
+ return xRef;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::doesMaxRowSizeIncludeBlobs( )
+{
+ OUString aVal;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_MAX_ROW_SIZE_INCLUDES_LONG,aVal,*this,m_pConnection->getTextEncoding());
+ return aVal.toChar() == 'Y';
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::storesLowerCaseQuotedIdentifiers( )
+{
+ SQLUSMALLINT nValue;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_QUOTED_IDENTIFIER_CASE,nValue,*this);
+ return nValue == SQL_IC_LOWER;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::storesLowerCaseIdentifiers( )
+{
+ SQLUSMALLINT nValue;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_IDENTIFIER_CASE,nValue,*this);
+ return nValue == SQL_IC_LOWER;
+}
+
+bool ODatabaseMetaData::impl_storesMixedCaseQuotedIdentifiers_throw( )
+{
+ SQLUSMALLINT nValue;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_QUOTED_IDENTIFIER_CASE,nValue,*this);
+ return nValue == SQL_IC_MIXED;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::storesMixedCaseIdentifiers( )
+{
+ SQLUSMALLINT nValue;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_IDENTIFIER_CASE,nValue,*this);
+ return nValue == SQL_IC_MIXED;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::storesUpperCaseQuotedIdentifiers( )
+{
+ SQLUSMALLINT nValue;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_QUOTED_IDENTIFIER_CASE,nValue,*this);
+ return nValue == SQL_IC_UPPER;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::storesUpperCaseIdentifiers( )
+{
+ SQLUSMALLINT nValue;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_IDENTIFIER_CASE,nValue,*this);
+ return nValue == SQL_IC_UPPER;
+}
+
+bool ODatabaseMetaData::impl_supportsAlterTableWithAddColumn_throw( )
+{
+ SQLUINTEGER nValue;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_ALTER_TABLE,nValue,*this);
+ return (nValue & SQL_AT_ADD_COLUMN) == SQL_AT_ADD_COLUMN;
+}
+
+bool ODatabaseMetaData::impl_supportsAlterTableWithDropColumn_throw( )
+{
+ SQLUINTEGER nValue;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_ALTER_TABLE,nValue,*this);
+ return ((nValue & SQL_AT_DROP_COLUMN) == SQL_AT_DROP_COLUMN) ||
+ ((nValue & SQL_AT_DROP_COLUMN_CASCADE) == SQL_AT_DROP_COLUMN_CASCADE) ||
+ ((nValue & SQL_AT_DROP_COLUMN_RESTRICT) == SQL_AT_DROP_COLUMN_RESTRICT);
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxIndexLength( )
+{
+ SQLUINTEGER nValue;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_MAX_INDEX_SIZE,nValue,*this);
+ return nValue;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsNonNullableColumns( )
+{
+ SQLUSMALLINT nValue;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_NON_NULLABLE_COLUMNS,nValue,*this);
+ return nValue == SQL_NNC_NON_NULL;
+}
+
+OUString SAL_CALL ODatabaseMetaData::getCatalogTerm( )
+{
+ OUString aVal;
+ if(m_bUseCatalog)
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_CATALOG_TERM,aVal,*this,m_pConnection->getTextEncoding());
+ return aVal;
+}
+
+OUString ODatabaseMetaData::impl_getIdentifierQuoteString_throw( )
+{
+ OUString aVal;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_IDENTIFIER_QUOTE_CHAR,aVal,*this,m_pConnection->getTextEncoding());
+ return aVal;
+}
+
+OUString SAL_CALL ODatabaseMetaData::getExtraNameCharacters( )
+{
+ OUString aVal;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_SPECIAL_CHARACTERS,aVal,*this,m_pConnection->getTextEncoding());
+ return aVal;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsDifferentTableCorrelationNames( )
+{
+ SQLUSMALLINT nValue;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_CORRELATION_NAME,nValue,*this);
+ return nValue != SQL_CN_NONE;
+}
+
+bool ODatabaseMetaData::impl_isCatalogAtStart_throw( )
+{
+ SQLUSMALLINT nValue=0;
+ if ( m_bUseCatalog )
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_CATALOG_LOCATION,nValue,*this);
+ return nValue == SQL_CL_START;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::dataDefinitionIgnoredInTransactions( )
+{
+ SQLUSMALLINT nValue;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_TXN_CAPABLE,nValue,*this);
+ return nValue == SQL_TC_DDL_IGNORE;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::dataDefinitionCausesTransactionCommit( )
+{
+ SQLUSMALLINT nValue;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_TXN_CAPABLE,nValue,*this);
+ return nValue == SQL_TC_DDL_COMMIT;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsDataManipulationTransactionsOnly( )
+{
+ SQLUSMALLINT nValue;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_TXN_CAPABLE,nValue,*this);
+ return nValue == SQL_TC_DML;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsDataDefinitionAndDataManipulationTransactions( )
+{
+ SQLUSMALLINT nValue;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_TXN_CAPABLE,nValue,*this);
+ return nValue == SQL_TC_ALL;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsPositionedDelete( )
+{
+ SQLUINTEGER nValue;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_DYNAMIC_CURSOR_ATTRIBUTES1,nValue,*this);
+ return (nValue & SQL_CA1_POS_DELETE) == SQL_CA1_POS_DELETE;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsPositionedUpdate( )
+{
+ SQLUINTEGER nValue;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_DYNAMIC_CURSOR_ATTRIBUTES1,nValue,*this);
+ return (nValue & SQL_CA1_POS_UPDATE) == SQL_CA1_POS_UPDATE;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsOpenStatementsAcrossRollback( )
+{
+ SQLUSMALLINT nValue;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_CURSOR_ROLLBACK_BEHAVIOR,nValue,*this);
+ return nValue == SQL_CB_PRESERVE || nValue == SQL_CB_CLOSE;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsOpenStatementsAcrossCommit( )
+{
+ SQLUSMALLINT nValue;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_CURSOR_COMMIT_BEHAVIOR,nValue,*this);
+ return nValue == SQL_CB_PRESERVE || nValue == SQL_CB_CLOSE;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsOpenCursorsAcrossCommit( )
+{
+ SQLUSMALLINT nValue;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_CURSOR_COMMIT_BEHAVIOR,nValue,*this);
+ return nValue == SQL_CB_PRESERVE;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsOpenCursorsAcrossRollback( )
+{
+ SQLUSMALLINT nValue;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_CURSOR_ROLLBACK_BEHAVIOR,nValue,*this);
+ return nValue == SQL_CB_PRESERVE;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsTransactionIsolationLevel( sal_Int32 level )
+{
+ SQLUINTEGER nValue;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_TXN_ISOLATION_OPTION,nValue,*this);
+ return (nValue & static_cast<SQLUINTEGER>(level)) == static_cast<SQLUINTEGER>(level);
+}
+
+bool ODatabaseMetaData::impl_supportsSchemasInDataManipulation_throw( )
+{
+ SQLUINTEGER nValue;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_SCHEMA_USAGE,nValue,*this);
+ return (nValue & SQL_SU_DML_STATEMENTS) == SQL_SU_DML_STATEMENTS;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsANSI92FullSQL( )
+{
+ SQLUINTEGER nValue;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_SQL_CONFORMANCE,nValue,*this);
+ return static_cast<bool>(nValue & SQL_SC_SQL92_FULL);
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsANSI92EntryLevelSQL( )
+{
+ SQLUINTEGER nValue;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_SQL_CONFORMANCE,nValue,*this);
+ return static_cast<bool>(nValue &SQL_SC_SQL92_ENTRY);
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsIntegrityEnhancementFacility( )
+{
+ OUString aStr;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_INTEGRITY,aStr,*this,m_pConnection->getTextEncoding());
+ return aStr.toChar() == 'Y';
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsSchemasInIndexDefinitions( )
+{
+ SQLUINTEGER nValue;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_SCHEMA_USAGE,nValue,*this);
+ return (nValue & SQL_SU_INDEX_DEFINITION) == SQL_SU_INDEX_DEFINITION;
+}
+
+bool ODatabaseMetaData::impl_supportsSchemasInTableDefinitions_throw( )
+{
+ SQLUINTEGER nValue;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_SCHEMA_USAGE,nValue,*this);
+ return (nValue & SQL_SU_TABLE_DEFINITION) == SQL_SU_TABLE_DEFINITION;
+}
+
+bool ODatabaseMetaData::impl_supportsCatalogsInTableDefinitions_throw( )
+{
+ SQLUINTEGER nValue=0;
+ if(m_bUseCatalog)
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_CATALOG_USAGE,nValue,*this);
+ return (nValue & SQL_CU_TABLE_DEFINITION) == SQL_CU_TABLE_DEFINITION;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsCatalogsInIndexDefinitions( )
+{
+ SQLUINTEGER nValue=0;
+ if(m_bUseCatalog)
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_CATALOG_USAGE,nValue,*this);
+ return (nValue & SQL_CU_INDEX_DEFINITION) == SQL_CU_INDEX_DEFINITION;
+}
+
+bool ODatabaseMetaData::impl_supportsCatalogsInDataManipulation_throw( )
+{
+ SQLUINTEGER nValue=0;
+ if(m_bUseCatalog)
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_CATALOG_USAGE,nValue,*this);
+ return (nValue & SQL_CU_DML_STATEMENTS) == SQL_CU_DML_STATEMENTS;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsOuterJoins( )
+{
+ SQLUINTEGER nValue;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_OJ_CAPABILITIES,nValue,*this);
+ return ((nValue & (SQL_OJ_FULL|SQL_OJ_LEFT|SQL_OJ_RIGHT|SQL_OJ_NESTED|SQL_OJ_NOT_ORDERED|SQL_OJ_ALL_COMPARISON_OPS|SQL_OJ_INNER)) != 0);
+}
+
+Reference< XResultSet > SAL_CALL ODatabaseMetaData::getTableTypes( )
+{
+ Reference< XResultSet > xRef;
+ try
+ {
+ rtl::Reference<ODatabaseMetaDataResultSet> pResult = new ODatabaseMetaDataResultSet(m_pConnection);
+ xRef = pResult;
+ pResult->openTablesTypes();
+ }
+ catch(SQLException&)
+ {
+ xRef = new ::connectivity::ODatabaseMetaDataResultSet(::connectivity::ODatabaseMetaDataResultSet::eTableTypes);
+ }
+ return xRef;
+}
+
+sal_Int32 ODatabaseMetaData::impl_getMaxStatements_throw( )
+{
+ SQLUSMALLINT nValue;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_MAX_CONCURRENT_ACTIVITIES,nValue,*this);
+ return nValue;
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxProcedureNameLength( )
+{
+ SQLUSMALLINT nValue;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_MAX_PROCEDURE_NAME_LEN,nValue,*this);
+ return nValue;
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxSchemaNameLength( )
+{
+ SQLUSMALLINT nValue;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_MAX_SCHEMA_NAME_LEN,nValue,*this);
+ return nValue;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsTransactions( )
+{
+ SQLUSMALLINT nValue;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_TXN_CAPABLE,nValue,*this);
+ return nValue != SQL_TC_NONE;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::allProceduresAreCallable( )
+{
+ OUString aValue;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_ACCESSIBLE_PROCEDURES,aValue,*this,m_pConnection->getTextEncoding());
+ return aValue.toChar() == 'Y';
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsStoredProcedures( )
+{
+ OUString aValue;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_PROCEDURES,aValue,*this,m_pConnection->getTextEncoding());
+ return aValue.toChar() == 'Y';
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsSelectForUpdate( )
+{
+ SQLUINTEGER nValue;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_DYNAMIC_CURSOR_ATTRIBUTES1,nValue,*this);
+ return (nValue & SQL_CA1_POSITIONED_UPDATE) == SQL_CA1_POSITIONED_UPDATE;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::allTablesAreSelectable( )
+{
+ OUString aValue;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_ACCESSIBLE_TABLES,aValue,*this,m_pConnection->getTextEncoding());
+ return aValue.toChar() == 'Y';
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::isReadOnly( )
+{
+ return m_pConnection->isReadOnly();
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::usesLocalFiles( )
+{
+ SQLUSMALLINT nValue;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_FILE_USAGE,nValue,*this);
+ return nValue == SQL_FILE_CATALOG;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::usesLocalFilePerTable( )
+{
+ SQLUSMALLINT nValue;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_FILE_USAGE,nValue,*this);
+ return nValue == SQL_FILE_TABLE;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsTypeConversion( )
+{
+ SQLUINTEGER nValue;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_CONVERT_FUNCTIONS,nValue,*this);
+ return (nValue & SQL_FN_CVT_CONVERT) == SQL_FN_CVT_CONVERT;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::nullPlusNonNullIsNull( )
+{
+ SQLUSMALLINT nValue;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_CONCAT_NULL_BEHAVIOR,nValue,*this);
+ return nValue == SQL_CB_NULL;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsColumnAliasing( )
+{
+ OUString aValue;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_COLUMN_ALIAS,aValue,*this,m_pConnection->getTextEncoding());
+ return aValue.toChar() == 'Y';
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsTableCorrelationNames( )
+{
+ SQLUSMALLINT nValue;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_CORRELATION_NAME,nValue,*this);
+ return nValue != SQL_CN_NONE;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsConvert( sal_Int32 fromType, sal_Int32 toType )
+{
+ if(fromType == toType)
+ return true;
+
+ SQLUINTEGER nValue=0;
+ switch(fromType)
+ {
+ case DataType::BIT:
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_CONVERT_BIT,nValue,*this);
+ break;
+ case DataType::TINYINT:
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_CONVERT_TINYINT,nValue,*this);
+ break;
+ case DataType::SMALLINT:
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_CONVERT_SMALLINT,nValue,*this);
+ break;
+ case DataType::INTEGER:
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_CONVERT_INTEGER,nValue,*this);
+ break;
+ case DataType::BIGINT:
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_CONVERT_BIGINT,nValue,*this);
+ break;
+ case DataType::FLOAT:
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_CONVERT_FLOAT,nValue,*this);
+ break;
+ case DataType::REAL:
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_CONVERT_REAL,nValue,*this);
+ break;
+ case DataType::DOUBLE:
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_CONVERT_DOUBLE,nValue,*this);
+ break;
+ case DataType::NUMERIC:
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_CONVERT_NUMERIC,nValue,*this);
+ break;
+ case DataType::DECIMAL:
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_CONVERT_DECIMAL,nValue,*this);
+ break;
+ case DataType::CHAR:
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_CONVERT_CHAR,nValue,*this);
+ break;
+ case DataType::VARCHAR:
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_CONVERT_VARCHAR,nValue,*this);
+ break;
+ case DataType::LONGVARCHAR:
+ case DataType::CLOB:
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_CONVERT_LONGVARCHAR,nValue,*this);
+ break;
+ case DataType::DATE:
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_CONVERT_DATE,nValue,*this);
+ break;
+ case DataType::TIME:
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_CONVERT_TIME,nValue,*this);
+ break;
+ case DataType::TIMESTAMP:
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_CONVERT_TIMESTAMP,nValue,*this);
+ break;
+ case DataType::BINARY:
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_CONVERT_BINARY,nValue,*this);
+ break;
+ case DataType::VARBINARY:
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_CONVERT_VARBINARY,nValue,*this);
+ break;
+ case DataType::LONGVARBINARY:
+ case DataType::BLOB:
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_CONVERT_LONGVARBINARY,nValue,*this);
+ break;
+ case DataType::SQLNULL:
+ // OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_CORRELATION_NAME,nValue,*this);
+ break;
+ case DataType::OTHER:
+ // OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_CORRELATION_NAME,nValue,*this);
+ break;
+ case DataType::OBJECT:
+ // OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_CORRELATION_NAME,nValue,*this);
+ break;
+ case DataType::DISTINCT:
+ // OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_CORRELATION_NAME,nValue,*this);
+ break;
+ case DataType::STRUCT:
+ // OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_CORRELATION_NAME,nValue,*this);
+ break;
+ case DataType::ARRAY:
+ // OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_CORRELATION_NAME,nValue,*this);
+ break;
+ case DataType::REF:
+ // OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_CORRELATION_NAME,nValue,*this);
+ break;
+ }
+ bool bConvert = false;
+ switch(toType)
+ {
+ case DataType::BIT:
+ bConvert = (nValue & SQL_CVT_BIT) == SQL_CVT_BIT;
+ break;
+ case DataType::TINYINT:
+ bConvert = (nValue & SQL_CVT_TINYINT) == SQL_CVT_TINYINT;
+ break;
+ case DataType::SMALLINT:
+ bConvert = (nValue & SQL_CVT_SMALLINT) == SQL_CVT_SMALLINT;
+ break;
+ case DataType::INTEGER:
+ bConvert = (nValue & SQL_CVT_INTEGER) == SQL_CVT_INTEGER;
+ break;
+ case DataType::BIGINT:
+ bConvert = (nValue & SQL_CVT_BIGINT) == SQL_CVT_BIGINT;
+ break;
+ case DataType::FLOAT:
+ bConvert = (nValue & SQL_CVT_FLOAT) == SQL_CVT_FLOAT;
+ break;
+ case DataType::REAL:
+ bConvert = (nValue & SQL_CVT_REAL) == SQL_CVT_REAL;
+ break;
+ case DataType::DOUBLE:
+ bConvert = (nValue & SQL_CVT_DOUBLE) == SQL_CVT_DOUBLE;
+ break;
+ case DataType::NUMERIC:
+ bConvert = (nValue & SQL_CVT_NUMERIC) == SQL_CVT_NUMERIC;
+ break;
+ case DataType::DECIMAL:
+ bConvert = (nValue & SQL_CVT_DECIMAL) == SQL_CVT_DECIMAL;
+ break;
+ case DataType::CHAR:
+ bConvert = (nValue & SQL_CVT_CHAR) == SQL_CVT_CHAR;
+ break;
+ case DataType::VARCHAR:
+ bConvert = (nValue & SQL_CVT_VARCHAR) == SQL_CVT_VARCHAR;
+ break;
+ case DataType::LONGVARCHAR:
+ case DataType::CLOB:
+ bConvert = (nValue & SQL_CVT_LONGVARCHAR) == SQL_CVT_LONGVARCHAR;
+ break;
+ case DataType::DATE:
+ bConvert = (nValue & SQL_CVT_DATE) == SQL_CVT_DATE;
+ break;
+ case DataType::TIME:
+ bConvert = (nValue & SQL_CVT_TIME) == SQL_CVT_TIME;
+ break;
+ case DataType::TIMESTAMP:
+ bConvert = (nValue & SQL_CVT_TIMESTAMP) == SQL_CVT_TIMESTAMP;
+ break;
+ case DataType::BINARY:
+ bConvert = (nValue & SQL_CVT_BINARY) == SQL_CVT_BINARY;
+ break;
+ case DataType::VARBINARY:
+ bConvert = (nValue & SQL_CVT_VARBINARY) == SQL_CVT_VARBINARY;
+ break;
+ case DataType::LONGVARBINARY:
+ case DataType::BLOB:
+ bConvert = (nValue & SQL_CVT_LONGVARBINARY) == SQL_CVT_LONGVARBINARY;
+ break;
+ }
+
+ return bConvert;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsExpressionsInOrderBy( )
+{
+ OUString aValue;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_EXPRESSIONS_IN_ORDERBY,aValue,*this,m_pConnection->getTextEncoding());
+ return aValue.toChar() == 'Y';
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsGroupBy( )
+{
+ SQLUSMALLINT nValue;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_GROUP_BY,nValue,*this);
+ return nValue != SQL_GB_NOT_SUPPORTED;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsGroupByBeyondSelect( )
+{
+ SQLUSMALLINT nValue;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_GROUP_BY,nValue,*this);
+ return nValue != SQL_GB_GROUP_BY_CONTAINS_SELECT;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsGroupByUnrelated( )
+{
+ SQLUSMALLINT nValue;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_GROUP_BY,nValue,*this);
+ return nValue == SQL_GB_NO_RELATION;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsMultipleTransactions( )
+{
+ OUString aValue;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_MULTIPLE_ACTIVE_TXN,aValue,*this,m_pConnection->getTextEncoding());
+ return aValue.toChar() == 'Y';
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsMultipleResultSets( )
+{
+ OUString aValue;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_MULT_RESULT_SETS,aValue,*this,m_pConnection->getTextEncoding());
+ return aValue.toChar() == 'Y';
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsLikeEscapeClause( )
+{
+ OUString aValue;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_LIKE_ESCAPE_CLAUSE,aValue,*this,m_pConnection->getTextEncoding());
+ return aValue.toChar() == 'Y';
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsOrderByUnrelated( )
+{
+ OUString aValue;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_ORDER_BY_COLUMNS_IN_SELECT,aValue,*this,m_pConnection->getTextEncoding());
+ return aValue.toChar() == 'N';
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsUnion( )
+{
+ SQLUINTEGER nValue;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_UNION,nValue,*this);
+ return (nValue & SQL_U_UNION) == SQL_U_UNION;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsUnionAll( )
+{
+ SQLUINTEGER nValue;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_UNION,nValue,*this);
+ return (nValue & SQL_U_UNION_ALL) == SQL_U_UNION_ALL;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsMixedCaseIdentifiers( )
+{
+ SQLUSMALLINT nValue;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_IDENTIFIER_CASE,nValue,*this);
+ return nValue == SQL_IC_MIXED;
+}
+
+bool ODatabaseMetaData::impl_supportsMixedCaseQuotedIdentifiers_throw( )
+{
+ SQLUSMALLINT nValue;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_QUOTED_IDENTIFIER_CASE,nValue,*this);
+ return nValue == SQL_IC_MIXED;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::nullsAreSortedAtEnd( )
+{
+ SQLUSMALLINT nValue;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_NULL_COLLATION,nValue,*this);
+ return nValue == SQL_NC_END;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::nullsAreSortedAtStart( )
+{
+ SQLUSMALLINT nValue;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_NULL_COLLATION,nValue,*this);
+ return nValue == SQL_NC_START;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::nullsAreSortedHigh( )
+{
+ SQLUSMALLINT nValue;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_NULL_COLLATION,nValue,*this);
+ return nValue == SQL_NC_HIGH;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::nullsAreSortedLow( )
+{
+ SQLUSMALLINT nValue;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_NULL_COLLATION,nValue,*this);
+ return nValue == SQL_NC_LOW;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsSchemasInProcedureCalls( )
+{
+ SQLUINTEGER nValue;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_SCHEMA_USAGE,nValue,*this);
+ return (nValue & SQL_SU_PROCEDURE_INVOCATION) == SQL_SU_PROCEDURE_INVOCATION;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsSchemasInPrivilegeDefinitions( )
+{
+ SQLUINTEGER nValue;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_SCHEMA_USAGE,nValue,*this);
+ return (nValue & SQL_SU_PRIVILEGE_DEFINITION) == SQL_SU_PRIVILEGE_DEFINITION;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsCatalogsInProcedureCalls( )
+{
+ SQLUINTEGER nValue=0;
+ if(m_bUseCatalog)
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_CATALOG_USAGE,nValue,*this);
+ return (nValue & SQL_CU_PROCEDURE_INVOCATION) == SQL_CU_PROCEDURE_INVOCATION;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsCatalogsInPrivilegeDefinitions( )
+{
+ SQLUINTEGER nValue=0;
+ if(m_bUseCatalog)
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_CATALOG_USAGE,nValue,*this);
+ return (nValue & SQL_CU_PRIVILEGE_DEFINITION) == SQL_CU_PRIVILEGE_DEFINITION;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsCorrelatedSubqueries( )
+{
+ SQLUINTEGER nValue;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_SUBQUERIES,nValue,*this);
+ return (nValue & SQL_SQ_CORRELATED_SUBQUERIES) == SQL_SQ_CORRELATED_SUBQUERIES;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsSubqueriesInComparisons( )
+{
+ SQLUINTEGER nValue;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_SUBQUERIES,nValue,*this);
+ return (nValue & SQL_SQ_COMPARISON) == SQL_SQ_COMPARISON;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsSubqueriesInExists( )
+{
+ SQLUINTEGER nValue;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_SUBQUERIES,nValue,*this);
+ return (nValue & SQL_SQ_EXISTS) == SQL_SQ_EXISTS;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsSubqueriesInIns( )
+{
+ SQLUINTEGER nValue;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_SUBQUERIES,nValue,*this);
+ return (nValue & SQL_SQ_IN) == SQL_SQ_IN;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsSubqueriesInQuantifieds( )
+{
+ SQLUINTEGER nValue;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_SUBQUERIES,nValue,*this);
+ return (nValue & SQL_SQ_QUANTIFIED) == SQL_SQ_QUANTIFIED;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsANSI92IntermediateSQL( )
+{
+ SQLUINTEGER nValue;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_SQL_CONFORMANCE,nValue,*this);
+ return static_cast<bool>(nValue & SQL_SC_SQL92_INTERMEDIATE);
+}
+
+OUString ODatabaseMetaData::getURLImpl()
+{
+ OUString aValue;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_DATA_SOURCE_NAME,aValue,*this,m_pConnection->getTextEncoding());
+ return aValue;
+}
+
+OUString SAL_CALL ODatabaseMetaData::getURL( )
+{
+ OUString aValue = m_pConnection->getURL();
+ if ( aValue.isEmpty() )
+ {
+ aValue = "sdbc:odbc:" + getURLImpl();
+ }
+ return aValue;
+}
+
+OUString SAL_CALL ODatabaseMetaData::getUserName( )
+{
+ OUString aValue;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_USER_NAME,aValue,*this,m_pConnection->getTextEncoding());
+ return aValue;
+}
+
+OUString SAL_CALL ODatabaseMetaData::getDriverName( )
+{
+ OUString aValue;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_DRIVER_NAME,aValue,*this,m_pConnection->getTextEncoding());
+ return aValue;
+}
+
+OUString SAL_CALL ODatabaseMetaData::getDriverVersion()
+{
+ OUString aValue;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_DRIVER_ODBC_VER,aValue,*this,m_pConnection->getTextEncoding());
+ return aValue;
+}
+
+OUString SAL_CALL ODatabaseMetaData::getDatabaseProductVersion( )
+{
+ OUString aValue;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_DRIVER_VER,aValue,*this,m_pConnection->getTextEncoding());
+ return aValue;
+}
+
+OUString SAL_CALL ODatabaseMetaData::getDatabaseProductName( )
+{
+ OUString aValue;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_DBMS_NAME,aValue,*this,m_pConnection->getTextEncoding());
+ return aValue;
+}
+
+OUString SAL_CALL ODatabaseMetaData::getProcedureTerm( )
+{
+ OUString aValue;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_PROCEDURE_TERM,aValue,*this,m_pConnection->getTextEncoding());
+ return aValue;
+}
+
+OUString SAL_CALL ODatabaseMetaData::getSchemaTerm( )
+{
+ OUString aValue;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_SCHEMA_TERM,aValue,*this,m_pConnection->getTextEncoding());
+ return aValue;
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getDriverMajorVersion( ) try
+{
+ OUString aValue;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_DRIVER_VER,aValue,*this,m_pConnection->getTextEncoding());
+ return o3tl::toInt32(aValue.subView(0,aValue.indexOf('.')));
+}
+catch (const SQLException &)
+{
+ return 0;
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getDefaultTransactionIsolation( )
+{
+ SQLUINTEGER nValue;
+ sal_Int32 nValueTranslated;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_DEFAULT_TXN_ISOLATION,nValue,*this);
+ switch(nValue)
+ {
+ case SQL_TXN_READ_UNCOMMITTED:
+ nValueTranslated = css::sdbc::TransactionIsolation::READ_UNCOMMITTED;
+ break;
+ case SQL_TXN_READ_COMMITTED:
+ nValueTranslated = css::sdbc::TransactionIsolation::READ_COMMITTED;
+ break;
+ case SQL_TXN_REPEATABLE_READ:
+ nValueTranslated = css::sdbc::TransactionIsolation::REPEATABLE_READ;
+ break;
+ case SQL_TXN_SERIALIZABLE:
+ nValueTranslated = css::sdbc::TransactionIsolation::SERIALIZABLE;
+ break;
+ default:
+ nValueTranslated = 0;
+ }
+ return nValueTranslated;
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getDriverMinorVersion( ) try
+{
+ OUString aValue;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_DRIVER_VER,aValue,*this,m_pConnection->getTextEncoding());
+ return o3tl::toInt32(aValue.subView(0,aValue.lastIndexOf('.')));
+}
+catch (const SQLException &)
+{
+ return 0;
+}
+
+OUString SAL_CALL ODatabaseMetaData::getSQLKeywords( )
+{
+ OUString aValue;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_KEYWORDS,aValue,*this,m_pConnection->getTextEncoding());
+ return aValue;
+}
+
+OUString SAL_CALL ODatabaseMetaData::getSearchStringEscape( )
+{
+ OUString aValue;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_SEARCH_PATTERN_ESCAPE,aValue,*this,m_pConnection->getTextEncoding());
+ return aValue;
+}
+
+OUString SAL_CALL ODatabaseMetaData::getStringFunctions( )
+{
+ SQLUINTEGER nValue;
+ OUStringBuffer aValue;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_STRING_FUNCTIONS,nValue,*this);
+ if(nValue & SQL_FN_STR_ASCII)
+ aValue.append("ASCII,");
+ if(nValue & SQL_FN_STR_BIT_LENGTH)
+ aValue.append("BIT_LENGTH,");
+ if(nValue & SQL_FN_STR_CHAR)
+ aValue.append("CHAR,");
+ if(nValue & SQL_FN_STR_CHAR_LENGTH)
+ aValue.append("CHAR_LENGTH,");
+ if(nValue & SQL_FN_STR_CHARACTER_LENGTH)
+ aValue.append("CHARACTER_LENGTH,");
+ if(nValue & SQL_FN_STR_CONCAT)
+ aValue.append("CONCAT,");
+ if(nValue & SQL_FN_STR_DIFFERENCE)
+ aValue.append("DIFFERENCE,");
+ if(nValue & SQL_FN_STR_INSERT)
+ aValue.append("INSERT,");
+ if(nValue & SQL_FN_STR_LCASE)
+ aValue.append("LCASE,");
+ if(nValue & SQL_FN_STR_LEFT)
+ aValue.append("LEFT,");
+ if(nValue & SQL_FN_STR_LENGTH)
+ aValue.append("LENGTH,");
+ if(nValue & SQL_FN_STR_LOCATE)
+ aValue.append("LOCATE,");
+ if(nValue & SQL_FN_STR_LOCATE_2)
+ aValue.append("LOCATE_2,");
+ if(nValue & SQL_FN_STR_LTRIM)
+ aValue.append("LTRIM,");
+ if(nValue & SQL_FN_STR_OCTET_LENGTH)
+ aValue.append("OCTET_LENGTH,");
+ if(nValue & SQL_FN_STR_POSITION)
+ aValue.append("POSITION,");
+ if(nValue & SQL_FN_STR_REPEAT)
+ aValue.append("REPEAT,");
+ if(nValue & SQL_FN_STR_REPLACE)
+ aValue.append("REPLACE,");
+ if(nValue & SQL_FN_STR_RIGHT)
+ aValue.append("RIGHT,");
+ if(nValue & SQL_FN_STR_RTRIM)
+ aValue.append("RTRIM,");
+ if(nValue & SQL_FN_STR_SOUNDEX)
+ aValue.append("SOUNDEX,");
+ if(nValue & SQL_FN_STR_SPACE)
+ aValue.append("SPACE,");
+ if(nValue & SQL_FN_STR_SUBSTRING)
+ aValue.append("SUBSTRING,");
+ if(nValue & SQL_FN_STR_UCASE)
+ aValue.append("UCASE,");
+
+
+ if ( !aValue.isEmpty() )
+ aValue.setLength(aValue.getLength()-1);
+
+ return aValue.makeStringAndClear();
+}
+
+OUString SAL_CALL ODatabaseMetaData::getTimeDateFunctions( )
+{
+ SQLUINTEGER nValue;
+ OUStringBuffer aValue;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_TIMEDATE_FUNCTIONS,nValue,*this);
+
+ if(nValue & SQL_FN_TD_CURRENT_DATE)
+ aValue.append("CURRENT_DATE,");
+ if(nValue & SQL_FN_TD_CURRENT_TIME)
+ aValue.append("CURRENT_TIME,");
+ if(nValue & SQL_FN_TD_CURRENT_TIMESTAMP)
+ aValue.append("CURRENT_TIMESTAMP,");
+ if(nValue & SQL_FN_TD_CURDATE)
+ aValue.append("CURDATE,");
+ if(nValue & SQL_FN_TD_CURTIME)
+ aValue.append("CURTIME,");
+ if(nValue & SQL_FN_TD_DAYNAME)
+ aValue.append("DAYNAME,");
+ if(nValue & SQL_FN_TD_DAYOFMONTH)
+ aValue.append("DAYOFMONTH,");
+ if(nValue & SQL_FN_TD_DAYOFWEEK)
+ aValue.append("DAYOFWEEK,");
+ if(nValue & SQL_FN_TD_DAYOFYEAR)
+ aValue.append("DAYOFYEAR,");
+ if(nValue & SQL_FN_TD_EXTRACT)
+ aValue.append("EXTRACT,");
+ if(nValue & SQL_FN_TD_HOUR)
+ aValue.append("HOUR,");
+ if(nValue & SQL_FN_TD_MINUTE)
+ aValue.append("MINUTE,");
+ if(nValue & SQL_FN_TD_MONTH)
+ aValue.append("MONTH,");
+ if(nValue & SQL_FN_TD_MONTHNAME)
+ aValue.append("MONTHNAME,");
+ if(nValue & SQL_FN_TD_NOW)
+ aValue.append("NOW,");
+ if(nValue & SQL_FN_TD_QUARTER)
+ aValue.append("QUARTER,");
+ if(nValue & SQL_FN_TD_SECOND)
+ aValue.append("SECOND,");
+ if(nValue & SQL_FN_TD_TIMESTAMPADD)
+ aValue.append("TIMESTAMPADD,");
+ if(nValue & SQL_FN_TD_TIMESTAMPDIFF)
+ aValue.append("TIMESTAMPDIFF,");
+ if(nValue & SQL_FN_TD_WEEK)
+ aValue.append("WEEK,");
+ if(nValue & SQL_FN_TD_YEAR)
+ aValue.append("YEAR,");
+
+ if ( !aValue.isEmpty() )
+ aValue.setLength(aValue.getLength()-1);
+
+ return aValue.makeStringAndClear();
+}
+
+OUString SAL_CALL ODatabaseMetaData::getSystemFunctions( )
+{
+ SQLUINTEGER nValue;
+ OUStringBuffer aValue;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_SYSTEM_FUNCTIONS,nValue,*this);
+
+ if(nValue & SQL_FN_SYS_DBNAME)
+ aValue.append("DBNAME,");
+ if(nValue & SQL_FN_SYS_IFNULL)
+ aValue.append("IFNULL,");
+ if(nValue & SQL_FN_SYS_USERNAME)
+ aValue.append("USERNAME,");
+
+ if ( !aValue.isEmpty() )
+ aValue.setLength(aValue.getLength()-1);
+
+ return aValue.makeStringAndClear();
+}
+
+OUString SAL_CALL ODatabaseMetaData::getNumericFunctions( )
+{
+ SQLUINTEGER nValue;
+ OUStringBuffer aValue;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_NUMERIC_FUNCTIONS,nValue,*this);
+
+ if(nValue & SQL_FN_NUM_ABS)
+ aValue.append("ABS,");
+ if(nValue & SQL_FN_NUM_ACOS)
+ aValue.append("ACOS,");
+ if(nValue & SQL_FN_NUM_ASIN)
+ aValue.append("ASIN,");
+ if(nValue & SQL_FN_NUM_ATAN)
+ aValue.append("ATAN,");
+ if(nValue & SQL_FN_NUM_ATAN2)
+ aValue.append("ATAN2,");
+ if(nValue & SQL_FN_NUM_CEILING)
+ aValue.append("CEILING,");
+ if(nValue & SQL_FN_NUM_COS)
+ aValue.append("COS,");
+ if(nValue & SQL_FN_NUM_COT)
+ aValue.append("COT,");
+ if(nValue & SQL_FN_NUM_DEGREES)
+ aValue.append("DEGREES,");
+ if(nValue & SQL_FN_NUM_EXP)
+ aValue.append("EXP,");
+ if(nValue & SQL_FN_NUM_FLOOR)
+ aValue.append("FLOOR,");
+ if(nValue & SQL_FN_NUM_LOG)
+ aValue.append("LOGF,");
+ if(nValue & SQL_FN_NUM_LOG10)
+ aValue.append("LOG10,");
+ if(nValue & SQL_FN_NUM_MOD)
+ aValue.append("MOD,");
+ if(nValue & SQL_FN_NUM_PI)
+ aValue.append("PI,");
+ if(nValue & SQL_FN_NUM_POWER)
+ aValue.append("POWER,");
+ if(nValue & SQL_FN_NUM_RADIANS)
+ aValue.append("RADIANS,");
+ if(nValue & SQL_FN_NUM_RAND)
+ aValue.append("RAND,");
+ if(nValue & SQL_FN_NUM_ROUND)
+ aValue.append("ROUND,");
+ if(nValue & SQL_FN_NUM_SIGN)
+ aValue.append("SIGN,");
+ if(nValue & SQL_FN_NUM_SIN)
+ aValue.append("SIN,");
+ if(nValue & SQL_FN_NUM_SQRT)
+ aValue.append("SQRT,");
+ if(nValue & SQL_FN_NUM_TAN)
+ aValue.append("TAN,");
+ if(nValue & SQL_FN_NUM_TRUNCATE)
+ aValue.append("TRUNCATE,");
+
+ if ( !aValue.isEmpty() )
+ aValue.setLength(aValue.getLength()-1);
+
+ return aValue.makeStringAndClear();
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsExtendedSQLGrammar( )
+{
+ SQLUINTEGER nValue;
+ // SQL_ODBC_SQL_CONFORMANCE is deprecated in ODBC 3.x, but there does not seem te be any equivalent.
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_ODBC_SQL_CONFORMANCE,nValue,*this);
+ SAL_WARN_IF(! (nValue == SQL_OSC_MINIMUM || nValue == SQL_OSC_CORE || nValue == SQL_OSC_EXTENDED),
+ "connectivity.odbc",
+ "SQL_ODBC_SQL_CONFORMANCE is neither MINIMAL nor CORE nor EXTENDED");
+ return nValue == SQL_OSC_EXTENDED;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsCoreSQLGrammar( )
+{
+ SQLUINTEGER nValue;
+ // SQL_ODBC_SQL_CONFORMANCE is deprecated in ODBC 3.x, but there does not seem te be any equivalent.
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_ODBC_SQL_CONFORMANCE,nValue,*this);
+ SAL_WARN_IF(! (nValue == SQL_OSC_MINIMUM || nValue == SQL_OSC_CORE || nValue == SQL_OSC_EXTENDED),
+ "connectivity.odbc",
+ "SQL_ODBC_SQL_CONFORMANCE is neither MINIMAL nor CORE nor EXTENDED");
+ return nValue == SQL_OSC_CORE || nValue == SQL_OSC_EXTENDED;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsMinimumSQLGrammar( )
+{
+ SQLUINTEGER nValue;
+ // SQL_ODBC_SQL_CONFORMANCE is deprecated in ODBC 3.x, but there does not seem te be any equivalent.
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_ODBC_SQL_CONFORMANCE,nValue,*this);
+ SAL_WARN_IF(! (nValue == SQL_OSC_MINIMUM || nValue == SQL_OSC_CORE || nValue == SQL_OSC_EXTENDED),
+ "connectivity.odbc",
+ "SQL_ODBC_SQL_CONFORMANCE is neither MINIMAL nor CORE nor EXTENDED");
+ return nValue == SQL_OSC_MINIMUM || nValue == SQL_OSC_CORE || nValue == SQL_OSC_EXTENDED;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsFullOuterJoins( )
+{
+ SQLUINTEGER nValue;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_OJ_CAPABILITIES,nValue,*this);
+ return (nValue & SQL_OJ_FULL) == SQL_OJ_FULL;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsLimitedOuterJoins( )
+{
+ return supportsFullOuterJoins( );
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxColumnsInGroupBy( )
+{
+ SQLUSMALLINT nValue;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_MAX_COLUMNS_IN_GROUP_BY,nValue,*this);
+ return nValue;
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxColumnsInOrderBy( )
+{
+ SQLUSMALLINT nValue;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_MAX_COLUMNS_IN_ORDER_BY,nValue,*this);
+ return nValue;
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxColumnsInSelect( )
+{
+ SQLUSMALLINT nValue;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_MAX_COLUMNS_IN_SELECT,nValue,*this);
+ return nValue;
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxUserNameLength( )
+{
+ SQLUSMALLINT nValue;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_MAX_USER_NAME_LEN,nValue,*this);
+ return nValue;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsResultSetType( sal_Int32 setType )
+{
+ SQLUINTEGER nValue;
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_CURSOR_SENSITIVITY,nValue,*this);
+ return (nValue & static_cast<SQLUINTEGER>(setType)) == static_cast<SQLUINTEGER>(setType);
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsResultSetConcurrency( sal_Int32 setType, sal_Int32 concurrency )
+{
+ SQLUINTEGER nValue;
+ SQLUSMALLINT nAskFor( SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES2 );
+ switch(setType)
+ {
+ default:
+ case ResultSetType::FORWARD_ONLY:
+ nAskFor = SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES2;
+ break;
+ case ResultSetType::SCROLL_INSENSITIVE:
+ nAskFor = SQL_STATIC_CURSOR_ATTRIBUTES2;
+ break;
+ case ResultSetType::SCROLL_SENSITIVE:
+ nAskFor = SQL_DYNAMIC_CURSOR_ATTRIBUTES2;
+ break;
+ }
+
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,nAskFor,nValue,*this);
+ bool bRet = false;
+ switch(concurrency)
+ {
+ case ResultSetConcurrency::READ_ONLY:
+ bRet = (nValue & SQL_CA2_READ_ONLY_CONCURRENCY) == SQL_CA2_READ_ONLY_CONCURRENCY;
+ break;
+ case ResultSetConcurrency::UPDATABLE:
+ bRet = (nValue & SQL_CA2_OPT_VALUES_CONCURRENCY) == SQL_CA2_OPT_VALUES_CONCURRENCY;
+ break;
+ }
+ return bRet;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::ownUpdatesAreVisible( sal_Int32 setType )
+{
+ SQLUINTEGER nValue;
+ SQLUSMALLINT nAskFor( SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES2 );
+ switch(setType)
+ {
+ default:
+ case ResultSetType::FORWARD_ONLY:
+ nAskFor = SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES2;
+ break;
+ case ResultSetType::SCROLL_INSENSITIVE:
+ nAskFor = SQL_STATIC_CURSOR_ATTRIBUTES2;
+ break;
+ case ResultSetType::SCROLL_SENSITIVE:
+ nAskFor = SQL_DYNAMIC_CURSOR_ATTRIBUTES2;
+ break;
+ }
+
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,nAskFor,nValue,*this);
+ return (nValue & SQL_CA2_SENSITIVITY_UPDATES) == SQL_CA2_SENSITIVITY_UPDATES;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::ownDeletesAreVisible( sal_Int32 setType )
+{
+ SQLUINTEGER nValue;
+ SQLUSMALLINT nAskFor( SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES2 );
+ switch(setType)
+ {
+ default:
+ case ResultSetType::FORWARD_ONLY:
+ nAskFor = SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES2;
+ break;
+ case ResultSetType::SCROLL_INSENSITIVE:
+ nAskFor = SQL_STATIC_CURSOR_ATTRIBUTES2;
+ break;
+ case ResultSetType::SCROLL_SENSITIVE:
+ nAskFor = SQL_DYNAMIC_CURSOR_ATTRIBUTES2;
+ break;
+ }
+
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,nAskFor,nValue,*this);
+ return (nValue & SQL_CA2_SENSITIVITY_DELETIONS) != SQL_CA2_SENSITIVITY_DELETIONS;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::ownInsertsAreVisible( sal_Int32 setType )
+{
+ SQLUINTEGER nValue;
+ SQLUSMALLINT nAskFor( SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES2 );
+ switch(setType)
+ {
+ default:
+ case ResultSetType::FORWARD_ONLY:
+ nAskFor = SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES2;
+ break;
+ case ResultSetType::SCROLL_INSENSITIVE:
+ nAskFor = SQL_STATIC_CURSOR_ATTRIBUTES2;
+ break;
+ case ResultSetType::SCROLL_SENSITIVE:
+ nAskFor = SQL_DYNAMIC_CURSOR_ATTRIBUTES2;
+ break;
+ }
+
+ OTools::GetInfo(m_pConnection,m_aConnectionHandle,nAskFor,nValue,*this);
+ return (nValue & SQL_CA2_SENSITIVITY_ADDITIONS) == SQL_CA2_SENSITIVITY_ADDITIONS;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::othersUpdatesAreVisible( sal_Int32 setType )
+{
+ return ownUpdatesAreVisible(setType);
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::othersDeletesAreVisible( sal_Int32 setType )
+{
+ return ownDeletesAreVisible(setType);
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::othersInsertsAreVisible( sal_Int32 setType )
+{
+ return ownInsertsAreVisible(setType);
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::updatesAreDetected( sal_Int32 /*setType*/ )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::deletesAreDetected( sal_Int32 /*setType*/ )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::insertsAreDetected( sal_Int32 /*setType*/ )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsBatchUpdates( )
+{
+ return false;
+}
+
+Reference< XResultSet > SAL_CALL ODatabaseMetaData::getUDTs( const Any& /*catalog*/, const OUString& /*schemaPattern*/, const OUString& /*typeNamePattern*/, const Sequence< sal_Int32 >& /*types*/ )
+{
+ return nullptr;
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/odbc/ODatabaseMetaDataResultSet.cxx b/connectivity/source/drivers/odbc/ODatabaseMetaDataResultSet.cxx
new file mode 100644
index 0000000000..5fbe8bf8f4
--- /dev/null
+++ b/connectivity/source/drivers/odbc/ODatabaseMetaDataResultSet.cxx
@@ -0,0 +1,1330 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <TConnection.hxx>
+
+#include <odbc/ODatabaseMetaDataResultSet.hxx>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <comphelper/property.hxx>
+#include <cppuhelper/typeprovider.hxx>
+#include <comphelper/sequence.hxx>
+#include <odbc/OResultSetMetaData.hxx>
+#include <odbc/OTools.hxx>
+#include <comphelper/types.hxx>
+#include <connectivity/dbexception.hxx>
+
+using namespace ::comphelper;
+
+
+using namespace connectivity::odbc;
+using namespace cppu;
+
+using namespace ::com::sun::star::lang;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::sdbc;
+using namespace com::sun::star::util;
+
+
+ODatabaseMetaDataResultSet::ODatabaseMetaDataResultSet(OConnection* _pConnection)
+ :ODatabaseMetaDataResultSet_BASE(m_aMutex)
+ ,OPropertySetHelper(ODatabaseMetaDataResultSet_BASE::rBHelper)
+
+ ,m_aStatementHandle(_pConnection->createStatementHandle())
+ ,m_pConnection(_pConnection)
+ ,m_nTextEncoding(_pConnection->getTextEncoding())
+ ,m_nRowPos(-1)
+ ,m_nDriverColumnCount(0)
+ ,m_nCurrentFetchState(0)
+ ,m_bWasNull(true)
+ ,m_bEOF(false)
+{
+ OSL_ENSURE(m_pConnection.is(),"ODatabaseMetaDataResultSet::ODatabaseMetaDataResultSet: No parent set!");
+ if( SQL_NULL_HANDLE == m_aStatementHandle )
+ throw RuntimeException();
+
+ osl_atomic_increment( &m_refCount );
+ m_pRowStatusArray.reset( new SQLUSMALLINT[1] ); // the default value
+ osl_atomic_decrement( &m_refCount );
+}
+
+
+ODatabaseMetaDataResultSet::~ODatabaseMetaDataResultSet()
+{
+ OSL_ENSURE(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed,"Object wasn't disposed!");
+ if(!ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed)
+ {
+ osl_atomic_increment( &m_refCount );
+ dispose();
+ }
+}
+
+void ODatabaseMetaDataResultSet::disposing()
+{
+ OPropertySetHelper::disposing();
+
+ ::osl::MutexGuard aGuard(m_aMutex);
+
+ m_pConnection->freeStatementHandle(m_aStatementHandle);
+
+ m_aStatement.clear();
+ m_xMetaData.clear();
+ m_pConnection.clear();
+}
+
+Any SAL_CALL ODatabaseMetaDataResultSet::queryInterface( const Type & rType )
+{
+ Any aRet = OPropertySetHelper::queryInterface(rType);
+ return aRet.hasValue() ? aRet : ODatabaseMetaDataResultSet_BASE::queryInterface(rType);
+}
+
+Reference< XPropertySetInfo > SAL_CALL ODatabaseMetaDataResultSet::getPropertySetInfo( )
+{
+ return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper());
+}
+
+void SAL_CALL ODatabaseMetaDataResultSet::acquire() noexcept
+{
+ ODatabaseMetaDataResultSet_BASE::acquire();
+}
+
+void SAL_CALL ODatabaseMetaDataResultSet::release() noexcept
+{
+ ODatabaseMetaDataResultSet_BASE::release();
+}
+
+Sequence< Type > SAL_CALL ODatabaseMetaDataResultSet::getTypes( )
+{
+ ::cppu::OTypeCollection aTypes( cppu::UnoType<XMultiPropertySet>::get(),
+ cppu::UnoType<XFastPropertySet>::get(),
+ cppu::UnoType<XPropertySet>::get());
+
+ return ::comphelper::concatSequences(aTypes.getTypes(),ODatabaseMetaDataResultSet_BASE::getTypes());
+}
+
+sal_Int32 ODatabaseMetaDataResultSet::mapColumn (sal_Int32 column)
+{
+ sal_Int32 map = column;
+
+ if (!m_aColMapping.empty())
+ {
+ // Validate column number
+ map = m_aColMapping[column];
+ }
+
+ return map;
+}
+
+
+sal_Int32 SAL_CALL ODatabaseMetaDataResultSet::findColumn( const OUString& columnName )
+{
+
+ checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed);
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+
+ Reference< XResultSetMetaData > xMeta = getMetaData();
+ sal_Int32 nLen = xMeta->getColumnCount();
+ sal_Int32 i = 1;
+ for(;i<=nLen;++i)
+ {
+ if(xMeta->isCaseSensitive(i) ? columnName == xMeta->getColumnName(i) :
+ columnName.equalsIgnoreAsciiCase(xMeta->getColumnName(i)))
+ return i;
+ }
+
+ ::dbtools::throwInvalidColumnException( columnName, *this );
+ assert(false);
+ return 0; // Never reached
+}
+
+template < typename T, SQLSMALLINT sqlTypeId > T ODatabaseMetaDataResultSet::getInteger ( sal_Int32 columnIndex )
+{
+ ::cppu::OBroadcastHelper& rBHelper(ODatabaseMetaDataResultSet_BASE::rBHelper);
+ checkDisposed(rBHelper.bDisposed);
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ columnIndex = mapColumn(columnIndex);
+ T nVal = 0;
+ if(columnIndex <= m_nDriverColumnCount)
+ {
+ getValue<T>(m_pConnection.get(), m_aStatementHandle, columnIndex, sqlTypeId, m_bWasNull, **this, nVal);
+
+ if ( !m_aValueRange.empty() )
+ {
+ auto aValueRangeIter = m_aValueRange.find(columnIndex);
+ if ( aValueRangeIter != m_aValueRange.end() )
+ return static_cast<T>(aValueRangeIter->second[nVal]);
+ }
+ }
+ else
+ m_bWasNull = true;
+ return nVal;
+}
+
+
+Reference< css::io::XInputStream > SAL_CALL ODatabaseMetaDataResultSet::getBinaryStream( sal_Int32 /*columnIndex*/ )
+{
+ ::dbtools::throwFunctionNotSupportedSQLException( "XRow::getBinaryStream", *this );
+ return nullptr;
+}
+
+Reference< css::io::XInputStream > SAL_CALL ODatabaseMetaDataResultSet::getCharacterStream( sal_Int32 /*columnIndex*/ )
+{
+ ::dbtools::throwFunctionNotSupportedSQLException( "XRow::getCharacterStream", *this );
+ return nullptr;
+}
+
+
+sal_Bool SAL_CALL ODatabaseMetaDataResultSet::getBoolean( sal_Int32 columnIndex )
+{
+
+ checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed);
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ columnIndex = mapColumn(columnIndex);
+
+ bool bRet = false;
+ if(columnIndex <= m_nDriverColumnCount)
+ {
+ sal_Int32 nType = getMetaData()->getColumnType(columnIndex);
+ switch(nType)
+ {
+ case DataType::BIT:
+ {
+ sal_Int8 nValue = 0;
+ OTools::getValue(m_pConnection.get(),m_aStatementHandle,columnIndex,SQL_C_BIT,m_bWasNull,**this,&nValue,sizeof nValue);
+ bRet = nValue != 0;
+ }
+ break;
+ default:
+ bRet = getInt(columnIndex) != 0;
+ }
+ }
+ return bRet;
+}
+
+
+sal_Int8 SAL_CALL ODatabaseMetaDataResultSet::getByte( sal_Int32 columnIndex )
+{
+ return getInteger<sal_Int8, SQL_C_STINYINT>( columnIndex );
+}
+
+
+Sequence< sal_Int8 > SAL_CALL ODatabaseMetaDataResultSet::getBytes( sal_Int32 columnIndex )
+{
+
+ checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed);
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+
+ columnIndex = mapColumn(columnIndex);
+ if(columnIndex <= m_nDriverColumnCount)
+ {
+ sal_Int32 nType = getMetaData()->getColumnType(columnIndex);
+ switch(nType)
+ {
+ case DataType::CHAR:
+ case DataType::VARCHAR:
+ case DataType::LONGVARCHAR:
+ {
+ OUString const & aRet = OTools::getStringValue(m_pConnection.get(),m_aStatementHandle,columnIndex,SQL_C_BINARY,m_bWasNull,**this,m_nTextEncoding);
+ return Sequence<sal_Int8>(reinterpret_cast<const sal_Int8*>(aRet.getStr()),sizeof(sal_Unicode)*aRet.getLength());
+ }
+ }
+ return OTools::getBytesValue(m_pConnection.get(),m_aStatementHandle,columnIndex,SQL_C_BINARY,m_bWasNull,**this);
+ }
+ else
+ m_bWasNull = true;
+ return Sequence<sal_Int8>();
+}
+
+
+css::util::Date SAL_CALL ODatabaseMetaDataResultSet::getDate( sal_Int32 columnIndex )
+{
+ checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed);
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+
+ columnIndex = mapColumn(columnIndex);
+ if(columnIndex <= m_nDriverColumnCount)
+ {
+ DATE_STRUCT aDate;
+ aDate.day = 0;
+ aDate.month = 0;
+ aDate.year = 0;
+ OTools::getValue(m_pConnection.get(),m_aStatementHandle,columnIndex,m_pConnection->useOldDateFormat() ? SQL_C_DATE : SQL_C_TYPE_DATE,m_bWasNull,**this,&aDate,sizeof aDate);
+ return Date(aDate.day,aDate.month,aDate.year);
+ }
+ else
+ m_bWasNull = true;
+ return Date();
+}
+
+
+double SAL_CALL ODatabaseMetaDataResultSet::getDouble( sal_Int32 columnIndex )
+{
+
+ checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed);
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+
+ columnIndex = mapColumn(columnIndex);
+ double nValue(0.0);
+ if(columnIndex <= m_nDriverColumnCount)
+ OTools::getValue(m_pConnection.get(),m_aStatementHandle,columnIndex,SQL_C_DOUBLE,m_bWasNull,**this,&nValue,sizeof nValue);
+ else
+ m_bWasNull = true;
+ return nValue;
+}
+
+
+float SAL_CALL ODatabaseMetaDataResultSet::getFloat( sal_Int32 columnIndex )
+{
+
+ checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed);
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+
+ columnIndex = mapColumn(columnIndex);
+ float nVal(0);
+ if(columnIndex <= m_nDriverColumnCount)
+ OTools::getValue(m_pConnection.get(),m_aStatementHandle,columnIndex,SQL_C_FLOAT,m_bWasNull,**this,&nVal,sizeof nVal);
+ else
+ m_bWasNull = true;
+ return nVal;
+}
+
+
+sal_Int32 SAL_CALL ODatabaseMetaDataResultSet::getInt( sal_Int32 columnIndex )
+{
+ return getInteger<sal_Int32, SQL_C_SLONG>( columnIndex );
+}
+
+
+sal_Int32 SAL_CALL ODatabaseMetaDataResultSet::getRow( )
+{
+ return 0;
+}
+
+
+sal_Int64 SAL_CALL ODatabaseMetaDataResultSet::getLong( sal_Int32 columnIndex )
+{
+ return getInteger<sal_Int64, SQL_C_SBIGINT>( columnIndex );
+}
+
+
+Reference< XResultSetMetaData > SAL_CALL ODatabaseMetaDataResultSet::getMetaData( )
+{
+ checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed);
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if (!m_xMetaData.is())
+ m_xMetaData = new OResultSetMetaData(m_pConnection.get(),m_aStatementHandle);
+ return m_xMetaData;
+}
+
+Reference< XArray > SAL_CALL ODatabaseMetaDataResultSet::getArray( sal_Int32 /*columnIndex*/ )
+{
+ ::dbtools::throwFunctionNotSupportedSQLException( "XRow::getArray", *this );
+ return nullptr;
+}
+
+Reference< XClob > SAL_CALL ODatabaseMetaDataResultSet::getClob( sal_Int32 /*columnIndex*/ )
+{
+ ::dbtools::throwFunctionNotSupportedSQLException( "XRow::getClob", *this );
+ return nullptr;
+}
+
+Reference< XBlob > SAL_CALL ODatabaseMetaDataResultSet::getBlob( sal_Int32 /*columnIndex*/ )
+{
+ ::dbtools::throwFunctionNotSupportedSQLException( "XRow::getBlob", *this );
+ return nullptr;
+}
+
+
+Reference< XRef > SAL_CALL ODatabaseMetaDataResultSet::getRef( sal_Int32 /*columnIndex*/ )
+{
+ ::dbtools::throwFunctionNotSupportedSQLException( "XRow::getRef", *this );
+ return nullptr;
+}
+
+
+Any SAL_CALL ODatabaseMetaDataResultSet::getObject( sal_Int32 /*columnIndex*/, const Reference< css::container::XNameAccess >& /*typeMap*/ )
+{
+ ::dbtools::throwFunctionNotSupportedSQLException( "XRow::getObject", *this );
+ return Any();
+}
+
+
+sal_Int16 SAL_CALL ODatabaseMetaDataResultSet::getShort( sal_Int32 columnIndex )
+{
+ return getInteger<sal_Int16, SQL_C_SSHORT>( columnIndex );
+}
+
+
+OUString SAL_CALL ODatabaseMetaDataResultSet::getString( sal_Int32 columnIndex )
+{
+
+ checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed);
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+
+ columnIndex = mapColumn(columnIndex);
+ OUString aVal;
+ if(columnIndex <= m_nDriverColumnCount)
+ aVal = OTools::getStringValue(m_pConnection.get(),m_aStatementHandle,columnIndex,impl_getColumnType_nothrow(columnIndex),m_bWasNull,**this,m_nTextEncoding);
+ else
+ m_bWasNull = true;
+
+ return aVal;
+}
+
+
+css::util::Time SAL_CALL ODatabaseMetaDataResultSet::getTime( sal_Int32 columnIndex )
+{
+
+ checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed);
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+
+ columnIndex = mapColumn(columnIndex);
+ TIME_STRUCT aTime={0,0,0};
+ if(columnIndex <= m_nDriverColumnCount)
+ OTools::getValue(m_pConnection.get(),m_aStatementHandle,columnIndex,m_pConnection->useOldDateFormat() ? SQL_C_TIME : SQL_C_TYPE_TIME,m_bWasNull,**this,&aTime,sizeof aTime);
+ else
+ m_bWasNull = true;
+ return Time(0, aTime.second,aTime.minute,aTime.hour, false);
+}
+
+
+css::util::DateTime SAL_CALL ODatabaseMetaDataResultSet::getTimestamp( sal_Int32 columnIndex )
+{
+
+ checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed);
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+
+ columnIndex = mapColumn(columnIndex);
+ TIMESTAMP_STRUCT aTime={0,0,0,0,0,0,0};
+ if(columnIndex <= m_nDriverColumnCount)
+ OTools::getValue(m_pConnection.get(),m_aStatementHandle,columnIndex,m_pConnection->useOldDateFormat() ? SQL_C_TIMESTAMP : SQL_C_TYPE_TIMESTAMP, m_bWasNull, **this, &aTime, sizeof aTime);
+ else
+ m_bWasNull = true;
+ return DateTime(aTime.fraction, aTime.second, aTime.minute, aTime.hour,
+ aTime.day, aTime.month, aTime.year, false);
+}
+
+
+sal_Bool SAL_CALL ODatabaseMetaDataResultSet::isAfterLast( )
+{
+
+ checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed);
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+
+ return m_nCurrentFetchState == SQL_NO_DATA;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaDataResultSet::isFirst( )
+{
+
+ checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed);
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+
+ return m_nRowPos == 1;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaDataResultSet::isLast( )
+{
+
+ checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed);
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+
+ return m_bEOF && m_nCurrentFetchState != SQL_NO_DATA;
+}
+
+void SAL_CALL ODatabaseMetaDataResultSet::beforeFirst( )
+{
+
+ checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed);
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+
+ if(first())
+ previous();
+ m_nCurrentFetchState = SQL_SUCCESS;
+}
+
+void SAL_CALL ODatabaseMetaDataResultSet::afterLast( )
+{
+
+ checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed);
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+
+ if(last())
+ next();
+}
+
+
+void SAL_CALL ODatabaseMetaDataResultSet::close( )
+{
+ {
+
+ checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed);
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ }
+ dispose();
+}
+
+
+sal_Bool SAL_CALL ODatabaseMetaDataResultSet::first( )
+{
+
+ checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed);
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ m_bEOF = false;
+
+ m_nCurrentFetchState = N3SQLFetchScroll(m_aStatementHandle,SQL_FETCH_FIRST,0);
+ OTools::ThrowException(m_pConnection.get(),m_nCurrentFetchState,m_aStatementHandle,SQL_HANDLE_STMT,*this);
+ bool bRet = ( m_nCurrentFetchState == SQL_SUCCESS || m_nCurrentFetchState == SQL_SUCCESS_WITH_INFO );
+ if( bRet )
+ m_nRowPos = 1;
+ return bRet;
+}
+
+
+sal_Bool SAL_CALL ODatabaseMetaDataResultSet::last( )
+{
+ checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed );
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+
+ m_nCurrentFetchState = N3SQLFetchScroll(m_aStatementHandle,SQL_FETCH_LAST,0);
+ OTools::ThrowException(m_pConnection.get(),m_nCurrentFetchState,m_aStatementHandle,SQL_HANDLE_STMT,*this);
+ // here I know definitely that I stand on the last record
+ bool bRet = ( m_nCurrentFetchState == SQL_SUCCESS || m_nCurrentFetchState == SQL_SUCCESS_WITH_INFO );
+ if( bRet )
+ m_bEOF = true;
+ return bRet;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaDataResultSet::absolute( sal_Int32 row )
+{
+
+ checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed);
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ m_bEOF = false;
+
+ m_nCurrentFetchState = N3SQLFetchScroll(m_aStatementHandle,SQL_FETCH_ABSOLUTE,row);
+ OTools::ThrowException(m_pConnection.get(),m_nCurrentFetchState,m_aStatementHandle,SQL_HANDLE_STMT,*this);
+ bool bRet = m_nCurrentFetchState == SQL_SUCCESS || m_nCurrentFetchState == SQL_SUCCESS_WITH_INFO;
+ if(bRet)
+ m_nRowPos = row;
+ return bRet;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaDataResultSet::relative( sal_Int32 row )
+{
+
+ checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed);
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ m_bEOF = false;
+
+ m_nCurrentFetchState = N3SQLFetchScroll(m_aStatementHandle,SQL_FETCH_RELATIVE,row);
+ OTools::ThrowException(m_pConnection.get(),m_nCurrentFetchState,m_aStatementHandle,SQL_HANDLE_STMT,*this);
+ bool bRet = m_nCurrentFetchState == SQL_SUCCESS || m_nCurrentFetchState == SQL_SUCCESS_WITH_INFO;
+ if(bRet)
+ m_nRowPos += row;
+ return bRet;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaDataResultSet::previous( )
+{
+
+ checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed);
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ m_bEOF = false;
+
+ m_nCurrentFetchState = N3SQLFetchScroll(m_aStatementHandle,SQL_FETCH_PRIOR,0);
+ OTools::ThrowException(m_pConnection.get(),m_nCurrentFetchState,m_aStatementHandle,SQL_HANDLE_STMT,*this);
+ bool bRet = m_nCurrentFetchState == SQL_SUCCESS || m_nCurrentFetchState == SQL_SUCCESS_WITH_INFO;
+ if(bRet)
+ --m_nRowPos;
+ else if ( m_nCurrentFetchState == SQL_NO_DATA )
+ m_nRowPos = 0;
+ return bRet;
+}
+
+Reference< XInterface > SAL_CALL ODatabaseMetaDataResultSet::getStatement( )
+{
+ return nullptr;
+}
+
+
+sal_Bool SAL_CALL ODatabaseMetaDataResultSet::rowDeleted( )
+{
+
+ checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed);
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+
+ return m_pRowStatusArray[0] == SQL_ROW_DELETED;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaDataResultSet::rowInserted( )
+{
+ checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed);
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+
+ return m_pRowStatusArray[0] == SQL_ROW_ADDED;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaDataResultSet::rowUpdated( )
+{
+
+ checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed);
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+
+ return m_pRowStatusArray[0] == SQL_ROW_UPDATED;
+}
+
+
+sal_Bool SAL_CALL ODatabaseMetaDataResultSet::isBeforeFirst( )
+{
+
+ checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed);
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+
+ return m_nRowPos == 0;
+}
+
+
+sal_Bool SAL_CALL ODatabaseMetaDataResultSet::next( )
+{
+
+ checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed);
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ m_bEOF = false;
+
+ SQLRETURN nOldFetchStatus = m_nCurrentFetchState;
+ // m_nCurrentFetchState = N3SQLFetchScroll(m_aStatementHandle,SQL_FETCH_NEXT,0);
+ m_nCurrentFetchState = N3SQLFetch(m_aStatementHandle);
+ OTools::ThrowException(m_pConnection.get(),m_nCurrentFetchState,m_aStatementHandle,SQL_HANDLE_STMT,*this);
+ bool bRet = m_nCurrentFetchState == SQL_SUCCESS || m_nCurrentFetchState == SQL_SUCCESS_WITH_INFO;
+ if(bRet || ( m_nCurrentFetchState == SQL_NO_DATA && nOldFetchStatus != SQL_NO_DATA ) )
+ ++m_nRowPos;
+ return bRet;
+}
+
+
+sal_Bool SAL_CALL ODatabaseMetaDataResultSet::wasNull( )
+{
+
+ checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed);
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+
+ return m_bWasNull;
+}
+
+void SAL_CALL ODatabaseMetaDataResultSet::refreshRow( )
+{
+
+ checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed);
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+}
+
+
+void SAL_CALL ODatabaseMetaDataResultSet::cancel( )
+{
+
+ checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed);
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+
+ N3SQLCancel(m_aStatementHandle);
+}
+
+void SAL_CALL ODatabaseMetaDataResultSet::clearWarnings( )
+{
+}
+
+Any SAL_CALL ODatabaseMetaDataResultSet::getWarnings( )
+{
+ return Any();
+}
+
+sal_Int32 ODatabaseMetaDataResultSet::getFetchSize()
+{
+ return 1;
+}
+
+OUString ODatabaseMetaDataResultSet::getCursorName()
+{
+ return OUString();
+}
+
+
+::cppu::IPropertyArrayHelper* ODatabaseMetaDataResultSet::createArrayHelper( ) const
+{
+
+ return new ::cppu::OPropertyArrayHelper
+ {
+ {
+ {
+ ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_CURSORNAME),
+ PROPERTY_ID_CURSORNAME,
+ cppu::UnoType<OUString>::get(),
+ 0
+ },
+ {
+ ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHDIRECTION),
+ PROPERTY_ID_FETCHDIRECTION,
+ cppu::UnoType<sal_Int32>::get(),
+ 0
+ },
+ {
+ ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHSIZE),
+ PROPERTY_ID_FETCHSIZE,
+ cppu::UnoType<sal_Int32>::get(),
+ 0
+ },
+ {
+ ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETCONCURRENCY),
+ PROPERTY_ID_RESULTSETCONCURRENCY,
+ cppu::UnoType<sal_Int32>::get(),
+ 0
+ },
+ {
+ ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETTYPE),
+ PROPERTY_ID_RESULTSETTYPE,
+ cppu::UnoType<sal_Int32>::get(),
+ 0
+ }
+ }
+ };
+}
+
+::cppu::IPropertyArrayHelper & ODatabaseMetaDataResultSet::getInfoHelper()
+{
+ return *getArrayHelper();
+}
+
+sal_Bool ODatabaseMetaDataResultSet::convertFastPropertyValue(
+ Any & rConvertedValue,
+ Any & rOldValue,
+ sal_Int32 nHandle,
+ const Any& rValue )
+{
+ switch(nHandle)
+ {
+ case PROPERTY_ID_CURSORNAME:
+ case PROPERTY_ID_RESULTSETCONCURRENCY:
+ case PROPERTY_ID_RESULTSETTYPE:
+ throw css::lang::IllegalArgumentException();
+ case PROPERTY_ID_FETCHDIRECTION:
+ return ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, getFetchDirection());
+ case PROPERTY_ID_FETCHSIZE:
+ return ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, getFetchSize());
+ default:
+ ;
+ }
+ return false;
+}
+
+void ODatabaseMetaDataResultSet::setFastPropertyValue_NoBroadcast( sal_Int32 nHandle, const Any& /*rValue*/ )
+{
+ switch(nHandle)
+ {
+ case PROPERTY_ID_CURSORNAME:
+ case PROPERTY_ID_RESULTSETCONCURRENCY:
+ case PROPERTY_ID_RESULTSETTYPE:
+ case PROPERTY_ID_FETCHDIRECTION:
+ case PROPERTY_ID_FETCHSIZE:
+ throw Exception("cannot set prop " + OUString::number(nHandle), nullptr);
+ default:
+ OSL_FAIL("setFastPropertyValue_NoBroadcast: Illegal handle value!");
+ }
+}
+
+void ODatabaseMetaDataResultSet::getFastPropertyValue( Any& rValue, sal_Int32 nHandle ) const
+{
+ switch(nHandle)
+ {
+ case PROPERTY_ID_CURSORNAME:
+ rValue <<= getCursorName();
+ break;
+ case PROPERTY_ID_RESULTSETCONCURRENCY:
+ rValue <<= sal_Int32(css::sdbc::ResultSetConcurrency::READ_ONLY);
+ break;
+ case PROPERTY_ID_RESULTSETTYPE:
+ rValue <<= sal_Int32(css::sdbc::ResultSetType::FORWARD_ONLY);
+ break;
+ case PROPERTY_ID_FETCHDIRECTION:
+ rValue <<= getFetchDirection();
+ break;
+ case PROPERTY_ID_FETCHSIZE:
+ rValue <<= getFetchSize();
+ break;
+ }
+}
+
+void ODatabaseMetaDataResultSet::openTypeInfo()
+{
+ ::std::map<sal_Int32,sal_Int32> aMap;
+ aMap[SQL_BIT] = DataType::BIT;
+ aMap[SQL_TINYINT] = DataType::TINYINT;
+ aMap[SQL_SMALLINT] = DataType::SMALLINT;
+ aMap[SQL_INTEGER] = DataType::INTEGER;
+ aMap[SQL_FLOAT] = DataType::FLOAT;
+ aMap[SQL_REAL] = DataType::REAL;
+ aMap[SQL_DOUBLE] = DataType::DOUBLE;
+ aMap[SQL_BIGINT] = DataType::BIGINT;
+
+ aMap[SQL_CHAR] = DataType::CHAR;
+ aMap[SQL_WCHAR] = DataType::CHAR;
+ aMap[SQL_VARCHAR] = DataType::VARCHAR;
+ aMap[SQL_WVARCHAR] = DataType::VARCHAR;
+ aMap[SQL_LONGVARCHAR] = DataType::LONGVARCHAR;
+ aMap[SQL_WLONGVARCHAR] = DataType::LONGVARCHAR;
+
+ aMap[SQL_TYPE_DATE] = DataType::DATE;
+ aMap[SQL_DATE] = DataType::DATE;
+ aMap[SQL_TYPE_TIME] = DataType::TIME;
+ aMap[SQL_TIME] = DataType::TIME;
+ aMap[SQL_TYPE_TIMESTAMP] = DataType::TIMESTAMP;
+ aMap[SQL_TIMESTAMP] = DataType::TIMESTAMP;
+
+ aMap[SQL_DECIMAL] = DataType::DECIMAL;
+ aMap[SQL_NUMERIC] = DataType::NUMERIC;
+
+ aMap[SQL_BINARY] = DataType::BINARY;
+ aMap[SQL_VARBINARY] = DataType::VARBINARY;
+ aMap[SQL_LONGVARBINARY] = DataType::LONGVARBINARY;
+
+ aMap[SQL_GUID] = DataType::VARBINARY;
+
+
+ m_aValueRange[2] = aMap;
+
+ OTools::ThrowException(m_pConnection.get(),N3SQLGetTypeInfo(m_aStatementHandle, SQL_ALL_TYPES),m_aStatementHandle,SQL_HANDLE_STMT,*this);
+ checkColumnCount();
+}
+
+void ODatabaseMetaDataResultSet::openTables(const Any& catalog, const OUString& schemaPattern,
+ std::u16string_view tableNamePattern,
+ const Sequence< OUString >& types )
+{
+ OString aPKQ,aPKO,aPKN,aCOL;
+ const OUString *pSchemaPat = nullptr;
+
+ if(schemaPattern != "%")
+ pSchemaPat = &schemaPattern;
+ else
+ pSchemaPat = nullptr;
+
+ if ( catalog.hasValue() )
+ aPKQ = OUStringToOString(comphelper::getString(catalog),m_nTextEncoding);
+ aPKO = OUStringToOString(schemaPattern,m_nTextEncoding);
+ aPKN = OUStringToOString(tableNamePattern,m_nTextEncoding);
+
+ const char *pPKQ = catalog.hasValue() && !aPKQ.isEmpty() ? aPKQ.getStr() : nullptr,
+ *pPKO = pSchemaPat && !pSchemaPat->isEmpty() && !aPKO.isEmpty() ? aPKO.getStr() : nullptr,
+ *pPKN = aPKN.getStr();
+
+
+ const char *pCOL = nullptr;
+ const char* const pComma = ",";
+ const OUString* pBegin = types.getConstArray();
+ const OUString* pEnd = pBegin + types.getLength();
+ for(;pBegin != pEnd;++pBegin)
+ {
+ aCOL += OUStringToOString(*pBegin,m_nTextEncoding) + pComma;
+ }
+ if ( !aCOL.isEmpty() )
+ {
+ aCOL = aCOL.replaceAt(aCOL.getLength()-1,1,pComma);
+ pCOL = aCOL.getStr();
+ }
+ else
+ pCOL = SQL_ALL_TABLE_TYPES;
+
+ SQLRETURN nRetcode = N3SQLTables(m_aStatementHandle,
+ reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pPKQ)), (catalog.hasValue() && !aPKQ.isEmpty()) ? SQL_NTS : 0,
+ reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pPKO)), pPKO ? SQL_NTS : 0,
+ reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pPKN)), SQL_NTS,
+ reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pCOL)), pCOL ? SQL_NTS : 0);
+ OTools::ThrowException(m_pConnection.get(),nRetcode,m_aStatementHandle,SQL_HANDLE_STMT,*this);
+ checkColumnCount();
+
+}
+
+void ODatabaseMetaDataResultSet::openTablesTypes( )
+{
+ SQLRETURN nRetcode = N3SQLTables(m_aStatementHandle,
+ nullptr,0,
+ nullptr,0,
+ nullptr,0,
+ reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(SQL_ALL_TABLE_TYPES)),SQL_NTS);
+ OTools::ThrowException(m_pConnection.get(),nRetcode,m_aStatementHandle,SQL_HANDLE_STMT,*this);
+
+ m_aColMapping.clear();
+ m_aColMapping.push_back(-1);
+ m_aColMapping.push_back(4);
+ m_xMetaData = new OResultSetMetaData(m_pConnection.get(),m_aStatementHandle,std::vector(m_aColMapping));
+ checkColumnCount();
+}
+
+void ODatabaseMetaDataResultSet::openCatalogs()
+{
+ SQLRETURN nRetcode = N3SQLTables(m_aStatementHandle,
+ reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(SQL_ALL_CATALOGS)),SQL_NTS,
+ reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>("")),SQL_NTS,
+ reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>("")),SQL_NTS,
+ reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>("")),SQL_NTS);
+
+ OTools::ThrowException(m_pConnection.get(),nRetcode,m_aStatementHandle,SQL_HANDLE_STMT,*this);
+
+ m_aColMapping.clear();
+ m_aColMapping.push_back(-1);
+ m_aColMapping.push_back(1);
+ m_xMetaData = new OResultSetMetaData(m_pConnection.get(),m_aStatementHandle,std::vector(m_aColMapping));
+ checkColumnCount();
+}
+
+void ODatabaseMetaDataResultSet::openSchemas()
+{
+ SQLRETURN nRetcode = N3SQLTables(m_aStatementHandle,
+ reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>("")),SQL_NTS,
+ reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(SQL_ALL_SCHEMAS)),SQL_NTS,
+ reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>("")),SQL_NTS,
+ reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>("")),SQL_NTS);
+ OTools::ThrowException(m_pConnection.get(),nRetcode,m_aStatementHandle,SQL_HANDLE_STMT,*this);
+
+ m_aColMapping.clear();
+ m_aColMapping.push_back(-1);
+ m_aColMapping.push_back(2);
+ m_xMetaData = new OResultSetMetaData(m_pConnection.get(),m_aStatementHandle,std::vector(m_aColMapping));
+ checkColumnCount();
+}
+
+void ODatabaseMetaDataResultSet::openColumnPrivileges( const Any& catalog, const OUString& schema,
+ std::u16string_view table,
+ std::u16string_view columnNamePattern )
+{
+ const OUString *pSchemaPat = nullptr;
+
+ if(schema != "%")
+ pSchemaPat = &schema;
+ else
+ pSchemaPat = nullptr;
+
+ OString aPKQ,aPKO,aPKN,aCOL;
+
+ if ( catalog.hasValue() )
+ aPKQ = OUStringToOString(comphelper::getString(catalog),m_nTextEncoding);
+ aPKO = OUStringToOString(schema,m_nTextEncoding);
+ aPKN = OUStringToOString(table,m_nTextEncoding);
+ aCOL = OUStringToOString(columnNamePattern,m_nTextEncoding);
+
+ const char *pPKQ = catalog.hasValue() && !aPKQ.isEmpty() ? aPKQ.getStr() : nullptr,
+ *pPKO = pSchemaPat && !pSchemaPat->isEmpty() && !aPKO.isEmpty() ? aPKO.getStr() : nullptr,
+ *pPKN = aPKN.getStr(),
+ *pCOL = aCOL.getStr();
+
+
+ SQLRETURN nRetcode = N3SQLColumnPrivileges(m_aStatementHandle,
+ reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pPKQ)), (catalog.hasValue() && !aPKQ.isEmpty()) ? SQL_NTS : 0,
+ reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pPKO)), pPKO ? SQL_NTS : 0 ,
+ reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pPKN)), SQL_NTS,
+ reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pCOL)), SQL_NTS);
+ OTools::ThrowException(m_pConnection.get(),nRetcode,m_aStatementHandle,SQL_HANDLE_STMT,*this);
+
+ checkColumnCount();
+}
+
+void ODatabaseMetaDataResultSet::openColumns( const Any& catalog, const OUString& schemaPattern,
+ std::u16string_view tableNamePattern, std::u16string_view columnNamePattern )
+{
+ const OUString *pSchemaPat = nullptr;
+
+ if(schemaPattern != "%")
+ pSchemaPat = &schemaPattern;
+ else
+ pSchemaPat = nullptr;
+
+ OString aPKQ,aPKO,aPKN,aCOL;
+ if ( catalog.hasValue() )
+ aPKQ = OUStringToOString(comphelper::getString(catalog),m_nTextEncoding);
+ aPKO = OUStringToOString(schemaPattern,m_nTextEncoding);
+ aPKN = OUStringToOString(tableNamePattern,m_nTextEncoding);
+ aCOL = OUStringToOString(columnNamePattern,m_nTextEncoding);
+
+ const char *pPKQ = catalog.hasValue() && !aPKQ.isEmpty() ? aPKQ.getStr() : nullptr,
+ *pPKO = pSchemaPat && !pSchemaPat->isEmpty() && !aPKO.isEmpty() ? aPKO.getStr() : nullptr,
+ *pPKN = aPKN.getStr(),
+ *pCOL = aCOL.getStr();
+
+
+ SQLRETURN nRetcode = N3SQLColumns(m_aStatementHandle,
+ reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pPKQ)), (catalog.hasValue() && !aPKQ.isEmpty()) ? SQL_NTS : 0,
+ reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pPKO)), pPKO ? SQL_NTS : 0,
+ reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pPKN)), SQL_NTS,
+ reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pCOL)), SQL_NTS);
+
+ OTools::ThrowException(m_pConnection.get(),nRetcode,m_aStatementHandle,SQL_HANDLE_STMT,*this);
+ ::std::map<sal_Int32,sal_Int32> aMap;
+ aMap[SQL_BIT] = DataType::BIT;
+ aMap[SQL_TINYINT] = DataType::TINYINT;
+ aMap[SQL_SMALLINT] = DataType::SMALLINT;
+ aMap[SQL_INTEGER] = DataType::INTEGER;
+ aMap[SQL_FLOAT] = DataType::FLOAT;
+ aMap[SQL_REAL] = DataType::REAL;
+ aMap[SQL_DOUBLE] = DataType::DOUBLE;
+ aMap[SQL_BIGINT] = DataType::BIGINT;
+
+ aMap[SQL_CHAR] = DataType::CHAR;
+ aMap[SQL_WCHAR] = DataType::CHAR;
+ aMap[SQL_VARCHAR] = DataType::VARCHAR;
+ aMap[SQL_WVARCHAR] = DataType::VARCHAR;
+ aMap[SQL_LONGVARCHAR] = DataType::LONGVARCHAR;
+ aMap[SQL_WLONGVARCHAR] = DataType::LONGVARCHAR;
+
+ aMap[SQL_TYPE_DATE] = DataType::DATE;
+ aMap[SQL_DATE] = DataType::DATE;
+ aMap[SQL_TYPE_TIME] = DataType::TIME;
+ aMap[SQL_TIME] = DataType::TIME;
+ aMap[SQL_TYPE_TIMESTAMP] = DataType::TIMESTAMP;
+ aMap[SQL_TIMESTAMP] = DataType::TIMESTAMP;
+
+ aMap[SQL_DECIMAL] = DataType::DECIMAL;
+ aMap[SQL_NUMERIC] = DataType::NUMERIC;
+
+ aMap[SQL_BINARY] = DataType::BINARY;
+ aMap[SQL_VARBINARY] = DataType::VARBINARY;
+ aMap[SQL_LONGVARBINARY] = DataType::LONGVARBINARY;
+
+ aMap[SQL_GUID] = DataType::VARBINARY;
+
+ m_aValueRange[5] = aMap;
+ checkColumnCount();
+}
+
+void ODatabaseMetaDataResultSet::openProcedureColumns( const Any& catalog, const OUString& schemaPattern,
+ std::u16string_view procedureNamePattern,std::u16string_view columnNamePattern )
+{
+ const OUString *pSchemaPat = nullptr;
+
+ if(schemaPattern != "%")
+ pSchemaPat = &schemaPattern;
+ else
+ pSchemaPat = nullptr;
+
+ OString aPKQ,aPKO,aPKN,aCOL;
+ if ( catalog.hasValue() )
+ aPKQ = OUStringToOString(comphelper::getString(catalog),m_nTextEncoding);
+ aPKO = OUStringToOString(schemaPattern,m_nTextEncoding);
+ aPKN = OUStringToOString(procedureNamePattern,m_nTextEncoding);
+ aCOL = OUStringToOString(columnNamePattern,m_nTextEncoding);
+
+ const char *pPKQ = catalog.hasValue() && !aPKQ.isEmpty() ? aPKQ.getStr() : nullptr,
+ *pPKO = pSchemaPat && !pSchemaPat->isEmpty() && !aPKO.isEmpty() ? aPKO.getStr() : nullptr,
+ *pPKN = aPKN.getStr(),
+ *pCOL = aCOL.getStr();
+
+
+ SQLRETURN nRetcode = N3SQLProcedureColumns(m_aStatementHandle,
+ reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pPKQ)), (catalog.hasValue() && !aPKQ.isEmpty()) ? SQL_NTS : 0,
+ reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pPKO)), pPKO ? SQL_NTS : 0 ,
+ reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pPKN)), SQL_NTS,
+ reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pCOL)), SQL_NTS);
+
+ OTools::ThrowException(m_pConnection.get(),nRetcode,m_aStatementHandle,SQL_HANDLE_STMT,*this);
+ checkColumnCount();
+}
+
+void ODatabaseMetaDataResultSet::openProcedures(const Any& catalog, const OUString& schemaPattern,
+ std::u16string_view procedureNamePattern)
+{
+ const OUString *pSchemaPat = nullptr;
+
+ if(schemaPattern != "%")
+ pSchemaPat = &schemaPattern;
+ else
+ pSchemaPat = nullptr;
+
+ OString aPKQ,aPKO,aPKN;
+
+ if ( catalog.hasValue() )
+ aPKQ = OUStringToOString(comphelper::getString(catalog),m_nTextEncoding);
+ aPKO = OUStringToOString(schemaPattern,m_nTextEncoding);
+ aPKN = OUStringToOString(procedureNamePattern,m_nTextEncoding);
+
+ const char *pPKQ = catalog.hasValue() && !aPKQ.isEmpty() ? aPKQ.getStr() : nullptr,
+ *pPKO = pSchemaPat && !pSchemaPat->isEmpty() && !aPKO.isEmpty() ? aPKO.getStr() : nullptr,
+ *pPKN = aPKN.getStr();
+
+
+ SQLRETURN nRetcode = N3SQLProcedures(m_aStatementHandle,
+ reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pPKQ)), (catalog.hasValue() && !aPKQ.isEmpty()) ? SQL_NTS : 0,
+ reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pPKO)), pPKO ? SQL_NTS : 0 ,
+ reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pPKN)), SQL_NTS);
+ OTools::ThrowException(m_pConnection.get(),nRetcode,m_aStatementHandle,SQL_HANDLE_STMT,*this);
+ checkColumnCount();
+}
+
+void ODatabaseMetaDataResultSet::openSpecialColumns(bool _bRowVer,const Any& catalog, const OUString& schema,
+ std::u16string_view table,sal_Int32 scope, bool nullable )
+{
+ // Some ODBC drivers really don't like getting an empty string as tableName
+ // E.g. psqlodbc up to at least version 09.01.0100 segfaults
+ if (table.empty())
+ {
+ static constexpr OUStringLiteral errMsg
+ = u"ODBC: Trying to get special columns of empty table name";
+ static constexpr OUStringLiteral SQLState = u"HY009";
+ throw SQLException( errMsg, *this, SQLState, -1, Any() );
+ }
+
+ const OUString *pSchemaPat = nullptr;
+
+ if(schema != "%")
+ pSchemaPat = &schema;
+ else
+ pSchemaPat = nullptr;
+
+ OString aPKQ,aPKO,aPKN;
+ if ( catalog.hasValue() )
+ aPKQ = OUStringToOString(comphelper::getString(catalog),m_nTextEncoding);
+ aPKO = OUStringToOString(schema,m_nTextEncoding);
+ aPKN = OUStringToOString(table,m_nTextEncoding);
+
+ const char *pPKQ = catalog.hasValue() && !aPKQ.isEmpty() ? aPKQ.getStr() : nullptr,
+ *pPKO = pSchemaPat && !pSchemaPat->isEmpty() && !aPKO.isEmpty() ? aPKO.getStr() : nullptr,
+ *pPKN = aPKN.getStr();
+
+
+ SQLRETURN nRetcode = N3SQLSpecialColumns(m_aStatementHandle,_bRowVer ? SQL_ROWVER : SQL_BEST_ROWID,
+ reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pPKQ)), (catalog.hasValue() && !aPKQ.isEmpty()) ? SQL_NTS : 0,
+ reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pPKO)), pPKO ? SQL_NTS : 0 ,
+ reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pPKN)), SQL_NTS,
+ static_cast<SQLSMALLINT>(scope),
+ nullable ? SQL_NULLABLE : SQL_NO_NULLS);
+ OTools::ThrowException(m_pConnection.get(),nRetcode,m_aStatementHandle,SQL_HANDLE_STMT,*this);
+ checkColumnCount();
+}
+
+void ODatabaseMetaDataResultSet::openVersionColumns(const Any& catalog, const OUString& schema,
+ std::u16string_view table)
+{
+ openSpecialColumns(true,catalog,schema,table,SQL_SCOPE_TRANSACTION,false);
+}
+
+void ODatabaseMetaDataResultSet::openBestRowIdentifier( const Any& catalog, const OUString& schema,
+ std::u16string_view table,sal_Int32 scope,bool nullable )
+{
+ openSpecialColumns(false,catalog,schema,table,scope,nullable);
+}
+
+void ODatabaseMetaDataResultSet::openForeignKeys( const Any& catalog, const OUString* schema,
+ const OUString* table,
+ const Any& catalog2, const OUString* schema2,
+ const OUString* table2)
+{
+ OString aPKQ, aPKO, aPKN, aFKQ, aFKO, aFKN;
+ if ( catalog.hasValue() )
+ aPKQ = OUStringToOString(comphelper::getString(catalog),m_nTextEncoding);
+ if ( catalog2.hasValue() )
+ aFKQ = OUStringToOString(comphelper::getString(catalog2),m_nTextEncoding);
+
+ const char *pPKQ = catalog.hasValue() && !aPKQ.isEmpty() ? aPKQ.getStr() : nullptr;
+ const char *pPKO = nullptr;
+ if (schema && !schema->isEmpty())
+ {
+ aPKO = OUStringToOString(*schema,m_nTextEncoding);
+ pPKO = aPKO.getStr();
+ }
+ const char *pPKN = nullptr;
+ if (table)
+ {
+ aPKN = OUStringToOString(*table,m_nTextEncoding);
+ pPKN = aPKN.getStr();
+ }
+ const char *pFKQ = catalog2.hasValue() && !aFKQ.isEmpty() ? aFKQ.getStr() : nullptr;
+ const char *pFKO = nullptr;
+ if (schema2 && !schema2->isEmpty())
+ {
+ aFKO = OUStringToOString(*schema2,m_nTextEncoding);
+ pFKO = aFKO.getStr();
+ }
+ const char *pFKN = nullptr;
+ if (table2)
+ {
+ aFKN = OUStringToOString(*table2,m_nTextEncoding);
+ pFKN = aFKN.getStr();
+ }
+
+ SQLRETURN nRetcode = N3SQLForeignKeys(m_aStatementHandle,
+ reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pPKQ)), (catalog.hasValue() && !aPKQ.isEmpty()) ? SQL_NTS : 0,
+ reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pPKO)), pPKO ? SQL_NTS : 0,
+ reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pPKN)), pPKN ? SQL_NTS : 0,
+ reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pFKQ)), (catalog2.hasValue() && !aFKQ.isEmpty()) ? SQL_NTS : 0,
+ reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pFKO)), pFKO ? SQL_NTS : 0,
+ reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pFKN)), SQL_NTS
+ );
+ OTools::ThrowException(m_pConnection.get(),nRetcode,m_aStatementHandle,SQL_HANDLE_STMT,*this);
+ checkColumnCount();
+}
+
+void ODatabaseMetaDataResultSet::openImportedKeys(const Any& catalog, const OUString& schema,
+ const OUString& table)
+{
+
+ openForeignKeys(Any(),nullptr,nullptr,catalog, schema == "%" ? &schema : nullptr, &table);
+}
+
+void ODatabaseMetaDataResultSet::openExportedKeys(const Any& catalog, const OUString& schema,
+ const OUString& table)
+{
+ openForeignKeys(catalog, schema == "%" ? &schema : nullptr, &table,Any(),nullptr,nullptr);
+}
+
+void ODatabaseMetaDataResultSet::openPrimaryKeys(const Any& catalog, const OUString& schema,
+ std::u16string_view table)
+{
+ const OUString *pSchemaPat = nullptr;
+
+ if(schema != "%")
+ pSchemaPat = &schema;
+ else
+ pSchemaPat = nullptr;
+
+ OString aPKQ,aPKO,aPKN;
+
+ if ( catalog.hasValue() )
+ aPKQ = OUStringToOString(comphelper::getString(catalog),m_nTextEncoding);
+ aPKO = OUStringToOString(schema,m_nTextEncoding);
+ aPKN = OUStringToOString(table,m_nTextEncoding);
+
+ const char *pPKQ = catalog.hasValue() && !aPKQ.isEmpty() ? aPKQ.getStr() : nullptr,
+ *pPKO = pSchemaPat && !pSchemaPat->isEmpty() && !aPKO.isEmpty() ? aPKO.getStr() : nullptr,
+ *pPKN = aPKN.getStr();
+
+
+ SQLRETURN nRetcode = N3SQLPrimaryKeys(m_aStatementHandle,
+ reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pPKQ)), (catalog.hasValue() && !aPKQ.isEmpty()) ? SQL_NTS : 0,
+ reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pPKO)), pPKO ? SQL_NTS : 0 ,
+ reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pPKN)), SQL_NTS);
+ OTools::ThrowException(m_pConnection.get(),nRetcode,m_aStatementHandle,SQL_HANDLE_STMT,*this);
+ checkColumnCount();
+}
+
+void ODatabaseMetaDataResultSet::openTablePrivileges(const Any& catalog, const OUString& schemaPattern,
+ std::u16string_view tableNamePattern)
+{
+ const OUString *pSchemaPat = nullptr;
+
+ if(schemaPattern != "%")
+ pSchemaPat = &schemaPattern;
+ else
+ pSchemaPat = nullptr;
+
+ OString aPKQ,aPKO,aPKN;
+
+ if ( catalog.hasValue() )
+ aPKQ = OUStringToOString(comphelper::getString(catalog),m_nTextEncoding);
+ aPKO = OUStringToOString(schemaPattern,m_nTextEncoding);
+ aPKN = OUStringToOString(tableNamePattern,m_nTextEncoding);
+
+ const char *pPKQ = catalog.hasValue() && !aPKQ.isEmpty() ? aPKQ.getStr() : nullptr,
+ *pPKO = pSchemaPat && !pSchemaPat->isEmpty() && !aPKO.isEmpty() ? aPKO.getStr() : nullptr,
+ *pPKN = aPKN.getStr();
+
+ SQLRETURN nRetcode = N3SQLTablePrivileges(m_aStatementHandle,
+ reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pPKQ)), (catalog.hasValue() && !aPKQ.isEmpty()) ? SQL_NTS : 0,
+ reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pPKO)), pPKO ? SQL_NTS : 0 ,
+ reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pPKN)), SQL_NTS);
+ OTools::ThrowException(m_pConnection.get(),nRetcode,m_aStatementHandle,SQL_HANDLE_STMT,*this);
+ checkColumnCount();
+}
+
+void ODatabaseMetaDataResultSet::openIndexInfo( const Any& catalog, const OUString& schema,
+ std::u16string_view table, bool unique, bool approximate )
+{
+ const OUString *pSchemaPat = nullptr;
+
+ if(schema != "%")
+ pSchemaPat = &schema;
+ else
+ pSchemaPat = nullptr;
+
+ OString aPKQ,aPKO,aPKN;
+
+ if ( catalog.hasValue() )
+ aPKQ = OUStringToOString(comphelper::getString(catalog),m_nTextEncoding);
+ aPKO = OUStringToOString(schema,m_nTextEncoding);
+ aPKN = OUStringToOString(table,m_nTextEncoding);
+
+ const char *pPKQ = catalog.hasValue() && !aPKQ.isEmpty() ? aPKQ.getStr() : nullptr,
+ *pPKO = pSchemaPat && !pSchemaPat->isEmpty() && !aPKO.isEmpty() ? aPKO.getStr() : nullptr,
+ *pPKN = aPKN.getStr();
+
+ SQLRETURN nRetcode = N3SQLStatistics(m_aStatementHandle,
+ reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pPKQ)), (catalog.hasValue() && !aPKQ.isEmpty()) ? SQL_NTS : 0,
+ reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pPKO)), pPKO ? SQL_NTS : 0 ,
+ reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pPKN)), SQL_NTS,
+ unique ? SQL_INDEX_UNIQUE : SQL_INDEX_ALL,
+ approximate ? 1 : 0);
+ OTools::ThrowException(m_pConnection.get(),nRetcode,m_aStatementHandle,SQL_HANDLE_STMT,*this);
+ checkColumnCount();
+}
+
+void ODatabaseMetaDataResultSet::checkColumnCount()
+{
+ sal_Int16 nNumResultCols=0;
+ OTools::ThrowException(m_pConnection.get(),N3SQLNumResultCols(m_aStatementHandle,&nNumResultCols),m_aStatementHandle,SQL_HANDLE_STMT,*this);
+ m_nDriverColumnCount = nNumResultCols;
+}
+
+
+SWORD ODatabaseMetaDataResultSet::impl_getColumnType_nothrow(sal_Int32 columnIndex)
+{
+ std::map<sal_Int32,SWORD>::iterator aFind = m_aODBCColumnTypes.find(columnIndex);
+ if ( aFind == m_aODBCColumnTypes.end() )
+ aFind = m_aODBCColumnTypes.emplace(
+ columnIndex,
+ OResultSetMetaData::getColumnODBCType(m_pConnection.get(),m_aStatementHandle,*this,columnIndex)
+ ).first;
+ return aFind->second;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/odbc/ODriver.cxx b/connectivity/source/drivers/odbc/ODriver.cxx
new file mode 100644
index 0000000000..cf3c5596aa
--- /dev/null
+++ b/connectivity/source/drivers/odbc/ODriver.cxx
@@ -0,0 +1,193 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <odbc/ODriver.hxx>
+#include <odbc/OConnection.hxx>
+#include <odbc/OTools.hxx>
+#include <connectivity/dbexception.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <strings.hrc>
+#include <resource/sharedresources.hxx>
+#include <utility>
+
+using namespace connectivity::odbc;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::sdbc;
+
+ODBCDriver::ODBCDriver(css::uno::Reference< css::uno::XComponentContext > _xContext)
+ :ODriver_BASE(m_aMutex)
+ ,m_xContext(std::move(_xContext))
+ ,m_pDriverHandle(SQL_NULL_HANDLE)
+{
+}
+
+void ODBCDriver::disposing()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+
+
+ for (auto const& connection : m_xConnections)
+ {
+ Reference< XComponent > xComp(connection.get(), UNO_QUERY);
+ if (xComp.is())
+ xComp->dispose();
+ }
+ m_xConnections.clear();
+
+ ODriver_BASE::disposing();
+}
+
+// static ServiceInfo
+
+OUString ODBCDriver::getImplementationName( )
+{
+ return "com.sun.star.comp.sdbc.ODBCDriver";
+ // this name is referenced in the configuration and in the odbc.xml
+ // Please take care when changing it.
+}
+
+
+Sequence< OUString > ODBCDriver::getSupportedServiceNames( )
+{
+ return { "com.sun.star.sdbc.Driver" };
+}
+
+
+sal_Bool SAL_CALL ODBCDriver::supportsService( const OUString& _rServiceName )
+{
+ return cppu::supportsService(this, _rServiceName);
+}
+
+
+Reference< XConnection > SAL_CALL ODBCDriver::connect( const OUString& url, const Sequence< PropertyValue >& info )
+{
+ if ( ! acceptsURL(url) )
+ return nullptr;
+
+ if(!m_pDriverHandle)
+ {
+ OUString aPath;
+ if(!EnvironmentHandle(aPath))
+ throw SQLException(aPath,*this,OUString(),1000,Any());
+ }
+ rtl::Reference<OConnection> pCon = new OConnection(m_pDriverHandle,this);
+ pCon->Construct(url,info);
+ m_xConnections.push_back(WeakReferenceHelper(*pCon));
+
+ return pCon;
+}
+
+sal_Bool SAL_CALL ODBCDriver::acceptsURL( const OUString& url )
+{
+ return url.startsWith("sdbc:odbc:");
+}
+
+Sequence< DriverPropertyInfo > SAL_CALL ODBCDriver::getPropertyInfo( const OUString& url, const Sequence< PropertyValue >& /*info*/ )
+{
+ if ( acceptsURL(url) )
+ {
+ Sequence< OUString > aBooleanValues{ "false", "true" };
+
+ return
+ {
+ {
+ "CharSet",
+ "CharSet of the database.",
+ false,
+ {},
+ {}
+ },
+ {
+ "UseCatalog",
+ "Use catalog for file-based databases.",
+ false,
+ "false",
+ aBooleanValues
+ },
+ {
+ "SystemDriverSettings",
+ "Driver settings.",
+ false,
+ {},
+ {}
+ },
+ {
+ "ParameterNameSubstitution",
+ "Change named parameters with '?'.",
+ false,
+ "false",
+ aBooleanValues
+ },
+ {
+ "IgnoreDriverPrivileges",
+ "Ignore the privileges from the database driver.",
+ false,
+ "false",
+ aBooleanValues
+ },
+ {
+ "IsAutoRetrievingEnabled",
+ "Retrieve generated values.",
+ false,
+ "false",
+ aBooleanValues
+ },
+ {
+ "AutoRetrievingStatement",
+ "Auto-increment statement.",
+ false,
+ {},
+ {}
+ },
+ {
+ "GenerateASBeforeCorrelationName",
+ "Generate AS before table correlation names.",
+ false,
+ "false",
+ aBooleanValues
+ },
+ {
+ "EscapeDateTime",
+ "Escape date time format.",
+ false,
+ "true",
+ aBooleanValues
+ }
+ };
+ }
+ ::connectivity::SharedResources aResources;
+ const OUString sMessage = aResources.getResourceString(STR_URI_SYNTAX_ERROR);
+ ::dbtools::throwGenericSQLException(sMessage ,*this);
+ return Sequence< DriverPropertyInfo >();
+}
+
+sal_Int32 SAL_CALL ODBCDriver::getMajorVersion( )
+{
+ return 1;
+}
+
+sal_Int32 SAL_CALL ODBCDriver::getMinorVersion( )
+{
+ return 0;
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/odbc/OFunctions.cxx b/connectivity/source/drivers/odbc/OFunctions.cxx
new file mode 100644
index 0000000000..951eb8b36b
--- /dev/null
+++ b/connectivity/source/drivers/odbc/OFunctions.cxx
@@ -0,0 +1,245 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <odbc/OFunctions.hxx>
+
+// Implib definitions for ODBC-DLL/shared library:
+
+namespace connectivity
+{
+ T3SQLAllocHandle pODBC3SQLAllocHandle;
+T3SQLConnect pODBC3SQLConnect;
+T3SQLDriverConnect pODBC3SQLDriverConnect;
+T3SQLBrowseConnect pODBC3SQLBrowseConnect;
+T3SQLDataSources pODBC3SQLDataSources;
+T3SQLDrivers pODBC3SQLDrivers;
+T3SQLGetInfo pODBC3SQLGetInfo;
+T3SQLGetFunctions pODBC3SQLGetFunctions;
+T3SQLGetTypeInfo pODBC3SQLGetTypeInfo;
+T3SQLSetConnectAttr pODBC3SQLSetConnectAttr;
+T3SQLGetConnectAttr pODBC3SQLGetConnectAttr;
+T3SQLSetEnvAttr pODBC3SQLSetEnvAttr;
+T3SQLGetEnvAttr pODBC3SQLGetEnvAttr;
+T3SQLSetStmtAttr pODBC3SQLSetStmtAttr;
+T3SQLGetStmtAttr pODBC3SQLGetStmtAttr;
+T3SQLPrepare pODBC3SQLPrepare;
+T3SQLBindParameter pODBC3SQLBindParameter;
+T3SQLSetCursorName pODBC3SQLSetCursorName;
+T3SQLExecute pODBC3SQLExecute;
+T3SQLExecDirect pODBC3SQLExecDirect;
+T3SQLDescribeParam pODBC3SQLDescribeParam;
+T3SQLNumParams pODBC3SQLNumParams;
+T3SQLParamData pODBC3SQLParamData;
+T3SQLPutData pODBC3SQLPutData;
+T3SQLRowCount pODBC3SQLRowCount;
+T3SQLNumResultCols pODBC3SQLNumResultCols;
+T3SQLDescribeCol pODBC3SQLDescribeCol;
+T3SQLColAttribute pODBC3SQLColAttribute;
+T3SQLBindCol pODBC3SQLBindCol;
+T3SQLFetch pODBC3SQLFetch;
+T3SQLFetchScroll pODBC3SQLFetchScroll;
+T3SQLGetData pODBC3SQLGetData;
+T3SQLSetPos pODBC3SQLSetPos;
+T3SQLBulkOperations pODBC3SQLBulkOperations;
+T3SQLMoreResults pODBC3SQLMoreResults;
+T3SQLGetDiagRec pODBC3SQLGetDiagRec;
+T3SQLColumnPrivileges pODBC3SQLColumnPrivileges;
+T3SQLColumns pODBC3SQLColumns;
+T3SQLForeignKeys pODBC3SQLForeignKeys;
+T3SQLPrimaryKeys pODBC3SQLPrimaryKeys;
+T3SQLProcedureColumns pODBC3SQLProcedureColumns;
+T3SQLProcedures pODBC3SQLProcedures;
+T3SQLSpecialColumns pODBC3SQLSpecialColumns;
+T3SQLStatistics pODBC3SQLStatistics;
+T3SQLTablePrivileges pODBC3SQLTablePrivileges;
+T3SQLTables pODBC3SQLTables;
+T3SQLFreeStmt pODBC3SQLFreeStmt;
+T3SQLCloseCursor pODBC3SQLCloseCursor;
+T3SQLCancel pODBC3SQLCancel;
+T3SQLEndTran pODBC3SQLEndTran;
+T3SQLDisconnect pODBC3SQLDisconnect;
+T3SQLFreeHandle pODBC3SQLFreeHandle;
+T3SQLGetCursorName pODBC3SQLGetCursorName;
+T3SQLNativeSql pODBC3SQLNativeSql;
+
+static bool LoadFunctions(oslModule pODBCso);
+
+// Take care of Dynamically loading of the DLL/shared lib and Addresses:
+// Returns sal_True at success
+bool LoadLibrary_ODBC3(OUString &_rPath)
+{
+ static bool bLoaded = false;
+ static oslModule pODBCso = nullptr;
+
+ if (bLoaded)
+ return true;
+#ifdef DISABLE_DYNLOADING
+ (void)_rPath;
+#else
+#ifdef _WIN32
+ _rPath = "ODBC32.DLL";
+#endif
+#ifdef UNX
+ #ifdef MACOSX
+ _rPath = "libiodbc.dylib";
+ #else
+ _rPath = "libodbc.so.2";
+ pODBCso = osl_loadModule( _rPath.pData,SAL_LOADMODULE_NOW );
+ if ( !pODBCso )
+ {
+ _rPath = "libodbc.so.1";
+ pODBCso = osl_loadModule( _rPath.pData,SAL_LOADMODULE_NOW );
+ }
+ if ( !pODBCso )
+ _rPath = "libodbc.so";
+
+ #endif /* MACOSX */
+#endif
+
+ if ( !pODBCso )
+ pODBCso = osl_loadModule( _rPath.pData,SAL_LOADMODULE_NOW );
+#endif // DISABLE_DYNLOADING
+ if( !pODBCso)
+ return false;
+
+ bLoaded = LoadFunctions(pODBCso);
+ return bLoaded;
+}
+
+
+bool LoadFunctions(oslModule pODBCso)
+{
+
+ if( ( pODBC3SQLAllocHandle = reinterpret_cast<T3SQLAllocHandle>(osl_getFunctionSymbol(pODBCso, OUString("SQLAllocHandle").pData ))) == nullptr )
+ return false;
+ if( ( pODBC3SQLConnect = reinterpret_cast<T3SQLConnect>(osl_getFunctionSymbol(pODBCso, OUString("SQLConnect").pData ))) == nullptr )
+ return false;
+ if( ( pODBC3SQLDriverConnect = reinterpret_cast<T3SQLDriverConnect>(osl_getFunctionSymbol(pODBCso, OUString("SQLDriverConnect").pData ))) == nullptr )
+ return false;
+ if( ( pODBC3SQLBrowseConnect = reinterpret_cast<T3SQLBrowseConnect>(osl_getFunctionSymbol(pODBCso, OUString("SQLBrowseConnect").pData ))) == nullptr )
+ return false;
+ if(( pODBC3SQLDataSources = reinterpret_cast<T3SQLDataSources>(osl_getFunctionSymbol(pODBCso, OUString("SQLDataSources").pData ))) == nullptr )
+ return false;
+ if(( pODBC3SQLDrivers = reinterpret_cast<T3SQLDrivers>(osl_getFunctionSymbol(pODBCso, OUString("SQLDrivers").pData ))) == nullptr )
+ return false;
+ if( ( pODBC3SQLGetInfo = reinterpret_cast<T3SQLGetInfo>(osl_getFunctionSymbol(pODBCso, OUString("SQLGetInfo").pData ))) == nullptr )
+ return false;
+ if(( pODBC3SQLGetFunctions = reinterpret_cast<T3SQLGetFunctions>(osl_getFunctionSymbol(pODBCso, OUString("SQLGetFunctions").pData ))) == nullptr )
+ return false;
+ if( ( pODBC3SQLGetTypeInfo = reinterpret_cast<T3SQLGetTypeInfo>(osl_getFunctionSymbol(pODBCso, OUString("SQLGetTypeInfo").pData ))) == nullptr )
+ return false;
+ if( ( pODBC3SQLSetConnectAttr = reinterpret_cast<T3SQLSetConnectAttr>(osl_getFunctionSymbol(pODBCso, OUString("SQLSetConnectAttr").pData ))) == nullptr )
+ return false;
+ if( ( pODBC3SQLGetConnectAttr = reinterpret_cast<T3SQLGetConnectAttr>(osl_getFunctionSymbol(pODBCso, OUString("SQLGetConnectAttr").pData ))) == nullptr )
+ return false;
+ if( ( pODBC3SQLSetEnvAttr = reinterpret_cast<T3SQLSetEnvAttr>(osl_getFunctionSymbol(pODBCso, OUString("SQLSetEnvAttr").pData ))) == nullptr )
+ return false;
+ if( ( pODBC3SQLGetEnvAttr = reinterpret_cast<T3SQLGetEnvAttr>(osl_getFunctionSymbol(pODBCso, OUString("SQLGetEnvAttr").pData ))) == nullptr )
+ return false;
+ if( ( pODBC3SQLSetStmtAttr = reinterpret_cast<T3SQLSetStmtAttr>(osl_getFunctionSymbol(pODBCso, OUString("SQLSetStmtAttr").pData ))) == nullptr )
+ return false;
+ if( ( pODBC3SQLGetStmtAttr = reinterpret_cast<T3SQLGetStmtAttr>(osl_getFunctionSymbol(pODBCso, OUString("SQLGetStmtAttr").pData ))) == nullptr )
+ return false;
+ if( ( pODBC3SQLPrepare = reinterpret_cast<T3SQLPrepare>(osl_getFunctionSymbol(pODBCso, OUString("SQLPrepare").pData ))) == nullptr )
+ return false;
+ if( ( pODBC3SQLBindParameter = reinterpret_cast<T3SQLBindParameter>(osl_getFunctionSymbol(pODBCso, OUString("SQLBindParameter").pData ))) == nullptr )
+ return false;
+ if( ( pODBC3SQLSetCursorName = reinterpret_cast<T3SQLSetCursorName>(osl_getFunctionSymbol(pODBCso, OUString("SQLSetCursorName").pData ))) == nullptr )
+ return false;
+ if( ( pODBC3SQLExecute = reinterpret_cast<T3SQLExecute>(osl_getFunctionSymbol(pODBCso, OUString("SQLExecute").pData ))) == nullptr )
+ return false;
+ if( ( pODBC3SQLExecDirect = reinterpret_cast<T3SQLExecDirect>(osl_getFunctionSymbol(pODBCso, OUString("SQLExecDirect").pData ))) == nullptr )
+ return false;
+ if( ( pODBC3SQLDescribeParam = reinterpret_cast<T3SQLDescribeParam>(osl_getFunctionSymbol(pODBCso, OUString("SQLDescribeParam").pData ))) == nullptr )
+ return false;
+ if( ( pODBC3SQLNumParams = reinterpret_cast<T3SQLNumParams>(osl_getFunctionSymbol(pODBCso, OUString("SQLNumParams").pData ))) == nullptr )
+ return false;
+ if( ( pODBC3SQLParamData = reinterpret_cast<T3SQLParamData>(osl_getFunctionSymbol(pODBCso, OUString("SQLParamData").pData ))) == nullptr )
+ return false;
+ if( ( pODBC3SQLPutData = reinterpret_cast<T3SQLPutData>(osl_getFunctionSymbol(pODBCso, OUString("SQLPutData").pData ))) == nullptr )
+ return false;
+ if( ( pODBC3SQLRowCount = reinterpret_cast<T3SQLRowCount>(osl_getFunctionSymbol(pODBCso, OUString("SQLRowCount").pData ))) == nullptr )
+ return false;
+ if( ( pODBC3SQLNumResultCols = reinterpret_cast<T3SQLNumResultCols>(osl_getFunctionSymbol(pODBCso, OUString("SQLNumResultCols").pData ))) == nullptr )
+ return false;
+ if( ( pODBC3SQLDescribeCol = reinterpret_cast<T3SQLDescribeCol>(osl_getFunctionSymbol(pODBCso, OUString("SQLDescribeCol").pData ))) == nullptr )
+ return false;
+ if( ( pODBC3SQLColAttribute = reinterpret_cast<T3SQLColAttribute>(osl_getFunctionSymbol(pODBCso, OUString("SQLColAttribute").pData ))) == nullptr )
+ return false;
+ if( ( pODBC3SQLBindCol = reinterpret_cast<T3SQLBindCol>(osl_getFunctionSymbol(pODBCso, OUString("SQLBindCol").pData ))) == nullptr )
+ return false;
+ if( ( pODBC3SQLFetch = reinterpret_cast<T3SQLFetch>(osl_getFunctionSymbol(pODBCso, OUString("SQLFetch").pData ))) == nullptr )
+ return false;
+ if( ( pODBC3SQLFetchScroll = reinterpret_cast<T3SQLFetchScroll>(osl_getFunctionSymbol(pODBCso, OUString("SQLFetchScroll").pData ))) == nullptr )
+ return false;
+ if( ( pODBC3SQLGetData = reinterpret_cast<T3SQLGetData>(osl_getFunctionSymbol(pODBCso, OUString("SQLGetData").pData ))) == nullptr )
+ return false;
+ if( ( pODBC3SQLSetPos = reinterpret_cast<T3SQLSetPos>(osl_getFunctionSymbol(pODBCso, OUString("SQLSetPos").pData ))) == nullptr )
+ return false;
+ if( ( pODBC3SQLBulkOperations = reinterpret_cast<T3SQLBulkOperations>(osl_getFunctionSymbol(pODBCso, OUString("SQLBulkOperations").pData ))) == nullptr )
+ return false;
+ if( ( pODBC3SQLMoreResults = reinterpret_cast<T3SQLMoreResults>(osl_getFunctionSymbol(pODBCso, OUString("SQLMoreResults").pData ))) == nullptr )
+ return false;
+ if( ( pODBC3SQLGetDiagRec = reinterpret_cast<T3SQLGetDiagRec>(osl_getFunctionSymbol(pODBCso, OUString("SQLGetDiagRec").pData ))) == nullptr )
+ return false;
+ if( ( pODBC3SQLColumnPrivileges = reinterpret_cast<T3SQLColumnPrivileges>(osl_getFunctionSymbol(pODBCso, OUString("SQLColumnPrivileges").pData ))) == nullptr )
+ return false;
+ if( ( pODBC3SQLColumns = reinterpret_cast<T3SQLColumns>(osl_getFunctionSymbol(pODBCso, OUString("SQLColumns").pData ))) == nullptr )
+ return false;
+ if( ( pODBC3SQLForeignKeys = reinterpret_cast<T3SQLForeignKeys>(osl_getFunctionSymbol(pODBCso, OUString("SQLForeignKeys").pData ))) == nullptr )
+ return false;
+ if( ( pODBC3SQLPrimaryKeys = reinterpret_cast<T3SQLPrimaryKeys>(osl_getFunctionSymbol(pODBCso, OUString("SQLPrimaryKeys").pData ))) == nullptr )
+ return false;
+ if( ( pODBC3SQLProcedureColumns = reinterpret_cast<T3SQLProcedureColumns>(osl_getFunctionSymbol(pODBCso, OUString("SQLProcedureColumns").pData ))) == nullptr )
+ return false;
+ if( ( pODBC3SQLProcedures = reinterpret_cast<T3SQLProcedures>(osl_getFunctionSymbol(pODBCso, OUString("SQLProcedures").pData ))) == nullptr )
+ return false;
+ if( ( pODBC3SQLSpecialColumns = reinterpret_cast<T3SQLSpecialColumns>(osl_getFunctionSymbol(pODBCso, OUString("SQLSpecialColumns").pData ))) == nullptr )
+ return false;
+ if( ( pODBC3SQLStatistics = reinterpret_cast<T3SQLStatistics>(osl_getFunctionSymbol(pODBCso, OUString("SQLStatistics").pData ))) == nullptr )
+ return false;
+ if( ( pODBC3SQLTablePrivileges = reinterpret_cast<T3SQLTablePrivileges>(osl_getFunctionSymbol(pODBCso, OUString("SQLTablePrivileges").pData ))) == nullptr )
+ return false;
+ if( ( pODBC3SQLTables = reinterpret_cast<T3SQLTables>(osl_getFunctionSymbol(pODBCso, OUString("SQLTables").pData ))) == nullptr )
+ return false;
+ if( ( pODBC3SQLFreeStmt = reinterpret_cast<T3SQLFreeStmt>(osl_getFunctionSymbol(pODBCso, OUString("SQLFreeStmt").pData ))) == nullptr )
+ return false;
+ if( ( pODBC3SQLCloseCursor = reinterpret_cast<T3SQLCloseCursor>(osl_getFunctionSymbol(pODBCso, OUString("SQLCloseCursor").pData ))) == nullptr )
+ return false;
+ if( ( pODBC3SQLCancel = reinterpret_cast<T3SQLCancel>(osl_getFunctionSymbol(pODBCso, OUString("SQLCancel").pData ))) == nullptr )
+ return false;
+ if( ( pODBC3SQLEndTran = reinterpret_cast<T3SQLEndTran>(osl_getFunctionSymbol(pODBCso, OUString("SQLEndTran").pData ))) == nullptr )
+ return false;
+ if( ( pODBC3SQLDisconnect = reinterpret_cast<T3SQLDisconnect>(osl_getFunctionSymbol(pODBCso, OUString("SQLDisconnect").pData ))) == nullptr )
+ return false;
+ if( ( pODBC3SQLFreeHandle = reinterpret_cast<T3SQLFreeHandle>(osl_getFunctionSymbol(pODBCso, OUString("SQLFreeHandle").pData ))) == nullptr )
+ return false;
+ if( ( pODBC3SQLGetCursorName = reinterpret_cast<T3SQLGetCursorName>(osl_getFunctionSymbol(pODBCso, OUString("SQLGetCursorName").pData ))) == nullptr )
+ return false;
+ if( ( pODBC3SQLNativeSql = reinterpret_cast<T3SQLNativeSql>(osl_getFunctionSymbol(pODBCso, OUString("SQLNativeSql").pData ))) == nullptr )
+ return false;
+
+ return true;
+}
+
+
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/odbc/OPreparedStatement.cxx b/connectivity/source/drivers/odbc/OPreparedStatement.cxx
new file mode 100644
index 0000000000..d5852c9ea4
--- /dev/null
+++ b/connectivity/source/drivers/odbc/OPreparedStatement.cxx
@@ -0,0 +1,924 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <string.h>
+#include <osl/diagnose.h>
+#include <odbc/OPreparedStatement.hxx>
+#include <odbc/OBoundParam.hxx>
+#include <com/sun/star/io/IOException.hpp>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <odbc/OTools.hxx>
+#include <odbc/OResultSet.hxx>
+#include <odbc/OResultSetMetaData.hxx>
+#include <comphelper/sequence.hxx>
+#include <connectivity/dbtools.hxx>
+#include <comphelper/types.hxx>
+#include <connectivity/FValue.hxx>
+#include <strings.hrc>
+#include <memory>
+#include <type_traits>
+
+using namespace ::comphelper;
+using namespace connectivity;
+using namespace connectivity::odbc;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::sdbc;
+using namespace com::sun::star::sdbcx;
+using namespace com::sun::star::container;
+using namespace com::sun::star::io;
+using namespace com::sun::star::util;
+
+IMPLEMENT_SERVICE_INFO(OPreparedStatement,"com.sun.star.sdbcx.OPreparedStatement","com.sun.star.sdbc.PreparedStatement");
+
+namespace
+{
+ // for now, never use wchar,
+ // but most of code is prepared to handle it
+ // in case we make this configurable
+ const bool bUseWChar = false;
+}
+
+OPreparedStatement::OPreparedStatement( OConnection* _pConnection,const OUString& sql)
+ :OStatement_BASE2(_pConnection)
+ ,numParams(0)
+ ,m_bPrepared(false)
+{
+ m_sSqlStatement = sql;
+}
+
+OPreparedStatement::~OPreparedStatement()
+{
+}
+
+void SAL_CALL OPreparedStatement::acquire() noexcept
+{
+ OStatement_BASE2::acquire();
+}
+
+void SAL_CALL OPreparedStatement::release() noexcept
+{
+ OStatement_BASE2::release();
+}
+
+Any SAL_CALL OPreparedStatement::queryInterface( const Type & rType )
+{
+ Any aRet = OStatement_BASE2::queryInterface(rType);
+ return aRet.hasValue() ? aRet : OPreparedStatement_BASE::queryInterface(rType);
+}
+
+css::uno::Sequence< css::uno::Type > SAL_CALL OPreparedStatement::getTypes( )
+{
+ return ::comphelper::concatSequences(OPreparedStatement_BASE::getTypes(),OStatement_BASE2::getTypes());
+}
+
+
+Reference< XResultSetMetaData > SAL_CALL OPreparedStatement::getMetaData( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OStatement_BASE::rBHelper.bDisposed);
+
+
+ prepareStatement();
+ OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!");
+ if(!m_xMetaData.is())
+ m_xMetaData = new OResultSetMetaData(getOwnConnection(),m_aStatementHandle);
+ return m_xMetaData;
+}
+
+
+void SAL_CALL OPreparedStatement::close( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OStatement_BASE::rBHelper.bDisposed);
+
+
+ // Close/clear our result set
+ clearMyResultSet ();
+
+ // Reset last warning message
+
+ try {
+ clearWarnings ();
+ OStatement_BASE2::close();
+ FreeParams();
+ }
+ catch (SQLException &) {
+ // If we get an error, ignore
+ }
+
+ // Remove this Statement object from the Connection object's
+ // list
+}
+
+
+sal_Bool SAL_CALL OPreparedStatement::execute( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OStatement_BASE::rBHelper.bDisposed);
+
+ // Reset warnings
+
+ clearWarnings ();
+
+ // Reset the statement handle, warning and saved Resultset
+
+ reset();
+
+ // Call SQLExecute
+ prepareStatement();
+
+ OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!");
+ try
+ {
+ SQLRETURN nReturn = N3SQLExecute(m_aStatementHandle);
+
+ OTools::ThrowException(m_pConnection.get(),nReturn,m_aStatementHandle,SQL_HANDLE_STMT,*this);
+ bool needData = nReturn == SQL_NEED_DATA;
+
+ // Now loop while more data is needed (i.e. a data-at-
+ // execution parameter was given). For each parameter
+ // that needs data, put the data from the input stream.
+
+ while (needData) {
+
+ // Get the parameter number that requires data
+
+ sal_Int32* paramIndex = nullptr;
+ N3SQLParamData(m_aStatementHandle, reinterpret_cast<SQLPOINTER*>(&paramIndex));
+
+ // If the parameter index is -1, there is no
+ // more data required
+
+ if ( !paramIndex || ( *paramIndex == -1 ) )
+ needData = false;
+ else
+ {
+ // Now we have the proper parameter
+ // index, get the data from the input
+ // stream and do a SQLPutData
+ putParamData (*paramIndex);
+ }
+ }
+
+ }
+ catch (const SQLWarning&)
+ {
+ }
+
+ // Now determine if there is a result set associated with
+ // the SQL statement that was executed. Get the column
+ // count, and if it is not zero, there is a result set.
+
+
+ return getColumnCount() > 0;
+}
+
+
+sal_Int32 SAL_CALL OPreparedStatement::executeUpdate( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OStatement_BASE::rBHelper.bDisposed);
+
+ sal_Int32 numRows = -1;
+
+ prepareStatement();
+ // Execute the statement. If execute returns sal_False, a
+ // row count exists.
+
+ if (!execute())
+ numRows = getUpdateCount ();
+ else
+ {
+ // No update count was produced (a ResultSet was). Raise
+ // an exception
+ m_pConnection->throwGenericSQLException(STR_NO_ROWCOUNT,*this);
+ }
+ return numRows;
+}
+
+
+void SAL_CALL OPreparedStatement::setString( sal_Int32 parameterIndex, const OUString& x )
+{
+ setParameter(parameterIndex, DataType::CHAR, invalid_scale, x);
+}
+
+
+Reference< XConnection > SAL_CALL OPreparedStatement::getConnection( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OStatement_BASE::rBHelper.bDisposed);
+
+ return m_pConnection;
+}
+
+
+Reference< XResultSet > SAL_CALL OPreparedStatement::executeQuery( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OStatement_BASE::rBHelper.bDisposed);
+
+ Reference< XResultSet > rs;
+
+ prepareStatement();
+
+ if (execute())
+ rs = getResultSet(false);
+ else
+ {
+ // No ResultSet was produced. Raise an exception
+ m_pConnection->throwGenericSQLException(STR_NO_RESULTSET,*this);
+ }
+ return rs;
+}
+
+
+void SAL_CALL OPreparedStatement::setBoolean( sal_Int32 parameterIndex, sal_Bool x )
+{
+ // Set the parameter as if it were an integer
+ setInt (parameterIndex, x ? 1 : 0 );
+}
+
+// The MutexGuard must _already_ be taken!
+void OPreparedStatement::setParameterPre(sal_Int32 parameterIndex)
+{
+ checkDisposed(OStatement_BASE::rBHelper.bDisposed);
+ prepareStatement();
+ checkParameterIndex(parameterIndex);
+ OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!");
+}
+
+
+template <typename T> void OPreparedStatement::setScalarParameter(const sal_Int32 parameterIndex, const sal_Int32 i_nType, const SQLULEN i_nColSize, const T i_Value)
+{
+ setScalarParameter(parameterIndex, i_nType, i_nColSize, invalid_scale, i_Value);
+}
+
+
+template <typename T> void OPreparedStatement::setScalarParameter(const sal_Int32 parameterIndex, const sal_Int32 i_nType, const SQLULEN i_nColSize, sal_Int32 i_nScale, const T i_Value)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ setParameterPre(parameterIndex);
+
+ typedef typename std::remove_reference<T>::type TnoRef;
+
+ TnoRef *bindBuf = static_cast< TnoRef* >( allocBindBuf(parameterIndex, sizeof(i_Value)) );
+ *bindBuf = i_Value;
+
+ setParameter(parameterIndex, i_nType, i_nColSize, i_nScale, bindBuf, sizeof(i_Value), sizeof(i_Value));
+}
+
+
+void OPreparedStatement::setParameter(const sal_Int32 parameterIndex, const sal_Int32 _nType, const sal_Int16 _nScale, const OUString &_sData)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ setParameterPre(parameterIndex);
+
+ assert (_nType == DataType::VARCHAR || _nType == DataType::CHAR || _nType == DataType::DECIMAL || _nType == DataType::NUMERIC);
+
+ sal_Int32 nCharLen;
+ sal_Int32 nByteLen;
+ void *pData;
+ if (bUseWChar)
+ {
+ /*
+ * On Windows, wchar is 16 bits (UTF-16 encoding), the ODBC "W" variants functions take UTF-16 encoded strings
+ * and character lengths are number of UTF-16 codepoints.
+ * Reference: http://msdn.microsoft.com/en-us/library/windows/desktop/ms716246%28v=vs.85%29.aspx
+ * ODBC Programmer's reference > Developing Applications > Programming Considerations > Unicode > Unicode Function Arguments
+ * http://support.microsoft.com/kb/294169
+ *
+ * UnixODBC can be configured at compile-time so that the "W" variants expect
+ * UTF-16 or UTF-32 encoded strings, and character lengths are number of codepoints.
+ * However, UTF-16 is the default, what all/most distributions do
+ * and the established API that most drivers implement.
+ * As wchar is often 32 bits, this differs from C-style strings of wchar!
+ *
+ * On MacOS X, the "W" variants use wchar_t, which is UCS4
+ *
+ * Our internal OUString storage is always UTF-16, so no conversion to do here.
+ */
+ static_assert(sizeof (SQLWCHAR) == 2 || sizeof (SQLWCHAR) == 4, "must be 2 or 4");
+ if (sizeof (SQLWCHAR) == 2)
+ {
+ nCharLen = _sData.getLength();
+ nByteLen = 2 * nCharLen;
+ pData = allocBindBuf(parameterIndex, nByteLen);
+ memcpy(pData, _sData.getStr(), nByteLen);
+ }
+ else
+ {
+ pData = allocBindBuf(parameterIndex, _sData.getLength() * 4);
+ sal_uInt32* pCursor = static_cast<sal_uInt32*>(pData);
+ nCharLen = 0;
+ for (sal_Int32 i = 0; i != _sData.getLength();)
+ {
+ *pCursor++ = _sData.iterateCodePoints(&i);
+ nCharLen += 1;
+ }
+ nByteLen = 4 * nCharLen;
+ }
+ }
+ else
+ {
+ assert(getOwnConnection()->getTextEncoding() != RTL_TEXTENCODING_UCS2 &&
+ getOwnConnection()->getTextEncoding() != RTL_TEXTENCODING_UCS4);
+ OString sOData(
+ OUStringToOString(_sData, getOwnConnection()->getTextEncoding()));
+ nCharLen = nByteLen = sOData.getLength();
+ pData = allocBindBuf(parameterIndex, nByteLen);
+ memcpy(pData, sOData.getStr(), nByteLen);
+ }
+
+ setParameter( parameterIndex, _nType, nCharLen, _nScale, pData, nByteLen, nByteLen );
+}
+
+void OPreparedStatement::setParameter(const sal_Int32 parameterIndex, const sal_Int32 _nType, const Sequence< sal_Int8 > &x)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ setParameterPre(parameterIndex);
+
+ assert(_nType == DataType::BINARY || _nType == DataType::VARBINARY);
+
+ // don't copy the sequence, just point the ODBC directly at the sequence's storage array
+ // Why BINARY/Sequence is treated differently than strings (which are copied), I'm not sure
+ OSL_VERIFY(allocBindBuf(parameterIndex, 0) == nullptr);
+ boundParams[parameterIndex-1].setSequence(x); // this ensures that the sequence stays alive
+
+ setParameter( parameterIndex, _nType, x.getLength(), invalid_scale, x.getConstArray(), x.getLength(), x.getLength() );
+}
+
+void OPreparedStatement::setParameter(const sal_Int32 parameterIndex, const sal_Int32 _nType, const SQLULEN _nColumnSize, const sal_Int32 _nScale, const void* const _pData, const SQLULEN _nDataLen, const SQLLEN _nDataAllocLen)
+{
+ SQLSMALLINT fCType, fSqlType;
+ OTools::getBindTypes(bUseWChar, m_pConnection->useOldDateFormat(), OTools::jdbcTypeToOdbc(_nType), fCType, fSqlType);
+
+ SQLLEN& rDataLen = boundParams[parameterIndex-1].getBindLengthBuffer();
+ rDataLen = _nDataLen;
+
+ SQLRETURN nRetcode;
+ nRetcode = (*reinterpret_cast<T3SQLBindParameter>(m_pConnection->getOdbcFunction(ODBC3SQLFunctionId::BindParameter)))(
+ m_aStatementHandle,
+ // checkParameterIndex guarantees this is safe
+ static_cast<SQLUSMALLINT>(parameterIndex),
+ SQL_PARAM_INPUT,
+ fCType,
+ fSqlType,
+ _nColumnSize,
+ _nScale,
+ // we trust the ODBC driver not to touch it because SQL_PARAM_INPUT
+ const_cast<void*>(_pData),
+ _nDataAllocLen,
+ &rDataLen);
+
+ OTools::ThrowException(m_pConnection.get(), nRetcode, m_aStatementHandle, SQL_HANDLE_STMT, *this);
+}
+
+void SAL_CALL OPreparedStatement::setByte( const sal_Int32 parameterIndex, const sal_Int8 x )
+{
+ setScalarParameter(parameterIndex, DataType::TINYINT, 3, 0, x);
+}
+
+void SAL_CALL OPreparedStatement::setDate( sal_Int32 parameterIndex, const Date& aData )
+{
+ DATE_STRUCT x(OTools::DateToOdbcDate(aData));
+ setScalarParameter<DATE_STRUCT&>(parameterIndex, DataType::DATE, 10, x);
+}
+
+void SAL_CALL OPreparedStatement::setTime( sal_Int32 parameterIndex, const css::util::Time& aVal )
+{
+ SQLULEN nColSize;
+ if(aVal.NanoSeconds == 0)
+ nColSize = 8;
+ else if(aVal.NanoSeconds % 100000000 == 0)
+ nColSize = 10;
+ else if(aVal.NanoSeconds % 10000000 == 0)
+ nColSize = 11;
+ else if(aVal.NanoSeconds % 1000000 == 0)
+ nColSize = 12;
+ else if(aVal.NanoSeconds % 100000 == 0)
+ nColSize = 13;
+ else if(aVal.NanoSeconds % 10000 == 0)
+ nColSize = 14;
+ else if(aVal.NanoSeconds % 1000 == 0)
+ nColSize = 15;
+ else if(aVal.NanoSeconds % 100 == 0)
+ nColSize = 16;
+ else if(aVal.NanoSeconds % 10 == 0)
+ nColSize = 17;
+ else
+ nColSize = 18;
+ TIME_STRUCT x(OTools::TimeToOdbcTime(aVal));
+ setScalarParameter<TIME_STRUCT&>(parameterIndex, DataType::TIME, nColSize, (nColSize == 8)? 0 : nColSize-9, x);
+}
+
+
+void SAL_CALL OPreparedStatement::setTimestamp( sal_Int32 parameterIndex, const DateTime& aVal )
+{
+ SQLULEN nColSize;
+ if(aVal.NanoSeconds == 0)
+ {
+ if (aVal.Seconds == 0)
+ nColSize=16;
+ else
+ nColSize=19;
+ }
+ else if(aVal.NanoSeconds % 100000000 == 0)
+ nColSize = 21;
+ else if(aVal.NanoSeconds % 10000000 == 0)
+ nColSize = 22;
+ else if(aVal.NanoSeconds % 1000000 == 0)
+ nColSize = 23;
+ else if(aVal.NanoSeconds % 100000 == 0)
+ nColSize = 24;
+ else if(aVal.NanoSeconds % 10000 == 0)
+ nColSize = 25;
+ else if(aVal.NanoSeconds % 1000 == 0)
+ nColSize = 26;
+ else if(aVal.NanoSeconds % 100 == 0)
+ nColSize = 27;
+ else if(aVal.NanoSeconds % 10 == 0)
+ nColSize = 28;
+ else
+ nColSize = 29;
+
+ TIMESTAMP_STRUCT x(OTools::DateTimeToTimestamp(aVal));
+ setScalarParameter<TIMESTAMP_STRUCT&>(parameterIndex, DataType::TIMESTAMP, nColSize, (nColSize <= 19)? 0 : nColSize-20, x);
+}
+
+
+void SAL_CALL OPreparedStatement::setDouble( sal_Int32 parameterIndex, double x )
+{
+ setScalarParameter(parameterIndex, DataType::DOUBLE, 15, x);
+}
+
+
+void SAL_CALL OPreparedStatement::setFloat( sal_Int32 parameterIndex, float x )
+{
+ setScalarParameter(parameterIndex, DataType::FLOAT, 15, x);
+}
+
+
+void SAL_CALL OPreparedStatement::setInt( sal_Int32 parameterIndex, sal_Int32 x )
+{
+ setScalarParameter(parameterIndex, DataType::INTEGER, 10, 0, x);
+}
+
+
+void SAL_CALL OPreparedStatement::setLong( sal_Int32 parameterIndex, sal_Int64 x )
+{
+ try
+ {
+ setScalarParameter(parameterIndex, DataType::BIGINT, 19, 0, x);
+ }
+ catch(SQLException&)
+ {
+ setString(parameterIndex, ORowSetValue(x).getString());
+ }
+}
+
+
+void SAL_CALL OPreparedStatement::setNull( sal_Int32 parameterIndex, const sal_Int32 _nType )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ setParameterPre(parameterIndex);
+
+ OSL_VERIFY(allocBindBuf(parameterIndex, 0) == nullptr);
+ SQLLEN * const lenBuf = getLengthBuf (parameterIndex);
+ *lenBuf = SQL_NULL_DATA;
+
+
+ SQLSMALLINT fCType;
+ SQLSMALLINT fSqlType;
+
+ OTools::getBindTypes( bUseWChar,
+ m_pConnection->useOldDateFormat(),
+ OTools::jdbcTypeToOdbc(_nType),
+ fCType,
+ fSqlType);
+
+ SQLRETURN nReturn = N3SQLBindParameter( m_aStatementHandle,
+ static_cast<SQLUSMALLINT>(parameterIndex),
+ SQL_PARAM_INPUT,
+ fCType,
+ fSqlType,
+ 0,
+ 0,
+ nullptr,
+ 0,
+ lenBuf
+ );
+ OTools::ThrowException(m_pConnection.get(),nReturn,m_aStatementHandle,SQL_HANDLE_STMT,*this);
+}
+
+
+void SAL_CALL OPreparedStatement::setClob( sal_Int32 parameterIndex, const Reference< XClob >& x )
+{
+ if ( x.is() )
+ setStream(parameterIndex, x->getCharacterStream(), x->length(), DataType::LONGVARCHAR);
+}
+
+
+void SAL_CALL OPreparedStatement::setBlob( sal_Int32 parameterIndex, const Reference< XBlob >& x )
+{
+ if ( x.is() )
+ setStream(parameterIndex, x->getBinaryStream(), x->length(), DataType::LONGVARBINARY);
+}
+
+
+void SAL_CALL OPreparedStatement::setArray( sal_Int32 /*parameterIndex*/, const Reference< XArray >& /*x*/ )
+{
+ ::dbtools::throwFunctionNotSupportedSQLException( "XParameters::setArray", *this );
+}
+
+
+void SAL_CALL OPreparedStatement::setRef( sal_Int32 /*parameterIndex*/, const Reference< XRef >& /*x*/ )
+{
+ ::dbtools::throwFunctionNotSupportedSQLException( "XParameters::setRef", *this );
+}
+
+void SAL_CALL OPreparedStatement::setObjectWithInfo( sal_Int32 parameterIndex, const Any& x, sal_Int32 sqlType, sal_Int32 scale )
+{
+ checkDisposed(OStatement_BASE::rBHelper.bDisposed);
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ prepareStatement();
+ // For each known SQL Type, call the appropriate
+ // set routine
+
+ switch (sqlType)
+ {
+ case DataType::CHAR:
+ case DataType::VARCHAR:
+ case DataType::LONGVARCHAR:
+ if(x.hasValue())
+ {
+ OUString sStr;
+ x >>= sStr;
+ setParameter(parameterIndex, sqlType, scale, sStr);
+ }
+ else
+ setNull(parameterIndex,sqlType);
+ break;
+ case DataType::DECIMAL:
+ case DataType::NUMERIC:
+ if(x.hasValue())
+ {
+ ORowSetValue aValue;
+ aValue.fill(x);
+ setParameter(parameterIndex, sqlType, scale, aValue.getString());
+ }
+ else
+ setNull(parameterIndex,sqlType);
+ break;
+ default:
+ ::dbtools::setObjectWithInfo(this,parameterIndex,x,sqlType,scale);
+ }
+}
+
+
+void SAL_CALL OPreparedStatement::setObjectNull( sal_Int32 parameterIndex, sal_Int32 sqlType, const OUString& /*typeName*/ )
+{
+ setNull(parameterIndex,sqlType);
+}
+
+
+void SAL_CALL OPreparedStatement::setObject( sal_Int32 parameterIndex, const Any& x )
+{
+ if (!::dbtools::implSetObject(this, parameterIndex, x))
+ { // there is no other setXXX call which can handle the value in x
+ throw SQLException();
+ }
+}
+
+
+void SAL_CALL OPreparedStatement::setShort( sal_Int32 parameterIndex, sal_Int16 x )
+{
+ setScalarParameter(parameterIndex, DataType::SMALLINT, 5, 0, x);
+}
+
+
+void SAL_CALL OPreparedStatement::setBytes( sal_Int32 parameterIndex, const Sequence< sal_Int8 >& x )
+{
+ setParameter(parameterIndex, DataType::BINARY, x);
+}
+
+
+void SAL_CALL OPreparedStatement::setCharacterStream( sal_Int32 parameterIndex, const Reference< css::io::XInputStream >& x, sal_Int32 length )
+{
+ // LEM: It is quite unclear to me what the interface here is.
+ // The XInputStream provides *bytes*, not characters.
+ setStream(parameterIndex, x, length, DataType::LONGVARCHAR);
+}
+
+
+void SAL_CALL OPreparedStatement::setBinaryStream( sal_Int32 parameterIndex, const Reference< css::io::XInputStream >& x, sal_Int32 length )
+{
+ setStream(parameterIndex, x, length, DataType::LONGVARBINARY);
+}
+
+
+void SAL_CALL OPreparedStatement::clearParameters( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ prepareStatement();
+ OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!");
+ N3SQLFreeStmt (m_aStatementHandle, SQL_RESET_PARAMS);
+ N3SQLFreeStmt (m_aStatementHandle, SQL_UNBIND);
+}
+
+void SAL_CALL OPreparedStatement::clearBatch( )
+{
+ ::dbtools::throwFunctionNotSupportedSQLException( "XPreparedBatchExecution::clearBatch", *this );
+ // clearParameters( );
+ // m_aBatchVector.erase();
+}
+
+
+void SAL_CALL OPreparedStatement::addBatch( )
+{
+ ::dbtools::throwFunctionNotSupportedSQLException( "XPreparedBatchExecution::addBatch", *this );
+}
+
+
+Sequence< sal_Int32 > SAL_CALL OPreparedStatement::executeBatch( )
+{
+ ::dbtools::throwFunctionNotSupportedSQLException( "XPreparedBatchExecution::executeBatch", *this );
+ // not reached, but keep -Werror happy
+ return Sequence< sal_Int32 > ();
+}
+
+
+// methods
+
+
+// initBoundParam
+// Initialize the bound parameter objects
+
+
+void OPreparedStatement::initBoundParam ()
+{
+ OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!");
+ // Get the number of parameters
+ numParams = 0;
+ N3SQLNumParams (m_aStatementHandle,&numParams);
+
+ // There are parameter markers, allocate the bound
+ // parameter objects
+
+ if (numParams > 0)
+ {
+ boundParams.reset(new OBoundParam[numParams]);
+ }
+}
+
+
+// allocBindBuf
+// Allocate storage for the permanent data buffer for the bound
+// parameter.
+
+
+void* OPreparedStatement::allocBindBuf( sal_Int32 index,sal_Int32 bufLen)
+{
+ void* b = nullptr;
+
+ // Sanity check the parameter number
+
+ if ((index >= 1) && (index <= numParams))
+ {
+ b = boundParams[index - 1].allocBindDataBuffer(bufLen);
+ }
+
+ return b;
+}
+
+
+// getLengthBuf
+// Gets the length buffer for the given parameter index
+
+
+SQLLEN* OPreparedStatement::getLengthBuf (sal_Int32 index)
+{
+ SQLLEN* b = nullptr;
+
+ // Sanity check the parameter number
+
+ if ((index >= 1) &&
+ (index <= numParams))
+ {
+ b = &boundParams[index - 1].getBindLengthBuffer ();
+ }
+
+ return b;
+}
+
+
+// putParamData
+// Puts parameter data from a previously bound input stream. The
+// input stream was bound using SQL_LEN_DATA_AT_EXEC.
+void OPreparedStatement::putParamData (sal_Int32 index)
+{
+ // Sanity check the parameter index
+ if ((index < 1) ||
+ (index > numParams))
+ {
+ return;
+ }
+
+ // We'll transfer up to MAX_PUT_DATA_LENGTH at a time
+ Sequence< sal_Int8 > buf( MAX_PUT_DATA_LENGTH );
+
+ // Get the information about the input stream
+
+ Reference< XInputStream> inputStream = boundParams[index - 1].getInputStream ();
+ if ( !inputStream.is() )
+ {
+ ::connectivity::SharedResources aResources;
+ const OUString sError( aResources.getResourceString(STR_NO_INPUTSTREAM));
+ throw SQLException (sError, *this,OUString(),0,Any());
+ }
+
+ sal_Int32 maxBytesLeft = boundParams[index - 1].getInputStreamLen ();
+
+ // Loop while more data from the input stream
+ sal_Int32 haveRead = 0;
+ try
+ {
+
+ do
+ {
+ sal_Int32 toReadThisRound = std::min( MAX_PUT_DATA_LENGTH, maxBytesLeft );
+
+ // Read some data from the input stream
+ haveRead = inputStream->readBytes( buf, toReadThisRound );
+ OSL_ENSURE( haveRead == buf.getLength(), "OPreparedStatement::putParamData: inconsistency!" );
+
+ if ( !haveRead )
+ // no more data in the stream - the given stream length was a maximum which could not be
+ // fulfilled by the stream
+ break;
+
+ // Put the data
+ OSL_ENSURE( m_aStatementHandle, "OPreparedStatement::putParamData: StatementHandle is null!" );
+ N3SQLPutData ( m_aStatementHandle, buf.getArray(), buf.getLength() );
+
+ // decrement the number of bytes still needed
+ maxBytesLeft -= haveRead;
+ }
+ while ( maxBytesLeft > 0 );
+ }
+ catch (const IOException& ex)
+ {
+
+ // If an I/O exception was generated, turn
+ // it into a SQLException
+
+ throw SQLException(ex.Message,*this,OUString(),0,Any());
+ }
+}
+
+// setStream
+// Sets an input stream as a parameter, using the given SQL type
+void OPreparedStatement::setStream(
+ sal_Int32 ParameterIndex,
+ const Reference< XInputStream>& x,
+ SQLLEN length,
+ sal_Int32 _nType)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OStatement_BASE::rBHelper.bDisposed);
+
+
+ prepareStatement();
+
+ checkParameterIndex(ParameterIndex);
+ // Get the buffer needed for the length
+
+ SQLLEN * const lenBuf = getLengthBuf(ParameterIndex);
+
+ // Allocate a new buffer for the parameter data. This buffer
+ // will be returned by SQLParamData (it is set to the parameter
+ // number, a sal_Int32)
+
+ sal_Int32* dataBuf = static_cast<sal_Int32*>( allocBindBuf(ParameterIndex, sizeof(ParameterIndex)) );
+ *dataBuf = ParameterIndex;
+
+ // Bind the parameter with SQL_LEN_DATA_AT_EXEC
+ *lenBuf = SQL_LEN_DATA_AT_EXEC (length);
+
+ SQLSMALLINT fCType, fSqlType;
+ OTools::getBindTypes(bUseWChar, m_pConnection->useOldDateFormat(), OTools::jdbcTypeToOdbc(_nType), fCType, fSqlType);
+
+
+ OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!");
+ N3SQLBindParameter(m_aStatementHandle,
+ static_cast<SQLUSMALLINT>(ParameterIndex),
+ SQL_PARAM_INPUT,
+ fCType,
+ fSqlType,
+ length,
+ invalid_scale,
+ dataBuf,
+ sizeof(ParameterIndex),
+ lenBuf);
+
+ // Save the input stream
+ boundParams[ParameterIndex - 1].setInputStream (x, length);
+}
+
+
+void OPreparedStatement::FreeParams()
+{
+ numParams = 0;
+ boundParams.reset();
+}
+
+void OPreparedStatement::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,const Any& rValue)
+{
+ try
+ {
+ switch(nHandle)
+ {
+ case PROPERTY_ID_RESULTSETCONCURRENCY:
+ if(!isPrepared())
+ setResultSetConcurrency(comphelper::getINT32(rValue));
+ break;
+ case PROPERTY_ID_RESULTSETTYPE:
+ if(!isPrepared())
+ setResultSetType(comphelper::getINT32(rValue));
+ break;
+ case PROPERTY_ID_FETCHDIRECTION:
+ if(!isPrepared())
+ setFetchDirection(comphelper::getINT32(rValue));
+ break;
+ case PROPERTY_ID_USEBOOKMARKS:
+ if(!isPrepared())
+ setUsingBookmarks(comphelper::getBOOL(rValue));
+ break;
+ default:
+ OStatement_Base::setFastPropertyValue_NoBroadcast(nHandle,rValue);
+ }
+ }
+ catch(const SQLException&)
+ {
+ // throw Exception(e.Message,*this);
+ }
+}
+
+void OPreparedStatement::prepareStatement()
+{
+ if(!isPrepared())
+ {
+ OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!");
+ OString aSql(OUStringToOString(m_sSqlStatement,getOwnConnection()->getTextEncoding()));
+ SQLRETURN nReturn = N3SQLPrepare(m_aStatementHandle, reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(aSql.getStr())), aSql.getLength());
+ OTools::ThrowException(m_pConnection.get(),nReturn,m_aStatementHandle,SQL_HANDLE_STMT,*this);
+ m_bPrepared = true;
+ initBoundParam();
+ }
+}
+
+void OPreparedStatement::checkParameterIndex(sal_Int32 _parameterIndex)
+{
+ if( _parameterIndex > numParams ||
+ _parameterIndex < 1 ||
+ _parameterIndex > std::numeric_limits<SQLUSMALLINT>::max() )
+ {
+ ::connectivity::SharedResources aResources;
+ const OUString sError( aResources.getResourceStringWithSubstitution(STR_WRONG_PARAM_INDEX,
+ "$pos$", OUString::number(_parameterIndex),
+ "$count$", OUString::number(numParams)
+ ));
+ SQLException aNext(sError,*this, OUString(),0,Any());
+
+ ::dbtools::throwInvalidIndexException(*this,Any(aNext));
+ }
+}
+
+rtl::Reference<OResultSet> OPreparedStatement::createResultSet()
+{
+ rtl::Reference<OResultSet> pReturn = new OResultSet(m_aStatementHandle,this);
+ pReturn->setMetaData(getMetaData());
+ return pReturn;
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/odbc/ORealDriver.cxx b/connectivity/source/drivers/odbc/ORealDriver.cxx
new file mode 100644
index 0000000000..28c054b45f
--- /dev/null
+++ b/connectivity/source/drivers/odbc/ORealDriver.cxx
@@ -0,0 +1,291 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <odbc/ODriver.hxx>
+#include <odbc/OTools.hxx>
+#include <odbc/OFunctions.hxx>
+
+namespace connectivity::odbc
+{
+ namespace {
+
+ class ORealOdbcDriver : public ODBCDriver
+ {
+ protected:
+ virtual oslGenericFunction getOdbcFunction(ODBC3SQLFunctionId _nIndex) const override;
+ virtual SQLHANDLE EnvironmentHandle(OUString &_rPath) override;
+ public:
+ explicit ORealOdbcDriver(const css::uno::Reference< css::uno::XComponentContext >& _rxContext) : ODBCDriver(_rxContext) {}
+ };
+
+ }
+
+oslGenericFunction ORealOdbcDriver::getOdbcFunction(ODBC3SQLFunctionId _nIndex) const
+{
+ oslGenericFunction pFunction = nullptr;
+ switch(_nIndex)
+ {
+ case ODBC3SQLFunctionId::AllocHandle:
+ pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLAllocHandle);
+ break;
+ case ODBC3SQLFunctionId::Connect:
+ pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLConnect);
+ break;
+ case ODBC3SQLFunctionId::DriverConnect:
+ pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLDriverConnect);
+ break;
+ case ODBC3SQLFunctionId::BrowseConnect:
+ pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLBrowseConnect);
+ break;
+ case ODBC3SQLFunctionId::DataSources:
+ pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLDataSources);
+ break;
+ case ODBC3SQLFunctionId::Drivers:
+ pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLDrivers);
+ break;
+ case ODBC3SQLFunctionId::GetInfo:
+
+ pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLGetInfo);
+ break;
+ case ODBC3SQLFunctionId::GetFunctions:
+
+ pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLGetFunctions);
+ break;
+ case ODBC3SQLFunctionId::GetTypeInfo:
+
+ pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLGetTypeInfo);
+ break;
+ case ODBC3SQLFunctionId::SetConnectAttr:
+
+ pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLSetConnectAttr);
+ break;
+ case ODBC3SQLFunctionId::GetConnectAttr:
+
+ pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLGetConnectAttr);
+ break;
+ case ODBC3SQLFunctionId::SetEnvAttr:
+
+ pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLSetEnvAttr);
+ break;
+ case ODBC3SQLFunctionId::GetEnvAttr:
+
+ pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLGetEnvAttr);
+ break;
+ case ODBC3SQLFunctionId::SetStmtAttr:
+
+ pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLSetStmtAttr);
+ break;
+ case ODBC3SQLFunctionId::GetStmtAttr:
+
+ pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLGetStmtAttr);
+ break;
+ case ODBC3SQLFunctionId::Prepare:
+
+ pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLPrepare);
+ break;
+ case ODBC3SQLFunctionId::BindParameter:
+
+ pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLBindParameter);
+ break;
+ case ODBC3SQLFunctionId::SetCursorName:
+
+ pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLSetCursorName);
+ break;
+ case ODBC3SQLFunctionId::Execute:
+
+ pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLExecute);
+ break;
+ case ODBC3SQLFunctionId::ExecDirect:
+
+ pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLExecDirect);
+ break;
+ case ODBC3SQLFunctionId::DescribeParam:
+
+ pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLDescribeParam);
+ break;
+ case ODBC3SQLFunctionId::NumParams:
+
+ pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLNumParams);
+ break;
+ case ODBC3SQLFunctionId::ParamData:
+
+ pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLParamData);
+ break;
+ case ODBC3SQLFunctionId::PutData:
+
+ pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLPutData);
+ break;
+ case ODBC3SQLFunctionId::RowCount:
+
+ pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLRowCount);
+ break;
+ case ODBC3SQLFunctionId::NumResultCols:
+
+ pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLNumResultCols);
+ break;
+ case ODBC3SQLFunctionId::DescribeCol:
+
+ pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLDescribeCol);
+ break;
+ case ODBC3SQLFunctionId::ColAttribute:
+
+ pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLColAttribute);
+ break;
+ case ODBC3SQLFunctionId::BindCol:
+
+ pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLBindCol);
+ break;
+ case ODBC3SQLFunctionId::Fetch:
+
+ pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLFetch);
+ break;
+ case ODBC3SQLFunctionId::FetchScroll:
+
+ pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLFetchScroll);
+ break;
+ case ODBC3SQLFunctionId::GetData:
+
+ pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLGetData);
+ break;
+ case ODBC3SQLFunctionId::SetPos:
+
+ pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLSetPos);
+ break;
+ case ODBC3SQLFunctionId::BulkOperations:
+
+ pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLBulkOperations);
+ break;
+ case ODBC3SQLFunctionId::MoreResults:
+
+ pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLMoreResults);
+ break;
+ case ODBC3SQLFunctionId::GetDiagRec:
+
+ pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLGetDiagRec);
+ break;
+ case ODBC3SQLFunctionId::ColumnPrivileges:
+
+ pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLColumnPrivileges);
+ break;
+ case ODBC3SQLFunctionId::Columns:
+
+ pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLColumns);
+ break;
+ case ODBC3SQLFunctionId::ForeignKeys:
+
+ pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLForeignKeys);
+ break;
+ case ODBC3SQLFunctionId::PrimaryKeys:
+
+ pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLPrimaryKeys);
+ break;
+ case ODBC3SQLFunctionId::ProcedureColumns:
+
+ pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLProcedureColumns);
+ break;
+ case ODBC3SQLFunctionId::Procedures:
+
+ pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLProcedures);
+ break;
+ case ODBC3SQLFunctionId::SpecialColumns:
+
+ pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLSpecialColumns);
+ break;
+ case ODBC3SQLFunctionId::Statistics:
+
+ pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLStatistics);
+ break;
+ case ODBC3SQLFunctionId::TablePrivileges:
+
+ pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLTablePrivileges);
+ break;
+ case ODBC3SQLFunctionId::Tables:
+
+ pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLTables);
+ break;
+ case ODBC3SQLFunctionId::FreeStmt:
+
+ pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLFreeStmt);
+ break;
+ case ODBC3SQLFunctionId::CloseCursor:
+
+ pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLCloseCursor);
+ break;
+ case ODBC3SQLFunctionId::Cancel:
+
+ pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLCancel);
+ break;
+ case ODBC3SQLFunctionId::EndTran:
+
+ pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLEndTran);
+ break;
+ case ODBC3SQLFunctionId::Disconnect:
+
+ pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLDisconnect);
+ break;
+ case ODBC3SQLFunctionId::FreeHandle:
+
+ pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLFreeHandle);
+ break;
+ case ODBC3SQLFunctionId::GetCursorName:
+
+ pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLGetCursorName);
+ break;
+ case ODBC3SQLFunctionId::NativeSql:
+
+ pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLNativeSql);
+ break;
+ default:
+ OSL_FAIL("Function unknown!");
+ }
+ return pFunction;
+}
+
+
+// ODBC Environment (common for all Connections):
+SQLHANDLE ORealOdbcDriver::EnvironmentHandle(OUString &_rPath)
+{
+ // Is (for this instance) already an Environment made?
+ if (!m_pDriverHandle)
+ {
+ SQLHANDLE h = SQL_NULL_HANDLE;
+ // allocate Environment
+
+ // load ODBC-DLL now:
+ if (!LoadLibrary_ODBC3(_rPath) || N3SQLAllocHandle(SQL_HANDLE_ENV,SQL_NULL_HANDLE,&h) != SQL_SUCCESS)
+ return SQL_NULL_HANDLE;
+
+ // Save in global Structure
+ m_pDriverHandle = h;
+ N3SQLSetEnvAttr(h, SQL_ATTR_ODBC_VERSION, reinterpret_cast<SQLPOINTER>(SQL_OV_ODBC3), SQL_IS_UINTEGER);
+ //N3SQLSetEnvAttr(h, SQL_ATTR_CONNECTION_POOLING,(SQLPOINTER) SQL_CP_ONE_PER_HENV, SQL_IS_INTEGER);
+ }
+
+ return m_pDriverHandle;
+}
+
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+connectivity_odbc_ORealOdbcDriver_get_implementation(
+ css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new connectivity::odbc::ORealOdbcDriver(context));
+}
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/odbc/OResultSet.cxx b/connectivity/source/drivers/odbc/OResultSet.cxx
new file mode 100644
index 0000000000..9e68cd1763
--- /dev/null
+++ b/connectivity/source/drivers/odbc/OResultSet.cxx
@@ -0,0 +1,1847 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <odbc/OResultSet.hxx>
+#include <odbc/OTools.hxx>
+#include <odbc/OResultSetMetaData.hxx>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/beans/PropertyVetoException.hpp>
+#include <com/sun/star/sdbcx/CompareBookmark.hpp>
+#include <com/sun/star/sdbc/ResultSetConcurrency.hpp>
+#include <com/sun/star/sdbc/ResultSetType.hpp>
+#include <comphelper/property.hxx>
+#include <comphelper/sequence.hxx>
+#include <cppuhelper/typeprovider.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <comphelper/types.hxx>
+#include <connectivity/dbtools.hxx>
+#include <connectivity/dbexception.hxx>
+#include <o3tl/safeint.hxx>
+#include <sal/log.hxx>
+
+using namespace ::comphelper;
+using namespace connectivity;
+using namespace connectivity::odbc;
+using namespace cppu;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::sdbc;
+using namespace com::sun::star::sdbcx;
+using namespace com::sun::star::container;
+using namespace com::sun::star::io;
+using namespace com::sun::star::util;
+
+#define ODBC_SQL_NOT_DEFINED 99UL
+static_assert(ODBC_SQL_NOT_DEFINED != SQL_UB_OFF, "ODBC_SQL_NOT_DEFINED must be unique");
+static_assert(ODBC_SQL_NOT_DEFINED != SQL_UB_ON, "ODBC_SQL_NOT_DEFINED must be unique");
+static_assert(ODBC_SQL_NOT_DEFINED != SQL_UB_FIXED, "ODBC_SQL_NOT_DEFINED must be unique");
+static_assert(ODBC_SQL_NOT_DEFINED != SQL_UB_VARIABLE, "ODBC_SQL_NOT_DEFINED must be unique");
+
+namespace
+{
+ const SQLLEN nMaxBookmarkLen = 20;
+}
+
+
+// IMPLEMENT_SERVICE_INFO(OResultSet,"com.sun.star.sdbcx.OResultSet","com.sun.star.sdbc.ResultSet");
+OUString SAL_CALL OResultSet::getImplementationName( )
+{
+ return "com.sun.star.sdbcx.odbc.ResultSet";
+}
+
+ Sequence< OUString > SAL_CALL OResultSet::getSupportedServiceNames( )
+{
+ return { "com.sun.star.sdbc.ResultSet", "com.sun.star.sdbcx.ResultSet" };
+}
+
+sal_Bool SAL_CALL OResultSet::supportsService( const OUString& _rServiceName )
+{
+ return cppu::supportsService(this, _rServiceName);
+}
+
+
+OResultSet::OResultSet(SQLHANDLE _pStatementHandle ,OStatement_Base* pStmt) : OResultSet_BASE(m_aMutex)
+ ,OPropertySetHelper(OResultSet_BASE::rBHelper)
+ ,m_bFetchDataInOrder(true)
+ ,m_aStatementHandle(_pStatementHandle)
+ ,m_aConnectionHandle(pStmt->getConnectionHandle())
+ ,m_pStatement(pStmt)
+ ,m_xStatement(*pStmt)
+ ,m_nTextEncoding(pStmt->getOwnConnection()->getTextEncoding())
+ ,m_nRowPos(0)
+ ,m_nUseBookmarks(ODBC_SQL_NOT_DEFINED)
+ ,m_nCurrentFetchState(0)
+ ,m_bWasNull(true)
+ ,m_bEOF(true)
+ ,m_bRowInserted(false)
+ ,m_bRowDeleted(false)
+ ,m_bUseFetchScroll(false)
+{
+ osl_atomic_increment( &m_refCount );
+ try
+ {
+ m_pRowStatusArray.reset( new SQLUSMALLINT[1] ); // the default value
+ setStmtOption<SQLUSMALLINT*, SQL_IS_POINTER>(SQL_ATTR_ROW_STATUS_PTR, m_pRowStatusArray.get());
+ }
+ catch(const Exception&)
+ { // we don't want our result destroy here
+ }
+
+ try
+ {
+ SQLULEN nCurType = getStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_CURSOR_TYPE);
+ SQLUINTEGER nValueLen = m_pStatement->getCursorProperties(nCurType,false);
+ if( (nValueLen & SQL_CA2_SENSITIVITY_DELETIONS) != SQL_CA2_SENSITIVITY_DELETIONS ||
+ (nValueLen & SQL_CA2_CRC_EXACT) != SQL_CA2_CRC_EXACT)
+ m_pSkipDeletedSet.reset( new OSkipDeletedSet(this) );
+ }
+ catch(const Exception&)
+ { // we don't want our result destroy here
+ }
+ try
+ {
+ SQLUINTEGER nValueLen = 0;
+ // Reference: http://msdn.microsoft.com/en-us/library/windows/desktop/ms715441%28v=vs.85%29.aspx
+ // LibreOffice ODBC binds columns only on update, so we don't care about SQL_GD_ANY_COLUMN / SQL_GD_BOUND
+ // TODO: maybe a problem if a column is updated, then an earlier column fetched?
+ // an updated column is bound...
+ // TODO: aren't we assuming SQL_GD_OUTPUT_PARAMS?
+ // If yes, we should at least OSL_ENSURE it,
+ // even better throw an exception any OUT parameter registration if !SQL_GD_OUTPUT_PARAMS.
+ // If !SQL_GD_ANY_ORDER, cache the whole row so that callers can access columns in any order.
+ // In other words, isolate them from ODBC restrictions.
+ // TODO: we assume SQL_GD_BLOCK, unless fetchSize is 1
+ OTools::GetInfo(m_pStatement->getOwnConnection(),m_aConnectionHandle,SQL_GETDATA_EXTENSIONS,nValueLen,nullptr);
+ m_bFetchDataInOrder = ((SQL_GD_ANY_ORDER & nValueLen) != SQL_GD_ANY_ORDER);
+ }
+ catch(const Exception&)
+ {
+ m_bFetchDataInOrder = true;
+ }
+ try
+ {
+ // TODO: this does *not* do what it appears.
+ // We use SQLFetchScroll unconditionally in several places
+ // the *only* difference this makes is whether ::next() uses SQLFetchScroll or SQLFetch
+ // so this test seems pointless
+ if ( getOdbcFunction(ODBC3SQLFunctionId::GetFunctions) )
+ {
+ SQLUSMALLINT nSupported = 0;
+ m_bUseFetchScroll = ( N3SQLGetFunctions(m_aConnectionHandle,SQL_API_SQLFETCHSCROLL,&nSupported) == SQL_SUCCESS && nSupported == 1 );
+ }
+ }
+ catch(const Exception&)
+ {
+ m_bUseFetchScroll = false;
+ }
+
+ osl_atomic_decrement( &m_refCount );
+}
+
+OResultSet::~OResultSet()
+{
+}
+
+void OResultSet::construct()
+{
+ osl_atomic_increment( &m_refCount );
+ allocBuffer();
+ osl_atomic_decrement( &m_refCount );
+}
+
+void OResultSet::disposing()
+{
+ N3SQLCloseCursor(m_aStatementHandle);
+ OPropertySetHelper::disposing();
+
+ ::osl::MutexGuard aGuard(m_aMutex);
+ releaseBuffer();
+
+ setStmtOption<SQLUSMALLINT*, SQL_IS_POINTER>(SQL_ATTR_ROW_STATUS_PTR, nullptr);
+ m_xStatement.clear();
+ m_xMetaData.clear();
+}
+
+SQLRETURN OResultSet::unbind(bool _bUnbindHandle)
+{
+ SQLRETURN nRet = 0;
+ if ( _bUnbindHandle )
+ nRet = N3SQLFreeStmt(m_aStatementHandle,SQL_UNBIND);
+
+ if ( !m_aBindVector.empty() )
+ {
+ for(auto& [rPtrAddr, rType] : m_aBindVector)
+ {
+ switch (rType)
+ {
+ case DataType::CHAR:
+ case DataType::VARCHAR:
+ delete static_cast< OString* >(reinterpret_cast< void * >(rPtrAddr));
+ break;
+ case DataType::BIGINT:
+ delete static_cast< sal_Int64* >(reinterpret_cast< void * >(rPtrAddr));
+ break;
+ case DataType::DECIMAL:
+ case DataType::NUMERIC:
+ delete static_cast< OString* >(reinterpret_cast< void * >(rPtrAddr));
+ break;
+ case DataType::REAL:
+ case DataType::DOUBLE:
+ delete static_cast< double* >(reinterpret_cast< void * >(rPtrAddr));
+ break;
+ case DataType::LONGVARCHAR:
+ case DataType::CLOB:
+ delete [] static_cast< char* >(reinterpret_cast< void * >(rPtrAddr));
+ break;
+ case DataType::LONGVARBINARY:
+ case DataType::BLOB:
+ delete [] static_cast< char* >(reinterpret_cast< void * >(rPtrAddr));
+ break;
+ case DataType::DATE:
+ delete static_cast< DATE_STRUCT* >(reinterpret_cast< void * >(rPtrAddr));
+ break;
+ case DataType::TIME:
+ delete static_cast< TIME_STRUCT* >(reinterpret_cast< void * >(rPtrAddr));
+ break;
+ case DataType::TIMESTAMP:
+ delete static_cast< TIMESTAMP_STRUCT* >(reinterpret_cast< void * >(rPtrAddr));
+ break;
+ case DataType::BIT:
+ case DataType::TINYINT:
+ delete static_cast< sal_Int8* >(reinterpret_cast< void * >(rPtrAddr));
+ break;
+ case DataType::SMALLINT:
+ delete static_cast< sal_Int16* >(reinterpret_cast< void * >(rPtrAddr));
+ break;
+ case DataType::INTEGER:
+ delete static_cast< sal_Int32* >(reinterpret_cast< void * >(rPtrAddr));
+ break;
+ case DataType::FLOAT:
+ delete static_cast< float* >(reinterpret_cast< void * >(rPtrAddr));
+ break;
+ case DataType::BINARY:
+ case DataType::VARBINARY:
+ delete static_cast< sal_Int8* >(reinterpret_cast< void * >(rPtrAddr));
+ break;
+ }
+ }
+ m_aBindVector.clear();
+ }
+ return nRet;
+}
+
+TVoidPtr OResultSet::allocBindColumn(sal_Int32 _nType,sal_Int32 _nColumnIndex)
+{
+ TVoidPtr aPair;
+ switch (_nType)
+ {
+ case DataType::CHAR:
+ case DataType::VARCHAR:
+ aPair = TVoidPtr(reinterpret_cast< sal_Int64 >(new OString()),_nType);
+ break;
+ case DataType::BIGINT:
+ aPair = TVoidPtr(reinterpret_cast< sal_Int64 >(new sal_Int64(0)),_nType);
+ break;
+ case DataType::DECIMAL:
+ case DataType::NUMERIC:
+ aPair = TVoidPtr(reinterpret_cast< sal_Int64 >(new OString()),_nType);
+ break;
+ case DataType::REAL:
+ case DataType::DOUBLE:
+ aPair = TVoidPtr(reinterpret_cast< sal_Int64 >(new double(0.0)),_nType);
+ break;
+ case DataType::LONGVARCHAR:
+ case DataType::CLOB:
+ aPair = TVoidPtr(reinterpret_cast< sal_Int64 >(new char[2]),_nType); // only for finding
+ break;
+ case DataType::LONGVARBINARY:
+ case DataType::BLOB:
+ aPair = TVoidPtr(reinterpret_cast< sal_Int64 >(new char[2]),_nType); // only for finding
+ break;
+ case DataType::DATE:
+ aPair = TVoidPtr(reinterpret_cast< sal_Int64 >(new DATE_STRUCT),_nType);
+ break;
+ case DataType::TIME:
+ aPair = TVoidPtr(reinterpret_cast< sal_Int64 >(new TIME_STRUCT),_nType);
+ break;
+ case DataType::TIMESTAMP:
+ aPair = TVoidPtr(reinterpret_cast< sal_Int64 >(new TIMESTAMP_STRUCT),_nType);
+ break;
+ case DataType::BIT:
+ case DataType::TINYINT:
+ aPair = TVoidPtr(reinterpret_cast< sal_Int64 >(new sal_Int8(0)),_nType);
+ break;
+ case DataType::SMALLINT:
+ aPair = TVoidPtr(reinterpret_cast< sal_Int64 >(new sal_Int16(0)),_nType);
+ break;
+ case DataType::INTEGER:
+ aPair = TVoidPtr(reinterpret_cast< sal_Int64 >(new sal_Int32(0)),_nType);
+ break;
+ case DataType::FLOAT:
+ aPair = TVoidPtr(reinterpret_cast< sal_Int64 >(new float(0)),_nType);
+ break;
+ case DataType::BINARY:
+ case DataType::VARBINARY:
+ aPair = TVoidPtr(reinterpret_cast< sal_Int64 >(new sal_Int8[m_aRow[_nColumnIndex].getSequence().getLength()]),_nType);
+ break;
+ default:
+ SAL_WARN( "connectivity.odbc", "Unknown type");
+ aPair = TVoidPtr(0,_nType);
+ }
+ return aPair;
+}
+
+void OResultSet::allocBuffer()
+{
+ Reference< XResultSetMetaData > xMeta = getMetaData();
+ sal_Int32 nLen = xMeta->getColumnCount();
+
+ m_aBindVector.reserve(nLen);
+ m_aRow.resize(nLen+1);
+
+ m_aRow[0].setTypeKind(DataType::VARBINARY);
+ m_aRow[0].setBound( false );
+
+ for(sal_Int32 i = 1;i<=nLen;++i)
+ {
+ sal_Int32 nType = xMeta->getColumnType(i);
+ m_aRow[i].setTypeKind( nType );
+ m_aRow[i].setBound( false );
+ }
+ m_aLengthVector.resize(nLen + 1);
+}
+
+void OResultSet::releaseBuffer()
+{
+ unbind(false);
+ m_aLengthVector.clear();
+}
+
+Any SAL_CALL OResultSet::queryInterface( const Type & rType )
+{
+ Any aRet = OPropertySetHelper::queryInterface(rType);
+ return aRet.hasValue() ? aRet : OResultSet_BASE::queryInterface(rType);
+}
+
+ Sequence< Type > SAL_CALL OResultSet::getTypes( )
+{
+ OTypeCollection aTypes( cppu::UnoType<css::beans::XMultiPropertySet>::get(),
+ cppu::UnoType<css::beans::XFastPropertySet>::get(),
+ cppu::UnoType<css::beans::XPropertySet>::get());
+
+ return ::comphelper::concatSequences(aTypes.getTypes(),OResultSet_BASE::getTypes());
+}
+
+
+sal_Int32 SAL_CALL OResultSet::findColumn( const OUString& columnName )
+{
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ Reference< XResultSetMetaData > xMeta = getMetaData();
+ sal_Int32 nLen = xMeta->getColumnCount();
+ sal_Int32 i = 1;
+ for(;i<=nLen;++i)
+ {
+ if(xMeta->isCaseSensitive(i) ? columnName == xMeta->getColumnName(i) :
+ columnName.equalsIgnoreAsciiCase(xMeta->getColumnName(i)))
+ return i;
+ }
+
+ ::dbtools::throwInvalidColumnException( columnName, *this );
+ assert(false);
+ return 0; // Never reached
+}
+
+void OResultSet::ensureCacheForColumn(sal_Int32 columnIndex)
+{
+ SAL_INFO( "connectivity.odbc", "odbc lionel@mamane.lu OResultSet::ensureCacheForColumn" );
+
+ assert(columnIndex >= 0);
+
+ const TDataRow::size_type oldCacheSize = m_aRow.size();
+ const TDataRow::size_type uColumnIndex = static_cast<TDataRow::size_type>(columnIndex);
+
+ if (oldCacheSize > uColumnIndex)
+ // nothing to do
+ return;
+
+ m_aRow.resize(columnIndex + 1);
+ TDataRow::iterator i (m_aRow.begin() + oldCacheSize);
+ const TDataRow::const_iterator end(m_aRow.end());
+ for (; i != end; ++i)
+ {
+ i->setBound(false);
+ }
+}
+void OResultSet::invalidateCache()
+{
+ for(auto& rItem : m_aRow)
+ {
+ rItem.setBound(false);
+ }
+}
+
+Reference< XInputStream > SAL_CALL OResultSet::getBinaryStream( sal_Int32 /*columnIndex*/ )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ ::dbtools::throwFunctionNotSupportedSQLException( "XRow::getBinaryStream", *this );
+
+ return nullptr;
+}
+
+Reference< XInputStream > SAL_CALL OResultSet::getCharacterStream( sal_Int32 /*columnIndex*/ )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ ::dbtools::throwFunctionNotSupportedSQLException( "XRow::getBinaryStream", *this );
+
+ return nullptr;
+}
+
+template < typename T > T OResultSet::impl_getValue( const sal_Int32 _nColumnIndex, SQLSMALLINT nType )
+{
+ T val;
+
+ OTools::getValue(m_pStatement->getOwnConnection(), m_aStatementHandle, _nColumnIndex, nType, m_bWasNull, **this, &val, sizeof(val));
+
+ return val;
+}
+
+// this function exists for the implicit conversion to sal_Bool (compared to a direct call to impl_getValue)
+bool OResultSet::impl_getBoolean( sal_Int32 columnIndex )
+{
+ return impl_getValue<sal_Int8>(columnIndex, SQL_C_BIT);
+}
+
+template < typename T > T OResultSet::getValue( sal_Int32 columnIndex )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+ fillColumn(columnIndex);
+ m_bWasNull = m_aRow[columnIndex].isNull();
+ auto const & row = m_aRow[columnIndex];
+ if constexpr ( std::is_same_v<css::util::Time, T> )
+ return row.getTime();
+ else if constexpr ( std::is_same_v<css::util::DateTime, T> )
+ return row.getDateTime();
+ else if constexpr ( std::is_same_v<css::util::Date, T> )
+ return row.getDate();
+ else if constexpr ( std::is_same_v<OUString, T> )
+ return row.getString();
+ else if constexpr ( std::is_same_v<sal_Int64, T> )
+ return row.getLong();
+ else if constexpr ( std::is_same_v<sal_Int32, T> )
+ return row.getInt32();
+ else if constexpr ( std::is_same_v<sal_Int16, T> )
+ return row.getInt16();
+ else if constexpr ( std::is_same_v<sal_Int8, T> )
+ return row.getInt8();
+ else if constexpr ( std::is_same_v<float, T> )
+ return row.getFloat();
+ else if constexpr ( std::is_same_v<double, T> )
+ return row.getDouble();
+ else if constexpr ( std::is_same_v<bool, T> )
+ return row.getBool();
+ else
+ return row;
+}
+
+sal_Bool SAL_CALL OResultSet::getBoolean( sal_Int32 columnIndex )
+{
+ return getValue<bool>( columnIndex );
+}
+
+sal_Int8 SAL_CALL OResultSet::getByte( sal_Int32 columnIndex )
+{
+ return getValue<sal_Int8>( columnIndex );
+}
+
+
+Sequence< sal_Int8 > SAL_CALL OResultSet::getBytes( sal_Int32 columnIndex )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+ fillColumn(columnIndex);
+ m_bWasNull = m_aRow[columnIndex].isNull();
+
+ Sequence< sal_Int8 > nRet;
+ switch(m_aRow[columnIndex].getTypeKind())
+ {
+ case DataType::BINARY:
+ case DataType::VARBINARY:
+ case DataType::LONGVARBINARY:
+ nRet = m_aRow[columnIndex].getSequence();
+ break;
+ default:
+ {
+ OUString const & sRet = m_aRow[columnIndex].getString();
+ nRet = Sequence<sal_Int8>(reinterpret_cast<const sal_Int8*>(sRet.getStr()),sizeof(sal_Unicode)*sRet.getLength());
+ }
+ }
+ return nRet;
+}
+Sequence< sal_Int8 > OResultSet::impl_getBytes( sal_Int32 columnIndex )
+{
+ const SWORD nColumnType = impl_getColumnType_nothrow(columnIndex);
+
+ switch(nColumnType)
+ {
+ case SQL_WVARCHAR:
+ case SQL_WCHAR:
+ case SQL_WLONGVARCHAR:
+ case SQL_VARCHAR:
+ case SQL_CHAR:
+ case SQL_LONGVARCHAR:
+ {
+ OUString const & aRet = OTools::getStringValue(m_pStatement->getOwnConnection(),m_aStatementHandle,columnIndex,nColumnType,m_bWasNull,**this,m_nTextEncoding);
+ return Sequence<sal_Int8>(reinterpret_cast<const sal_Int8*>(aRet.getStr()),sizeof(sal_Unicode)*aRet.getLength());
+ }
+ default:
+ return OTools::getBytesValue(m_pStatement->getOwnConnection(),m_aStatementHandle,columnIndex,SQL_C_BINARY,m_bWasNull,**this);
+ }
+}
+
+Date OResultSet::impl_getDate( sal_Int32 columnIndex )
+{
+ DATE_STRUCT aDate = impl_getValue< DATE_STRUCT> ( columnIndex,
+ m_pStatement->getOwnConnection()->useOldDateFormat() ? SQL_C_DATE : SQL_C_TYPE_DATE );
+
+ return Date(aDate.day, aDate.month, aDate.year);
+}
+
+Date SAL_CALL OResultSet::getDate( sal_Int32 columnIndex )
+{
+ return getValue<Date>( columnIndex );
+}
+
+
+double SAL_CALL OResultSet::getDouble( sal_Int32 columnIndex )
+{
+ return getValue<double>( columnIndex );
+}
+
+
+float SAL_CALL OResultSet::getFloat( sal_Int32 columnIndex )
+{
+ return getValue<float>( columnIndex );
+}
+
+sal_Int16 SAL_CALL OResultSet::getShort( sal_Int32 columnIndex )
+{
+ return getValue<sal_Int16>( columnIndex );
+}
+
+sal_Int32 SAL_CALL OResultSet::getInt( sal_Int32 columnIndex )
+{
+ return getValue<sal_Int32>( columnIndex );
+}
+
+sal_Int64 SAL_CALL OResultSet::getLong( sal_Int32 columnIndex )
+{
+ return getValue<sal_Int64>( columnIndex );
+}
+sal_Int64 OResultSet::impl_getLong( sal_Int32 columnIndex )
+{
+ try
+ {
+ return impl_getValue<sal_Int64>(columnIndex, SQL_C_SBIGINT);
+ }
+ catch(const SQLException&)
+ {
+ return getString(columnIndex).toInt64();
+ }
+}
+
+sal_Int32 SAL_CALL OResultSet::getRow( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ return m_pSkipDeletedSet ? m_pSkipDeletedSet->getMappedPosition(getDriverPos()) : getDriverPos();
+}
+
+Reference< XResultSetMetaData > SAL_CALL OResultSet::getMetaData( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+
+ if(!m_xMetaData.is())
+ m_xMetaData = new OResultSetMetaData(m_pStatement->getOwnConnection(),m_aStatementHandle);
+ return m_xMetaData;
+}
+
+Reference< XArray > SAL_CALL OResultSet::getArray( sal_Int32 /*columnIndex*/ )
+{
+ ::dbtools::throwFunctionNotSupportedSQLException( "XRow::getArray", *this );
+ return nullptr;
+}
+
+
+Reference< XClob > SAL_CALL OResultSet::getClob( sal_Int32 /*columnIndex*/ )
+{
+ ::dbtools::throwFunctionNotSupportedSQLException( "XRow::getClob", *this );
+ return nullptr;
+}
+
+Reference< XBlob > SAL_CALL OResultSet::getBlob( sal_Int32 /*columnIndex*/ )
+{
+ ::dbtools::throwFunctionNotSupportedSQLException( "XRow::getBlob", *this );
+ return nullptr;
+}
+
+
+Reference< XRef > SAL_CALL OResultSet::getRef( sal_Int32 /*columnIndex*/ )
+{
+ ::dbtools::throwFunctionNotSupportedSQLException( "XRow::getRef", *this );
+ return nullptr;
+}
+
+
+Any SAL_CALL OResultSet::getObject( sal_Int32 columnIndex, const Reference< css::container::XNameAccess >& /*typeMap*/ )
+{
+ return getValue<ORowSetValue>( columnIndex ).makeAny();
+}
+
+OUString OResultSet::impl_getString( sal_Int32 columnIndex )
+{
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+ const SWORD nColumnType = impl_getColumnType_nothrow(columnIndex);
+ return OTools::getStringValue(m_pStatement->getOwnConnection(),m_aStatementHandle,columnIndex,nColumnType,m_bWasNull,**this,m_nTextEncoding);
+}
+OUString OResultSet::getString( sal_Int32 columnIndex )
+{
+ return getValue<OUString>( columnIndex );
+}
+
+Time OResultSet::impl_getTime( sal_Int32 columnIndex )
+{
+ TIME_STRUCT aTime = impl_getValue< TIME_STRUCT > ( columnIndex,
+ m_pStatement->getOwnConnection()->useOldDateFormat() ? SQL_C_TIME : SQL_C_TYPE_TIME );
+
+ return Time(0, aTime.second,aTime.minute,aTime.hour, false);
+}
+Time SAL_CALL OResultSet::getTime( sal_Int32 columnIndex )
+{
+ return getValue<Time>( columnIndex );
+}
+
+DateTime OResultSet::impl_getTimestamp( sal_Int32 columnIndex )
+{
+ TIMESTAMP_STRUCT aTime = impl_getValue< TIMESTAMP_STRUCT > ( columnIndex,
+ m_pStatement->getOwnConnection()->useOldDateFormat() ? SQL_C_TIMESTAMP : SQL_C_TYPE_TIMESTAMP );
+
+ return DateTime(aTime.fraction,
+ aTime.second,
+ aTime.minute,
+ aTime.hour,
+ aTime.day,
+ aTime.month,
+ aTime.year,
+ false);
+}
+DateTime SAL_CALL OResultSet::getTimestamp( sal_Int32 columnIndex )
+{
+ return getValue<DateTime>( columnIndex );
+}
+
+sal_Bool SAL_CALL OResultSet::isBeforeFirst( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+ return m_nRowPos == 0;
+}
+
+sal_Bool SAL_CALL OResultSet::isAfterLast( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ return m_nRowPos != 0 && m_nCurrentFetchState == SQL_NO_DATA;
+}
+
+sal_Bool SAL_CALL OResultSet::isFirst( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ return m_nRowPos == 1;
+}
+
+sal_Bool SAL_CALL OResultSet::isLast( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+
+ return m_bEOF && m_nCurrentFetchState != SQL_NO_DATA;
+}
+
+void SAL_CALL OResultSet::beforeFirst( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+
+ if(first())
+ previous();
+ m_nCurrentFetchState = SQL_SUCCESS;
+}
+
+void SAL_CALL OResultSet::afterLast( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ if(last())
+ next();
+ m_bEOF = true;
+}
+
+
+void SAL_CALL OResultSet::close( )
+{
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ }
+ dispose();
+}
+
+
+sal_Bool SAL_CALL OResultSet::first( )
+{
+ return moveImpl(IResultSetHelper::FIRST,0);
+}
+
+
+sal_Bool SAL_CALL OResultSet::last( )
+{
+ return moveImpl(IResultSetHelper::LAST,0);
+}
+
+sal_Bool SAL_CALL OResultSet::absolute( sal_Int32 row )
+{
+ return moveImpl(IResultSetHelper::ABSOLUTE1,row);
+}
+
+sal_Bool SAL_CALL OResultSet::relative( sal_Int32 row )
+{
+ return moveImpl(IResultSetHelper::RELATIVE1,row);
+}
+
+sal_Bool SAL_CALL OResultSet::previous( )
+{
+ return moveImpl(IResultSetHelper::PRIOR,0);
+}
+
+Reference< XInterface > SAL_CALL OResultSet::getStatement( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+ return m_xStatement;
+}
+
+
+sal_Bool SAL_CALL OResultSet::rowDeleted()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ bool bRet = m_bRowDeleted;
+ m_bRowDeleted = false;
+
+ return bRet;
+}
+
+sal_Bool SAL_CALL OResultSet::rowInserted( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ bool bInserted = m_bRowInserted;
+ m_bRowInserted = false;
+
+ return bInserted;
+}
+
+sal_Bool SAL_CALL OResultSet::rowUpdated( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+
+ return m_pRowStatusArray[0] == SQL_ROW_UPDATED;
+}
+
+
+sal_Bool SAL_CALL OResultSet::next( )
+{
+ return moveImpl(IResultSetHelper::NEXT,1);
+}
+
+
+sal_Bool SAL_CALL OResultSet::wasNull( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ return m_bWasNull;
+}
+
+
+void SAL_CALL OResultSet::cancel( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+
+ N3SQLCancel(m_aStatementHandle);
+}
+
+void SAL_CALL OResultSet::clearWarnings( )
+{
+}
+
+Any SAL_CALL OResultSet::getWarnings( )
+{
+ return Any();
+}
+
+void SAL_CALL OResultSet::insertRow( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+
+ SQLLEN nRealLen = 0;
+ Sequence<sal_Int8> aBookmark(nMaxBookmarkLen);
+ static_assert(o3tl::make_unsigned(nMaxBookmarkLen) >= sizeof(SQLLEN), "must be larger");
+
+ SQLRETURN nRet = N3SQLBindCol(m_aStatementHandle,
+ 0,
+ SQL_C_VARBOOKMARK,
+ aBookmark.getArray(),
+ nMaxBookmarkLen,
+ &nRealLen
+ );
+
+ bool bPositionByBookmark = ( nullptr != getOdbcFunction( ODBC3SQLFunctionId::BulkOperations ) );
+ if ( bPositionByBookmark )
+ {
+ nRet = N3SQLBulkOperations( m_aStatementHandle, SQL_ADD );
+ fillNeededData( nRet );
+ }
+ else
+ {
+ if(isBeforeFirst())
+ next(); // must be done
+ nRet = N3SQLSetPos( m_aStatementHandle, 1, SQL_ADD, SQL_LOCK_NO_CHANGE );
+ fillNeededData( nRet );
+ }
+ aBookmark.realloc(nRealLen);
+ try
+ {
+ OTools::ThrowException(m_pStatement->getOwnConnection(),nRet,m_aStatementHandle,SQL_HANDLE_STMT,*this);
+ }
+ catch(const SQLException&)
+ {
+ nRet = unbind();
+ throw;
+ }
+
+ nRet = unbind();
+ OTools::ThrowException(m_pStatement->getOwnConnection(),nRet,m_aStatementHandle,SQL_HANDLE_STMT,*this);
+
+ if ( bPositionByBookmark )
+ {
+ setStmtOption<SQLLEN*, SQL_IS_POINTER>(SQL_ATTR_FETCH_BOOKMARK_PTR, reinterpret_cast<SQLLEN*>(aBookmark.getArray()));
+
+ nRet = N3SQLFetchScroll(m_aStatementHandle,SQL_FETCH_BOOKMARK,0);
+ }
+ else
+ nRet = N3SQLFetchScroll(m_aStatementHandle,SQL_FETCH_RELATIVE,0); // OJ 06.03.2004
+ // sometimes we got an error but we are not interested in anymore #106047# OJ
+ // OTools::ThrowException(m_pStatement->getOwnConnection(),nRet,m_aStatementHandle,SQL_HANDLE_STMT,*this);
+
+ if(m_pSkipDeletedSet)
+ {
+ if(moveToBookmark(Any(aBookmark)))
+ {
+ sal_Int32 nRowPos = getDriverPos();
+ if ( -1 == m_nRowPos )
+ {
+ nRowPos = m_aPosToBookmarks.size() + 1;
+ }
+ if ( nRowPos == m_nRowPos )
+ ++nRowPos;
+ m_nRowPos = nRowPos;
+ m_pSkipDeletedSet->insertNewPosition(nRowPos);
+ m_aPosToBookmarks[aBookmark] = nRowPos;
+ }
+ }
+ m_bRowInserted = true;
+
+}
+
+void SAL_CALL OResultSet::updateRow( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ SQLRETURN nRet;
+
+ try
+ {
+ bool bPositionByBookmark = ( nullptr != getOdbcFunction( ODBC3SQLFunctionId::BulkOperations ) );
+ if ( bPositionByBookmark )
+ {
+ getBookmark();
+ assert(m_aRow[0].isBound());
+ Sequence<sal_Int8> aBookmark(m_aRow[0].getSequence());
+ SQLLEN nRealLen = aBookmark.getLength();
+ nRet = N3SQLBindCol(m_aStatementHandle,
+ 0,
+ SQL_C_VARBOOKMARK,
+ aBookmark.getArray(),
+ aBookmark.getLength(),
+ &nRealLen
+ );
+ OTools::ThrowException(m_pStatement->getOwnConnection(),nRet,m_aStatementHandle,SQL_HANDLE_STMT,*this);
+ nRet = N3SQLBulkOperations(m_aStatementHandle, SQL_UPDATE_BY_BOOKMARK);
+ fillNeededData(nRet);
+ // the driver should not have touched this
+ // (neither the contents of aBookmark FWIW)
+ assert(nRealLen == aBookmark.getLength());
+ }
+ else
+ {
+ nRet = N3SQLSetPos(m_aStatementHandle,1,SQL_UPDATE,SQL_LOCK_NO_CHANGE);
+ fillNeededData(nRet);
+ }
+ OTools::ThrowException(m_pStatement->getOwnConnection(),nRet,m_aStatementHandle,SQL_HANDLE_STMT,*this);
+ // unbind all columns so we can fetch all columns again with SQLGetData
+ // (and also so that our buffers don't clobber anything, and
+ // so that a subsequent fetch does not overwrite m_aRow[0])
+ invalidateCache();
+ nRet = unbind();
+ OSL_ENSURE(nRet == SQL_SUCCESS,"ODBC insert could not unbind the columns after success");
+ }
+ catch(...)
+ {
+ // unbind all columns so that a subsequent fetch does not overwrite m_aRow[0]
+ nRet = unbind();
+ OSL_ENSURE(nRet == SQL_SUCCESS,"ODBC insert could not unbind the columns after failure");
+ throw;
+ }
+}
+
+void SAL_CALL OResultSet::deleteRow( )
+{
+ SQLRETURN nRet = SQL_SUCCESS;
+ sal_Int32 nPos = getDriverPos();
+ nRet = N3SQLSetPos(m_aStatementHandle,1,SQL_DELETE,SQL_LOCK_NO_CHANGE);
+ OTools::ThrowException(m_pStatement->getOwnConnection(),nRet,m_aStatementHandle,SQL_HANDLE_STMT,*this);
+
+ m_bRowDeleted = ( m_pRowStatusArray[0] == SQL_ROW_DELETED );
+ if ( m_bRowDeleted )
+ {
+ TBookmarkPosMap::iterator aIter = std::find_if(m_aPosToBookmarks.begin(), m_aPosToBookmarks.end(),
+ [&nPos](const TBookmarkPosMap::value_type& rEntry) { return rEntry.second == nPos; });
+ if (aIter != m_aPosToBookmarks.end())
+ m_aPosToBookmarks.erase(aIter);
+ }
+ if ( m_pSkipDeletedSet )
+ m_pSkipDeletedSet->deletePosition(nPos);
+}
+
+
+void SAL_CALL OResultSet::cancelRowUpdates( )
+{
+}
+
+
+void SAL_CALL OResultSet::moveToInsertRow( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+
+ invalidateCache();
+ // first unbound all columns
+ OSL_VERIFY( unbind() == SQL_SUCCESS );
+ // SQLRETURN nRet = N3SQLSetStmtAttr(m_aStatementHandle,SQL_ATTR_ROW_ARRAY_SIZE ,(SQLPOINTER)1,SQL_IS_INTEGER);
+}
+
+
+void SAL_CALL OResultSet::moveToCurrentRow( )
+{
+ invalidateCache();
+}
+
+void OResultSet::updateValue(sal_Int32 columnIndex, SQLSMALLINT _nType, void const * _pValue)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ m_aBindVector.push_back(allocBindColumn(OTools::MapOdbcType2Jdbc(_nType),columnIndex));
+ void* pData = reinterpret_cast<void*>(m_aBindVector.rbegin()->first);
+ OSL_ENSURE(pData != nullptr,"Data for update is NULL!");
+ OTools::bindValue( m_pStatement->getOwnConnection(),
+ m_aStatementHandle,
+ columnIndex,
+ _nType,
+ 0,
+ _pValue,
+ pData,
+ &m_aLengthVector[columnIndex],
+ **this,
+ m_nTextEncoding,
+ m_pStatement->getOwnConnection()->useOldDateFormat());
+}
+
+void SAL_CALL OResultSet::updateNull( sal_Int32 columnIndex )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ m_aBindVector.push_back(allocBindColumn(DataType::CHAR,columnIndex));
+ void* pData = reinterpret_cast<void*>(m_aBindVector.rbegin()->first);
+ OTools::bindValue(m_pStatement->getOwnConnection(),m_aStatementHandle,columnIndex,SQL_CHAR,0,nullptr,pData,&m_aLengthVector[columnIndex],**this,m_nTextEncoding,m_pStatement->getOwnConnection()->useOldDateFormat());
+}
+
+
+void SAL_CALL OResultSet::updateBoolean( sal_Int32 columnIndex, sal_Bool x )
+{
+ updateValue(columnIndex,SQL_BIT,&x);
+}
+
+void SAL_CALL OResultSet::updateByte( sal_Int32 columnIndex, sal_Int8 x )
+{
+ updateValue(columnIndex,SQL_CHAR,&x);
+}
+
+
+void SAL_CALL OResultSet::updateShort( sal_Int32 columnIndex, sal_Int16 x )
+{
+ updateValue(columnIndex,SQL_TINYINT,&x);
+}
+
+void SAL_CALL OResultSet::updateInt( sal_Int32 columnIndex, sal_Int32 x )
+{
+ updateValue(columnIndex,SQL_INTEGER,&x);
+}
+
+void SAL_CALL OResultSet::updateLong( sal_Int32 /*columnIndex*/, sal_Int64 /*x*/ )
+{
+ ::dbtools::throwFunctionNotSupportedSQLException( "XRowUpdate::updateLong", *this );
+}
+
+void SAL_CALL OResultSet::updateFloat( sal_Int32 columnIndex, float x )
+{
+ updateValue(columnIndex,SQL_REAL,&x);
+}
+
+
+void SAL_CALL OResultSet::updateDouble( sal_Int32 columnIndex, double x )
+{
+ updateValue(columnIndex,SQL_DOUBLE,&x);
+}
+
+void SAL_CALL OResultSet::updateString( sal_Int32 columnIndex, const OUString& x )
+{
+ sal_Int32 nType = m_aRow[columnIndex].getTypeKind();
+ SQLSMALLINT nOdbcType = OTools::jdbcTypeToOdbc(nType);
+ m_aRow[columnIndex] = x;
+ m_aRow[columnIndex].setTypeKind(nType); // OJ: otherwise longvarchar will be recognized by fillNeededData
+ m_aRow[columnIndex].setBound(true);
+ updateValue(columnIndex,nOdbcType, &x);
+}
+
+void SAL_CALL OResultSet::updateBytes( sal_Int32 columnIndex, const Sequence< sal_Int8 >& x )
+{
+ sal_Int32 nType = m_aRow[columnIndex].getTypeKind();
+ SQLSMALLINT nOdbcType = OTools::jdbcTypeToOdbc(nType);
+ m_aRow[columnIndex] = x;
+ m_aRow[columnIndex].setTypeKind(nType); // OJ: otherwise longvarbinary will be recognized by fillNeededData
+ m_aRow[columnIndex].setBound(true);
+ updateValue(columnIndex,nOdbcType, &x);
+}
+
+void SAL_CALL OResultSet::updateDate( sal_Int32 columnIndex, const Date& x )
+{
+ DATE_STRUCT aVal = OTools::DateToOdbcDate(x);
+ updateValue(columnIndex,SQL_DATE,&aVal);
+}
+
+
+void SAL_CALL OResultSet::updateTime( sal_Int32 columnIndex, const css::util::Time& x )
+{
+ TIME_STRUCT aVal = OTools::TimeToOdbcTime(x);
+ updateValue(columnIndex,SQL_TIME,&aVal);
+}
+
+
+void SAL_CALL OResultSet::updateTimestamp( sal_Int32 columnIndex, const DateTime& x )
+{
+ TIMESTAMP_STRUCT aVal = OTools::DateTimeToTimestamp(x);
+ updateValue(columnIndex,SQL_TIMESTAMP,&aVal);
+}
+
+
+void SAL_CALL OResultSet::updateBinaryStream( sal_Int32 columnIndex, const Reference< XInputStream >& x, sal_Int32 length )
+{
+ if(!x.is())
+ ::dbtools::throwFunctionSequenceException(*this);
+
+ Sequence<sal_Int8> aSeq;
+ x->readBytes(aSeq,length);
+ updateBytes(columnIndex,aSeq);
+}
+
+void SAL_CALL OResultSet::updateCharacterStream( sal_Int32 columnIndex, const Reference< XInputStream >& x, sal_Int32 length )
+{
+ updateBinaryStream(columnIndex,x,length);
+}
+
+void SAL_CALL OResultSet::refreshRow( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+
+ // SQLRETURN nRet = N3SQLSetPos(m_aStatementHandle,1,SQL_REFRESH,SQL_LOCK_NO_CHANGE);
+ m_nCurrentFetchState = N3SQLFetchScroll(m_aStatementHandle,SQL_FETCH_RELATIVE,0);
+ OTools::ThrowException(m_pStatement->getOwnConnection(),m_nCurrentFetchState,m_aStatementHandle,SQL_HANDLE_STMT,*this);
+}
+
+void SAL_CALL OResultSet::updateObject( sal_Int32 columnIndex, const Any& x )
+{
+ if (!::dbtools::implUpdateObject(this, columnIndex, x))
+ throw SQLException();
+}
+
+
+void SAL_CALL OResultSet::updateNumericObject( sal_Int32 columnIndex, const Any& x, sal_Int32 /*scale*/ )
+{
+ if (!::dbtools::implUpdateObject(this, columnIndex, x))
+ throw SQLException();
+}
+
+// XRowLocate
+Any SAL_CALL OResultSet::getBookmark( )
+{
+ fillColumn(0);
+ if(m_aRow[0].isNull())
+ throw SQLException();
+ return m_aRow[0].makeAny();
+}
+Sequence<sal_Int8> OResultSet::impl_getBookmark( )
+{
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ TBookmarkPosMap::const_iterator aFind = std::find_if(m_aPosToBookmarks.begin(),m_aPosToBookmarks.end(),
+ [this] (const TBookmarkPosMap::value_type& bookmarkPos) {
+ return bookmarkPos.second == m_nRowPos;
+ });
+
+ if ( aFind == m_aPosToBookmarks.end() )
+ {
+ if ( m_nUseBookmarks == ODBC_SQL_NOT_DEFINED )
+ {
+ m_nUseBookmarks = getStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_USE_BOOKMARKS);
+ }
+ if(m_nUseBookmarks == SQL_UB_OFF)
+ throw SQLException();
+
+ Sequence<sal_Int8> bookmark = OTools::getBytesValue(m_pStatement->getOwnConnection(),m_aStatementHandle,0,SQL_C_VARBOOKMARK,m_bWasNull,**this);
+ m_aPosToBookmarks[bookmark] = m_nRowPos;
+ OSL_ENSURE(bookmark.hasElements(),"Invalid bookmark from length 0!");
+ return bookmark;
+ }
+ else
+ {
+ return aFind->first;
+ }
+}
+
+sal_Bool SAL_CALL OResultSet::moveToBookmark( const Any& bookmark )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ invalidateCache();
+ Sequence<sal_Int8> aBookmark;
+ bookmark >>= aBookmark;
+ OSL_ENSURE(aBookmark.hasElements(),"Invalid bookmark from length 0!");
+ if(aBookmark.hasElements())
+ {
+ SQLRETURN nReturn = setStmtOption<SQLLEN*, SQL_IS_POINTER>(SQL_ATTR_FETCH_BOOKMARK_PTR, reinterpret_cast<SQLLEN*>(aBookmark.getArray()));
+
+ if ( SQL_INVALID_HANDLE != nReturn && SQL_ERROR != nReturn )
+ {
+ m_nCurrentFetchState = N3SQLFetchScroll(m_aStatementHandle,SQL_FETCH_BOOKMARK,0);
+ OTools::ThrowException(m_pStatement->getOwnConnection(),m_nCurrentFetchState,m_aStatementHandle,SQL_HANDLE_STMT,*this);
+ TBookmarkPosMap::const_iterator aFind = m_aPosToBookmarks.find(aBookmark);
+ if(aFind != m_aPosToBookmarks.end())
+ m_nRowPos = aFind->second;
+ else
+ m_nRowPos = -1;
+ return m_nCurrentFetchState == SQL_SUCCESS || m_nCurrentFetchState == SQL_SUCCESS_WITH_INFO;
+ }
+ }
+ return false;
+}
+
+sal_Bool SAL_CALL OResultSet::moveRelativeToBookmark( const Any& bookmark, sal_Int32 rows )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+
+ invalidateCache();
+ Sequence<sal_Int8> aBookmark;
+ bookmark >>= aBookmark;
+ setStmtOption<SQLLEN*, SQL_IS_POINTER>(SQL_ATTR_FETCH_BOOKMARK_PTR, reinterpret_cast<SQLLEN*>(aBookmark.getArray()));
+
+ m_nCurrentFetchState = N3SQLFetchScroll(m_aStatementHandle,SQL_FETCH_BOOKMARK,rows);
+ OTools::ThrowException(m_pStatement->getOwnConnection(),m_nCurrentFetchState,m_aStatementHandle,SQL_HANDLE_STMT,*this);
+ return m_nCurrentFetchState == SQL_SUCCESS || m_nCurrentFetchState == SQL_SUCCESS_WITH_INFO;
+}
+
+sal_Int32 SAL_CALL OResultSet::compareBookmarks( const Any& lhs, const Any& rhs )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ return (lhs == rhs) ? CompareBookmark::EQUAL : CompareBookmark::NOT_EQUAL;
+}
+
+sal_Bool SAL_CALL OResultSet::hasOrderedBookmarks( )
+{
+ return false;
+}
+
+sal_Int32 SAL_CALL OResultSet::hashBookmark( const Any& /*bookmark*/ )
+{
+ ::dbtools::throwFunctionNotSupportedSQLException( "XRowLocate::hashBookmark", *this );
+ return 0;
+}
+
+// XDeleteRows
+Sequence< sal_Int32 > SAL_CALL OResultSet::deleteRows( const Sequence< Any >& rows )
+{
+ Sequence< sal_Int32 > aRet(rows.getLength());
+ sal_Int32 *pRet = aRet.getArray();
+
+ const Any *pBegin = rows.getConstArray();
+ const Any *pEnd = pBegin + rows.getLength();
+
+ for(;pBegin != pEnd;++pBegin,++pRet)
+ {
+ try
+ {
+ if(moveToBookmark(*pBegin))
+ {
+ deleteRow();
+ *pRet = 1;
+ }
+ }
+ catch(const SQLException&)
+ {
+ *pRet = 0;
+ }
+ }
+ return aRet;
+}
+
+template < typename T, SQLINTEGER BufferLength > T OResultSet::getStmtOption (SQLINTEGER fOption) const
+{
+ T result (0);
+ OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!");
+ N3SQLGetStmtAttr(m_aStatementHandle, fOption, &result, BufferLength, nullptr);
+ return result;
+}
+template < typename T, SQLINTEGER BufferLength > SQLRETURN OResultSet::setStmtOption (SQLINTEGER fOption, T value) const
+{
+ OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!");
+ SQLPOINTER sv = reinterpret_cast<SQLPOINTER>(value);
+ return N3SQLSetStmtAttr(m_aStatementHandle, fOption, sv, BufferLength);
+}
+
+sal_Int32 OResultSet::getResultSetConcurrency() const
+{
+ sal_uInt32 nValue = getStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_CONCURRENCY);
+ if(SQL_CONCUR_READ_ONLY == nValue)
+ nValue = ResultSetConcurrency::READ_ONLY;
+ else
+ nValue = ResultSetConcurrency::UPDATABLE;
+
+ return nValue;
+}
+
+sal_Int32 OResultSet::getResultSetType() const
+{
+ sal_uInt32 nValue = getStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_CURSOR_SENSITIVITY);
+ if(SQL_SENSITIVE == nValue)
+ nValue = ResultSetType::SCROLL_SENSITIVE;
+ else if(SQL_INSENSITIVE == nValue)
+ nValue = ResultSetType::SCROLL_INSENSITIVE;
+ else
+ {
+ SQLULEN nCurType = getStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_CURSOR_TYPE);
+ if(SQL_CURSOR_KEYSET_DRIVEN == nCurType)
+ nValue = ResultSetType::SCROLL_SENSITIVE;
+ else if(SQL_CURSOR_STATIC == nCurType)
+ nValue = ResultSetType::SCROLL_INSENSITIVE;
+ else if(SQL_CURSOR_FORWARD_ONLY == nCurType)
+ nValue = ResultSetType::FORWARD_ONLY;
+ else if(SQL_CURSOR_DYNAMIC == nCurType)
+ nValue = ResultSetType::SCROLL_SENSITIVE;
+ }
+ return nValue;
+}
+
+sal_Int32 OResultSet::getFetchSize() const
+{
+ return getStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_ROW_ARRAY_SIZE);
+}
+
+OUString OResultSet::getCursorName() const
+{
+ SQLCHAR pName[258];
+ SQLSMALLINT nRealLen = 0;
+ N3SQLGetCursorName(m_aStatementHandle,pName,256,&nRealLen);
+ return OUString::createFromAscii(reinterpret_cast<char*>(pName));
+}
+
+bool OResultSet::isBookmarkable() const
+{
+ if(!m_aConnectionHandle)
+ return false;
+
+ const SQLULEN nCursorType = getStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_CURSOR_TYPE);
+
+ sal_Int32 nAttr = 0;
+ try
+ {
+ switch(nCursorType)
+ {
+ case SQL_CURSOR_FORWARD_ONLY:
+ return false;
+ case SQL_CURSOR_STATIC:
+ OTools::GetInfo(m_pStatement->getOwnConnection(),m_aConnectionHandle,SQL_STATIC_CURSOR_ATTRIBUTES1,nAttr,nullptr);
+ break;
+ case SQL_CURSOR_KEYSET_DRIVEN:
+ OTools::GetInfo(m_pStatement->getOwnConnection(),m_aConnectionHandle,SQL_KEYSET_CURSOR_ATTRIBUTES1,nAttr,nullptr);
+ break;
+ case SQL_CURSOR_DYNAMIC:
+ OTools::GetInfo(m_pStatement->getOwnConnection(),m_aConnectionHandle,SQL_DYNAMIC_CURSOR_ATTRIBUTES1,nAttr,nullptr);
+ break;
+ }
+ }
+ catch(const Exception&)
+ {
+ return false;
+ }
+
+ if ( m_nUseBookmarks == ODBC_SQL_NOT_DEFINED )
+ {
+ m_nUseBookmarks = getStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_USE_BOOKMARKS);
+ }
+
+ return (m_nUseBookmarks != SQL_UB_OFF) && (nAttr & SQL_CA1_BOOKMARK) == SQL_CA1_BOOKMARK;
+}
+
+void OResultSet::setFetchDirection(sal_Int32 _par0)
+{
+ ::dbtools::throwFunctionNotSupportedSQLException( "setFetchDirection", *this );
+
+ OSL_ENSURE(_par0>0,"Illegal fetch direction!");
+ if ( _par0 > 0 )
+ {
+ setStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_CURSOR_TYPE, _par0);
+ }
+}
+
+void OResultSet::setFetchSize(sal_Int32 _par0)
+{
+ OSL_ENSURE(_par0>0,"Illegal fetch size!");
+ if ( _par0 != 1 )
+ {
+ throw css::beans::PropertyVetoException("SDBC/ODBC layer not prepared for fetchSize > 1", *this);
+ }
+ setStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_ROW_ARRAY_SIZE, _par0);
+ m_pRowStatusArray.reset( new SQLUSMALLINT[_par0] );
+ setStmtOption<SQLUSMALLINT*, SQL_IS_POINTER>(SQL_ATTR_ROW_STATUS_PTR, m_pRowStatusArray.get());
+}
+
+IPropertyArrayHelper* OResultSet::createArrayHelper( ) const
+{
+ return new OPropertyArrayHelper
+ {
+ {
+ {
+ ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_CURSORNAME),
+ PROPERTY_ID_CURSORNAME,
+ cppu::UnoType<OUString>::get(),
+ PropertyAttribute::READONLY
+ },
+ {
+ ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHDIRECTION),
+ PROPERTY_ID_FETCHDIRECTION,
+ cppu::UnoType<sal_Int32>::get(),
+ 0
+ },
+ {
+ ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHSIZE),
+ PROPERTY_ID_FETCHSIZE,
+ cppu::UnoType<sal_Int32>::get(),
+ 0
+ },
+ {
+ ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISBOOKMARKABLE),
+ PROPERTY_ID_ISBOOKMARKABLE,
+ cppu::UnoType<bool>::get(),
+ PropertyAttribute::READONLY
+ },
+ {
+ ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETCONCURRENCY),
+ PROPERTY_ID_RESULTSETCONCURRENCY,
+ cppu::UnoType<sal_Int32>::get(),
+ PropertyAttribute::READONLY
+ },
+ {
+ ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETTYPE),
+ PROPERTY_ID_RESULTSETTYPE,
+ cppu::UnoType<sal_Int32>::get(),
+ PropertyAttribute::READONLY
+ }
+ }
+ };
+}
+
+IPropertyArrayHelper & OResultSet::getInfoHelper()
+{
+ return *getArrayHelper();
+}
+
+sal_Bool OResultSet::convertFastPropertyValue(
+ Any & rConvertedValue,
+ Any & rOldValue,
+ sal_Int32 nHandle,
+ const Any& rValue )
+{
+ switch(nHandle)
+ {
+ case PROPERTY_ID_ISBOOKMARKABLE:
+ case PROPERTY_ID_CURSORNAME:
+ case PROPERTY_ID_RESULTSETCONCURRENCY:
+ case PROPERTY_ID_RESULTSETTYPE:
+ throw css::lang::IllegalArgumentException();
+ case PROPERTY_ID_FETCHDIRECTION:
+ return ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, getFetchDirection());
+ case PROPERTY_ID_FETCHSIZE:
+ return ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, getFetchSize());
+ default:
+ ;
+ }
+ return false;
+}
+
+void OResultSet::setFastPropertyValue_NoBroadcast(
+ sal_Int32 nHandle,
+ const Any& rValue
+ )
+{
+ switch(nHandle)
+ {
+ case PROPERTY_ID_ISBOOKMARKABLE:
+ case PROPERTY_ID_CURSORNAME:
+ case PROPERTY_ID_RESULTSETCONCURRENCY:
+ case PROPERTY_ID_RESULTSETTYPE:
+ throw Exception("cannot set prop " + OUString::number(nHandle), nullptr);
+ case PROPERTY_ID_FETCHDIRECTION:
+ setFetchDirection(getINT32(rValue));
+ break;
+ case PROPERTY_ID_FETCHSIZE:
+ setFetchSize(getINT32(rValue));
+ break;
+ default:
+ ;
+ }
+}
+
+void OResultSet::getFastPropertyValue(
+ Any& rValue,
+ sal_Int32 nHandle
+ ) const
+{
+ switch(nHandle)
+ {
+ case PROPERTY_ID_ISBOOKMARKABLE:
+ rValue <<= isBookmarkable();
+ break;
+ case PROPERTY_ID_CURSORNAME:
+ rValue <<= getCursorName();
+ break;
+ case PROPERTY_ID_RESULTSETCONCURRENCY:
+ rValue <<= getResultSetConcurrency();
+ break;
+ case PROPERTY_ID_RESULTSETTYPE:
+ rValue <<= getResultSetType();
+ break;
+ case PROPERTY_ID_FETCHDIRECTION:
+ rValue <<= getFetchDirection();
+ break;
+ case PROPERTY_ID_FETCHSIZE:
+ rValue <<= getFetchSize();
+ break;
+ }
+}
+
+void OResultSet::fillColumn(const sal_Int32 _nColumn)
+{
+ ensureCacheForColumn(_nColumn);
+
+ if (m_aRow[_nColumn].isBound())
+ return;
+
+ sal_Int32 curCol;
+ if(m_bFetchDataInOrder)
+ {
+ // m_aRow necessarily has a prefix of bound values, then all unbound values
+ // EXCEPT for column 0
+ // so use binary search to find the earliest unbound value before or at _nColumn
+ sal_Int32 lower=0;
+ sal_Int32 upper=_nColumn;
+
+ while (lower < upper)
+ {
+ const sal_Int32 middle=(upper-lower)/2 + lower;
+ if(m_aRow[middle].isBound())
+ {
+ lower=middle+1;
+ }
+ else
+ {
+ upper=middle;
+ }
+ }
+
+ curCol = upper;
+ }
+ else
+ {
+ curCol = _nColumn;
+ }
+
+ TDataRow::iterator pColumn = m_aRow.begin() + curCol;
+ const TDataRow::const_iterator pColumnEnd = m_aRow.begin() + _nColumn + 1;
+
+ if(curCol==0)
+ {
+ try
+ {
+ *pColumn=impl_getBookmark();
+ }
+ catch (SQLException &)
+ {
+ pColumn->setNull();
+ }
+ pColumn->setBound(true);
+ ++curCol;
+ ++pColumn;
+ }
+
+ for (; pColumn != pColumnEnd; ++curCol, ++pColumn)
+ {
+ const sal_Int32 nType = pColumn->getTypeKind();
+ switch (nType)
+ {
+ case DataType::CHAR:
+ case DataType::VARCHAR:
+ case DataType::DECIMAL:
+ case DataType::NUMERIC:
+ case DataType::LONGVARCHAR:
+ case DataType::CLOB:
+ *pColumn=impl_getString(curCol);
+ break;
+ case DataType::FLOAT:
+ *pColumn = impl_getValue<float>(curCol, SQL_C_FLOAT);
+ break;
+ case DataType::REAL:
+ case DataType::DOUBLE:
+ *pColumn = impl_getValue<double>(curCol, SQL_C_DOUBLE);
+ break;
+ case DataType::BINARY:
+ case DataType::VARBINARY:
+ case DataType::LONGVARBINARY:
+ case DataType::BLOB:
+ *pColumn = impl_getBytes(curCol);
+ break;
+ case DataType::DATE:
+ *pColumn = impl_getDate(curCol);
+ break;
+ case DataType::TIME:
+ *pColumn = impl_getTime(curCol);
+ break;
+ case DataType::TIMESTAMP:
+ *pColumn = impl_getTimestamp(curCol);
+ break;
+ case DataType::BIT:
+ *pColumn = impl_getBoolean(curCol);
+ break;
+ case DataType::TINYINT:
+ *pColumn = impl_getValue<sal_Int8>(curCol, SQL_C_TINYINT);
+ break;
+ case DataType::SMALLINT:
+ *pColumn = impl_getValue<sal_Int16>(curCol, SQL_C_SHORT);
+ break;
+ case DataType::INTEGER:
+ *pColumn = impl_getValue<sal_Int32>(curCol, SQL_C_LONG);
+ break;
+ case DataType::BIGINT:
+ *pColumn = impl_getLong(curCol);
+ break;
+ default:
+ SAL_WARN( "connectivity.odbc","Unknown DataType");
+ }
+
+ if ( m_bWasNull )
+ pColumn->setNull();
+ pColumn->setBound(true);
+ if(nType != pColumn->getTypeKind())
+ {
+ pColumn->setTypeKind(nType);
+ }
+ }
+}
+
+void SAL_CALL OResultSet::acquire() noexcept
+{
+ OResultSet_BASE::acquire();
+}
+
+void SAL_CALL OResultSet::release() noexcept
+{
+ OResultSet_BASE::release();
+}
+
+css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL OResultSet::getPropertySetInfo( )
+{
+ return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper());
+}
+
+bool OResultSet::move(IResultSetHelper::Movement _eCursorPosition, sal_Int32 _nOffset, bool /*_bRetrieveData*/)
+{
+ SQLSMALLINT nFetchOrientation = SQL_FETCH_NEXT;
+ switch(_eCursorPosition)
+ {
+ case IResultSetHelper::NEXT:
+ nFetchOrientation = SQL_FETCH_NEXT;
+ break;
+ case IResultSetHelper::PRIOR:
+ nFetchOrientation = SQL_FETCH_PRIOR;
+ break;
+ case IResultSetHelper::FIRST:
+ nFetchOrientation = SQL_FETCH_FIRST;
+ break;
+ case IResultSetHelper::LAST:
+ nFetchOrientation = SQL_FETCH_LAST;
+ break;
+ case IResultSetHelper::RELATIVE1:
+ nFetchOrientation = SQL_FETCH_RELATIVE;
+ break;
+ case IResultSetHelper::ABSOLUTE1:
+ nFetchOrientation = SQL_FETCH_ABSOLUTE;
+ break;
+ case IResultSetHelper::BOOKMARK: // special case here because we are only called with position numbers
+ {
+ TBookmarkPosMap::const_iterator aIter = std::find_if(m_aPosToBookmarks.begin(), m_aPosToBookmarks.end(),
+ [&_nOffset](const TBookmarkPosMap::value_type& rEntry) { return rEntry.second == _nOffset; });
+ if (aIter != m_aPosToBookmarks.end())
+ return moveToBookmark(Any(aIter->first));
+ SAL_WARN( "connectivity.odbc", "Bookmark not found!");
+ }
+ return false;
+ }
+
+ m_bEOF = false;
+ invalidateCache();
+
+ SQLRETURN nOldFetchStatus = m_nCurrentFetchState;
+ // TODO FIXME: both of these will misbehave for
+ // _eCursorPosition == IResultSetHelper::NEXT/PREVIOUS
+ // when fetchSize > 1
+ if ( !m_bUseFetchScroll && _eCursorPosition == IResultSetHelper::NEXT )
+ m_nCurrentFetchState = N3SQLFetch(m_aStatementHandle);
+ else
+ m_nCurrentFetchState = N3SQLFetchScroll(m_aStatementHandle,nFetchOrientation,_nOffset);
+
+ SAL_INFO(
+ "connectivity.odbc",
+ "move(" << nFetchOrientation << "," << _nOffset << "), FetchState = "
+ << m_nCurrentFetchState);
+ OTools::ThrowException(m_pStatement->getOwnConnection(),m_nCurrentFetchState,m_aStatementHandle,SQL_HANDLE_STMT,*this);
+
+ const bool bSuccess = m_nCurrentFetchState == SQL_SUCCESS || m_nCurrentFetchState == SQL_SUCCESS_WITH_INFO;
+ if ( bSuccess )
+ {
+ switch(_eCursorPosition)
+ {
+ case IResultSetHelper::NEXT:
+ ++m_nRowPos;
+ break;
+ case IResultSetHelper::PRIOR:
+ --m_nRowPos;
+ break;
+ case IResultSetHelper::FIRST:
+ m_nRowPos = 1;
+ break;
+ case IResultSetHelper::LAST:
+ m_bEOF = true;
+ break;
+ case IResultSetHelper::RELATIVE1:
+ m_nRowPos += _nOffset;
+ break;
+ case IResultSetHelper::ABSOLUTE1:
+ case IResultSetHelper::BOOKMARK: // special case here because we are only called with position numbers
+ m_nRowPos = _nOffset;
+ break;
+ } // switch(_eCursorPosition)
+ if ( m_nUseBookmarks == ODBC_SQL_NOT_DEFINED )
+ {
+ m_nUseBookmarks = getStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_USE_BOOKMARKS);
+ }
+ if ( m_nUseBookmarks == SQL_UB_OFF )
+ {
+ m_aRow[0].setNull();
+ }
+ else
+ {
+ ensureCacheForColumn(0);
+ Sequence<sal_Int8> bookmark = OTools::getBytesValue(m_pStatement->getOwnConnection(),m_aStatementHandle,0,SQL_C_VARBOOKMARK,m_bWasNull,**this);
+ m_aPosToBookmarks[bookmark] = m_nRowPos;
+ OSL_ENSURE(bookmark.hasElements(),"Invalid bookmark from length 0!");
+ m_aRow[0] = bookmark;
+ }
+ m_aRow[0].setBound(true);
+ }
+ else if ( IResultSetHelper::PRIOR == _eCursorPosition && m_nCurrentFetchState == SQL_NO_DATA )
+ // we went beforeFirst
+ m_nRowPos = 0;
+ else if(IResultSetHelper::NEXT == _eCursorPosition && m_nCurrentFetchState == SQL_NO_DATA && nOldFetchStatus != SQL_NO_DATA)
+ // we went afterLast
+ ++m_nRowPos;
+
+ return bSuccess;
+}
+
+sal_Int32 OResultSet::getDriverPos() const
+{
+ sal_Int32 nValue = getStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_ROW_NUMBER);
+ SAL_INFO(
+ "connectivity.odbc",
+ "RowNum = " << nValue << ", RowPos = " << m_nRowPos);
+ return nValue ? nValue : m_nRowPos;
+}
+
+bool OResultSet::isRowDeleted() const
+{
+ return m_pRowStatusArray[0] == SQL_ROW_DELETED;
+}
+
+bool OResultSet::moveImpl(IResultSetHelper::Movement _eCursorPosition, sal_Int32 _nOffset)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+ return (m_pSkipDeletedSet != nullptr)
+ ? m_pSkipDeletedSet->skipDeleted(_eCursorPosition,_nOffset,true/*_bRetrieveData*/)
+ : move(_eCursorPosition,_nOffset,true/*_bRetrieveData*/);
+}
+
+void OResultSet::fillNeededData(SQLRETURN _nRet)
+{
+ SQLRETURN nRet = _nRet;
+ if( nRet != SQL_NEED_DATA)
+ return;
+
+ void* pColumnIndex = nullptr;
+ nRet = N3SQLParamData(m_aStatementHandle,&pColumnIndex);
+
+ do
+ {
+ if (nRet != SQL_SUCCESS && nRet != SQL_SUCCESS_WITH_INFO && nRet != SQL_NEED_DATA)
+ break;
+
+ sal_IntPtr nColumnIndex ( reinterpret_cast<sal_IntPtr>(pColumnIndex));
+ Sequence< sal_Int8 > aSeq;
+ switch(m_aRow[nColumnIndex].getTypeKind())
+ {
+ case DataType::BINARY:
+ case DataType::VARBINARY:
+ case DataType::LONGVARBINARY:
+ case DataType::BLOB:
+ aSeq = m_aRow[nColumnIndex].getSequence();
+ N3SQLPutData (m_aStatementHandle, aSeq.getArray(), aSeq.getLength());
+ break;
+ case SQL_WLONGVARCHAR:
+ {
+ OUString const & sRet = m_aRow[nColumnIndex].getString();
+ N3SQLPutData (m_aStatementHandle, static_cast<SQLPOINTER>(const_cast<sal_Unicode *>(sRet.getStr())), sizeof(sal_Unicode)*sRet.getLength());
+ break;
+ }
+ case DataType::LONGVARCHAR:
+ case DataType::CLOB:
+ {
+ OUString sRet = m_aRow[nColumnIndex].getString();
+ OString aString(OUStringToOString(sRet,m_nTextEncoding));
+ N3SQLPutData (m_aStatementHandle, static_cast<SQLPOINTER>(const_cast<char *>(aString.getStr())), aString.getLength());
+ break;
+ }
+ default:
+ SAL_WARN( "connectivity.odbc", "Not supported at the moment!");
+ }
+ nRet = N3SQLParamData(m_aStatementHandle,&pColumnIndex);
+ }
+ while (nRet == SQL_NEED_DATA);
+}
+
+SWORD OResultSet::impl_getColumnType_nothrow(sal_Int32 columnIndex)
+{
+ std::map<sal_Int32,SWORD>::const_iterator aFind = m_aODBCColumnTypes.find(columnIndex);
+ if ( aFind == m_aODBCColumnTypes.end() )
+ aFind = m_aODBCColumnTypes.emplace(
+ columnIndex,
+ OResultSetMetaData::getColumnODBCType(m_pStatement->getOwnConnection(),m_aStatementHandle,*this,columnIndex)
+ ).first;
+ return aFind->second;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/odbc/OResultSetMetaData.cxx b/connectivity/source/drivers/odbc/OResultSetMetaData.cxx
new file mode 100644
index 0000000000..21b95c6a7b
--- /dev/null
+++ b/connectivity/source/drivers/odbc/OResultSetMetaData.cxx
@@ -0,0 +1,291 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <odbc/OResultSetMetaData.hxx>
+#include <odbc/OTools.hxx>
+
+using namespace connectivity::odbc;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::sdbc;
+
+
+OResultSetMetaData::~OResultSetMetaData()
+{
+}
+
+OUString OResultSetMetaData::getCharColAttrib(sal_Int32 _column,sal_Int32 ident)
+{
+ sal_Int32 column = _column;
+ if(_column <static_cast<sal_Int32>(m_vMapping.size())) // use mapping
+ column = m_vMapping[_column];
+
+ SQLSMALLINT BUFFER_LEN = 128;
+ std::unique_ptr<char[]> pName(new char[BUFFER_LEN+1]);
+ SQLSMALLINT nRealLen=0;
+ SQLRETURN nRet = N3SQLColAttribute(m_aStatementHandle,
+ static_cast<SQLUSMALLINT>(column),
+ static_cast<SQLUSMALLINT>(ident),
+ static_cast<SQLPOINTER>(pName.get()),
+ BUFFER_LEN,
+ &nRealLen,
+ nullptr
+ );
+ OUString sValue;
+ if ( nRet == SQL_SUCCESS )
+ {
+ if ( nRealLen < 0 )
+ nRealLen = BUFFER_LEN;
+ sValue = OUString(pName.get(),nRealLen,m_pConnection->getTextEncoding());
+ }
+ pName.reset();
+ OTools::ThrowException(m_pConnection,nRet,m_aStatementHandle,SQL_HANDLE_STMT,*this);
+ if(nRealLen > BUFFER_LEN)
+ {
+ pName.reset(new char[nRealLen+1]);
+ nRet = N3SQLColAttribute(m_aStatementHandle,
+ static_cast<SQLUSMALLINT>(column),
+ static_cast<SQLUSMALLINT>(ident),
+ static_cast<SQLPOINTER>(pName.get()),
+ nRealLen,
+ &nRealLen,
+ nullptr
+ );
+ if ( nRet == SQL_SUCCESS && nRealLen > 0)
+ sValue = OUString(pName.get(),nRealLen,m_pConnection->getTextEncoding());
+ OTools::ThrowException(m_pConnection,nRet,m_aStatementHandle,SQL_HANDLE_STMT,*this);
+ }
+
+ return sValue;
+}
+
+SQLLEN OResultSetMetaData::getNumColAttrib(OConnection const * _pConnection
+ ,SQLHANDLE _aStatementHandle
+ ,const css::uno::Reference< css::uno::XInterface >& _xInterface
+ ,sal_Int32 _column
+ ,sal_Int32 _ident)
+{
+ SQLLEN nValue=0;
+ OTools::ThrowException(_pConnection,(*reinterpret_cast<T3SQLColAttribute>(_pConnection->getOdbcFunction(ODBC3SQLFunctionId::ColAttribute)))(_aStatementHandle,
+ static_cast<SQLUSMALLINT>(_column),
+ static_cast<SQLUSMALLINT>(_ident),
+ nullptr,
+ 0,
+ nullptr,
+ &nValue),_aStatementHandle,SQL_HANDLE_STMT,_xInterface);
+ return nValue;
+}
+
+sal_Int32 OResultSetMetaData::getNumColAttrib(sal_Int32 _column,sal_Int32 ident)
+{
+ sal_Int32 column = _column;
+ if(_column < static_cast<sal_Int32>(m_vMapping.size())) // use mapping
+ column = m_vMapping[_column];
+
+ return getNumColAttrib(m_pConnection,m_aStatementHandle,*this,column,ident);
+}
+
+sal_Int32 SAL_CALL OResultSetMetaData::getColumnDisplaySize( sal_Int32 column )
+{
+ return getNumColAttrib(column,SQL_DESC_DISPLAY_SIZE);
+}
+
+SQLSMALLINT OResultSetMetaData::getColumnODBCType(OConnection const * _pConnection
+ ,SQLHANDLE _aStatementHandle
+ ,const css::uno::Reference< css::uno::XInterface >& _xInterface
+ ,sal_Int32 column)
+{
+ SQLSMALLINT nType = 0;
+ try
+ {
+ nType = static_cast<SQLSMALLINT>(getNumColAttrib(_pConnection,_aStatementHandle,_xInterface,column,SQL_DESC_CONCISE_TYPE));
+ if(nType == SQL_UNKNOWN_TYPE)
+ nType = static_cast<SQLSMALLINT>(getNumColAttrib(_pConnection,_aStatementHandle,_xInterface,column, SQL_DESC_TYPE));
+ }
+ catch(SQLException& ) // in this case we have an odbc 2.0 driver
+ {
+ nType = static_cast<SQLSMALLINT>(getNumColAttrib(_pConnection,_aStatementHandle,_xInterface,column,SQL_DESC_CONCISE_TYPE ));
+ }
+
+ return nType;
+}
+
+sal_Int32 SAL_CALL OResultSetMetaData::getColumnType( sal_Int32 column )
+{
+ std::map<sal_Int32,sal_Int32>::iterator aFind = m_aColumnTypes.find(column);
+ if ( aFind == m_aColumnTypes.end() )
+ {
+ sal_Int32 nType = 0;
+ if(!m_bUseODBC2Types)
+ {
+ try
+ {
+ nType = getNumColAttrib(column,SQL_DESC_CONCISE_TYPE);
+ if(nType == SQL_UNKNOWN_TYPE)
+ nType = getNumColAttrib(column, SQL_DESC_TYPE);
+ nType = OTools::MapOdbcType2Jdbc(nType);
+ }
+ catch(SQLException& ) // in this case we have an odbc 2.0 driver
+ {
+ m_bUseODBC2Types = true;
+ nType = OTools::MapOdbcType2Jdbc(getNumColAttrib(column,SQL_DESC_CONCISE_TYPE ));
+ }
+ }
+ else
+ nType = OTools::MapOdbcType2Jdbc(getNumColAttrib(column,SQL_DESC_CONCISE_TYPE ));
+ aFind = m_aColumnTypes.emplace(column,nType).first;
+ }
+
+
+ return aFind->second;
+}
+
+
+sal_Int32 SAL_CALL OResultSetMetaData::getColumnCount( )
+{
+ if(m_nColCount != -1)
+ return m_nColCount;
+ sal_Int16 nNumResultCols=0;
+ OTools::ThrowException(m_pConnection,N3SQLNumResultCols(m_aStatementHandle,&nNumResultCols),m_aStatementHandle,SQL_HANDLE_STMT,*this);
+ m_nColCount = nNumResultCols;
+ return m_nColCount;
+}
+
+
+sal_Bool SAL_CALL OResultSetMetaData::isCaseSensitive( sal_Int32 column )
+{
+ return getNumColAttrib(column,SQL_DESC_CASE_SENSITIVE) == SQL_TRUE;
+}
+
+
+OUString SAL_CALL OResultSetMetaData::getSchemaName( sal_Int32 column )
+{
+ return getCharColAttrib(column,SQL_DESC_SCHEMA_NAME);
+}
+
+
+OUString SAL_CALL OResultSetMetaData::getColumnName( sal_Int32 column )
+{
+ return getCharColAttrib(column,SQL_DESC_NAME);
+}
+
+OUString SAL_CALL OResultSetMetaData::getTableName( sal_Int32 column )
+{
+ return getCharColAttrib(column,SQL_DESC_TABLE_NAME);
+}
+
+OUString SAL_CALL OResultSetMetaData::getCatalogName( sal_Int32 column )
+{
+ return getCharColAttrib(column,SQL_DESC_CATALOG_NAME);
+}
+
+OUString SAL_CALL OResultSetMetaData::getColumnTypeName( sal_Int32 column )
+{
+ return getCharColAttrib(column,SQL_DESC_TYPE_NAME);
+}
+
+OUString SAL_CALL OResultSetMetaData::getColumnLabel( sal_Int32 column )
+{
+ return getCharColAttrib(column,SQL_DESC_LABEL);
+}
+
+OUString SAL_CALL OResultSetMetaData::getColumnServiceName( sal_Int32 /*column*/ )
+{
+ return OUString();
+}
+
+
+sal_Bool SAL_CALL OResultSetMetaData::isCurrency( sal_Int32 column )
+{
+ return getNumColAttrib(column,SQL_DESC_FIXED_PREC_SCALE) == SQL_TRUE;
+}
+
+
+sal_Bool SAL_CALL OResultSetMetaData::isAutoIncrement( sal_Int32 column )
+{
+ return getNumColAttrib(column,SQL_DESC_AUTO_UNIQUE_VALUE) == SQL_TRUE;
+}
+
+
+sal_Bool SAL_CALL OResultSetMetaData::isSigned( sal_Int32 column )
+{
+ return getNumColAttrib(column,SQL_DESC_UNSIGNED) == SQL_FALSE;
+}
+
+sal_Int32 SAL_CALL OResultSetMetaData::getPrecision( sal_Int32 column )
+{
+ sal_Int32 nType = 0;
+ try
+ {
+ nType = getNumColAttrib(column,SQL_DESC_PRECISION);
+ }
+ catch(const SQLException& ) // in this case we have an odbc 2.0 driver
+ {
+ m_bUseODBC2Types = true;
+ nType = getNumColAttrib(column,SQL_COLUMN_PRECISION );
+ }
+ return nType;
+}
+
+sal_Int32 SAL_CALL OResultSetMetaData::getScale( sal_Int32 column )
+{
+ sal_Int32 nType = 0;
+ try
+ {
+ nType = getNumColAttrib(column,SQL_DESC_SCALE);
+ }
+ catch(const SQLException& ) // in this case we have an odbc 2.0 driver
+ {
+ m_bUseODBC2Types = true;
+ nType = getNumColAttrib(column,SQL_COLUMN_SCALE );
+ }
+ return nType;
+}
+
+
+sal_Int32 SAL_CALL OResultSetMetaData::isNullable( sal_Int32 column )
+{
+ return getNumColAttrib(column,SQL_DESC_NULLABLE);
+}
+
+
+sal_Bool SAL_CALL OResultSetMetaData::isSearchable( sal_Int32 column )
+{
+ return getNumColAttrib(column,SQL_DESC_SEARCHABLE) != SQL_PRED_NONE;
+}
+
+
+sal_Bool SAL_CALL OResultSetMetaData::isReadOnly( sal_Int32 column )
+{
+ return getNumColAttrib(column,SQL_DESC_UPDATABLE) == SQL_ATTR_READONLY;
+}
+
+
+sal_Bool SAL_CALL OResultSetMetaData::isDefinitelyWritable( sal_Int32 column )
+{
+ return getNumColAttrib(column,SQL_DESC_UPDATABLE) == SQL_ATTR_WRITE;
+}
+
+sal_Bool SAL_CALL OResultSetMetaData::isWritable( sal_Int32 column )
+{
+ return getNumColAttrib(column,SQL_DESC_UPDATABLE) == SQL_ATTR_WRITE;
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/odbc/OStatement.cxx b/connectivity/source/drivers/odbc/OStatement.cxx
new file mode 100644
index 0000000000..3840e914d1
--- /dev/null
+++ b/connectivity/source/drivers/odbc/OStatement.cxx
@@ -0,0 +1,1140 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <osl/diagnose.h>
+#include <odbc/OStatement.hxx>
+#include <odbc/OConnection.hxx>
+#include <odbc/OResultSet.hxx>
+#include <comphelper/property.hxx>
+#include <odbc/OTools.hxx>
+#include <com/sun/star/sdbc/ResultSetConcurrency.hpp>
+#include <com/sun/star/sdbc/ResultSetType.hpp>
+#include <com/sun/star/sdbc/FetchDirection.hpp>
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <comphelper/sequence.hxx>
+#include <cppuhelper/typeprovider.hxx>
+#include <cppuhelper/queryinterface.hxx>
+#include <comphelper/types.hxx>
+#include <rtl/strbuf.hxx>
+#include <algorithm>
+#include <strings.hrc>
+#include <connectivity/dbexception.hxx>
+
+using namespace ::comphelper;
+
+#define THROW_SQL(x) \
+ OTools::ThrowException(m_pConnection.get(),x,m_aStatementHandle,SQL_HANDLE_STMT,*this)
+
+
+using namespace connectivity::odbc;
+
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::sdbc;
+using namespace com::sun::star::sdbcx;
+using namespace com::sun::star::container;
+using namespace com::sun::star::io;
+using namespace com::sun::star::util;
+
+OStatement_Base::OStatement_Base(OConnection* _pConnection )
+ :OStatement_BASE(m_aMutex)
+ ,OPropertySetHelper(OStatement_BASE::rBHelper)
+ ,m_pConnection(_pConnection)
+ ,m_aStatementHandle(SQL_NULL_HANDLE)
+ ,m_pRowStatusArray(nullptr)
+{
+ osl_atomic_increment( &m_refCount );
+ m_aStatementHandle = m_pConnection->createStatementHandle();
+
+ //setMaxFieldSize(0);
+ // Don't do this. By ODBC spec, "0" is the default for the SQL_ATTR_MAX_LENGTH attribute. We once introduced
+ // this line since a PostgreSQL ODBC driver had a default other than 0. However, current drivers (at least 8.3
+ // and later) have a proper default of 0, so there should be no need anymore.
+ // On the other hand, the NotesSQL driver (IBM's ODBC driver for the Lotus Notes series) wrongly interprets
+ // "0" as "0", whereas the ODBC spec says it should in fact mean "unlimited".
+ // So, removing this line seems to be the best option for now.
+ // If we ever again encounter an ODBC driver which needs this option, then we should introduce a data source
+ // setting for it, instead of unconditionally doing it.
+
+ osl_atomic_decrement( &m_refCount );
+}
+
+OStatement_Base::~OStatement_Base()
+{
+ OSL_ENSURE(!m_aStatementHandle,"Sohould ne null here!");
+}
+
+void OStatement_Base::disposeResultSet()
+{
+ // free the cursor if alive
+ Reference< XComponent > xComp(m_xResultSet.get(), UNO_QUERY);
+ if (xComp.is())
+ xComp->dispose();
+ m_xResultSet.clear();
+}
+
+void SAL_CALL OStatement_Base::disposing()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+
+ disposeResultSet();
+ ::comphelper::disposeComponent(m_xGeneratedStatement);
+
+ OSL_ENSURE(m_aStatementHandle,"OStatement_BASE2::disposing: StatementHandle is null!");
+ if (m_pConnection.is())
+ {
+ m_pConnection->freeStatementHandle(m_aStatementHandle);
+ m_pConnection.clear();
+ }
+ OSL_ENSURE(!m_aStatementHandle,"Sohould ne null here!");
+
+ OStatement_BASE::disposing();
+}
+
+void OStatement_BASE2::disposing()
+{
+ ::osl::MutexGuard aGuard1(m_aMutex);
+ OStatement_Base::disposing();
+}
+
+Any SAL_CALL OStatement_Base::queryInterface( const Type & rType )
+{
+ if ( m_pConnection.is() && !m_pConnection->isAutoRetrievingEnabled() && rType == cppu::UnoType<XGeneratedResultSet>::get())
+ return Any();
+ Any aRet = OStatement_BASE::queryInterface(rType);
+ return aRet.hasValue() ? aRet : OPropertySetHelper::queryInterface(rType);
+}
+
+Sequence< Type > SAL_CALL OStatement_Base::getTypes( )
+{
+ ::cppu::OTypeCollection aTypes( cppu::UnoType<XMultiPropertySet>::get(),
+ cppu::UnoType<XFastPropertySet>::get(),
+ cppu::UnoType<XPropertySet>::get());
+ Sequence< Type > aOldTypes = OStatement_BASE::getTypes();
+ if ( m_pConnection.is() && !m_pConnection->isAutoRetrievingEnabled() )
+ {
+ auto [begin, end] = asNonConstRange(aOldTypes);
+ auto newEnd = std::remove(begin, end,
+ cppu::UnoType<XGeneratedResultSet>::get());
+ aOldTypes.realloc(std::distance(begin, newEnd));
+ }
+
+ return ::comphelper::concatSequences(aTypes.getTypes(),aOldTypes);
+}
+
+Reference< XResultSet > SAL_CALL OStatement_Base::getGeneratedValues( )
+{
+ OSL_ENSURE( m_pConnection.is() && m_pConnection->isAutoRetrievingEnabled(),"Illegal call here. isAutoRetrievingEnabled is false!");
+ Reference< XResultSet > xRes;
+ if ( m_pConnection.is() )
+ {
+ OUString sStmt = m_pConnection->getTransformedGeneratedStatement(m_sSqlStatement);
+ if ( !sStmt.isEmpty() )
+ {
+ ::comphelper::disposeComponent(m_xGeneratedStatement);
+ m_xGeneratedStatement = m_pConnection->createStatement();
+ xRes = m_xGeneratedStatement->executeQuery(sStmt);
+ }
+ }
+ return xRes;
+}
+
+void SAL_CALL OStatement_Base::cancel( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OStatement_BASE::rBHelper.bDisposed);
+
+ OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!");
+ N3SQLCancel(m_aStatementHandle);
+}
+
+
+void SAL_CALL OStatement_Base::close( )
+{
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OStatement_BASE::rBHelper.bDisposed);
+
+ }
+ dispose();
+}
+
+
+void SAL_CALL OStatement::clearBatch( )
+{
+
+}
+
+void OStatement_Base::reset()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OStatement_BASE::rBHelper.bDisposed);
+
+
+ clearWarnings ();
+
+ if (m_xResultSet.get().is())
+ {
+ clearMyResultSet();
+ }
+ if(m_aStatementHandle)
+ {
+ THROW_SQL(N3SQLFreeStmt(m_aStatementHandle, SQL_CLOSE));
+ }
+}
+
+// clearMyResultSet
+// If a ResultSet was created for this Statement, close it
+void OStatement_Base::clearMyResultSet()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OStatement_BASE::rBHelper.bDisposed);
+
+ try
+ {
+ Reference<XCloseable> xCloseable(
+ m_xResultSet.get(), css::uno::UNO_QUERY);
+ if ( xCloseable.is() )
+ xCloseable->close();
+ }
+ catch( const DisposedException& ) { }
+
+ m_xResultSet.clear();
+}
+
+SQLLEN OStatement_Base::getRowCount()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OStatement_BASE::rBHelper.bDisposed);
+
+
+ SQLLEN numRows = 0;
+
+ try {
+ THROW_SQL(N3SQLRowCount(m_aStatementHandle,&numRows));
+ }
+ catch (const SQLException&)
+ {
+ }
+ return numRows;
+}
+
+// lockIfNecessary
+// If the given SQL statement contains a 'FOR UPDATE' clause, change
+// the concurrency to lock so that the row can then be updated. Returns
+// true if the concurrency has been changed
+bool OStatement_Base::lockIfNecessary (const OUString& sql)
+{
+ bool rc = false;
+
+ // First, convert the statement to upper case
+
+ OUString sqlStatement = sql.toAsciiUpperCase ();
+
+ // Now, look for the FOR UPDATE keywords. If there is any extra white
+ // space between the FOR and UPDATE, this will fail.
+
+ sal_Int32 index = sqlStatement.indexOf(" FOR UPDATE");
+
+ // We found it. Change our concurrency level to ensure that the
+ // row can be updated.
+
+ if (index > 0)
+ {
+ OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!");
+ try
+ {
+ THROW_SQL((setStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_CONCURRENCY, SQL_CONCUR_LOCK)));
+ }
+ catch (const SQLWarning& warn)
+ {
+ // Catch any warnings and place on the warning stack
+ setWarning (warn);
+ }
+ rc = true;
+ }
+
+ return rc;
+}
+
+// setWarning
+// Sets the warning
+
+
+void OStatement_Base::setWarning (const SQLWarning &ex)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OStatement_BASE::rBHelper.bDisposed);
+
+
+ m_aLastWarning = ex;
+}
+
+
+// getColumnCount
+// Return the number of columns in the ResultSet
+sal_Int32 OStatement_Base::getColumnCount()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OStatement_BASE::rBHelper.bDisposed);
+
+
+ sal_Int16 numCols = 0;
+ OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!");
+
+ try {
+ THROW_SQL(N3SQLNumResultCols(m_aStatementHandle,&numCols));
+ }
+ catch (const SQLException&)
+ {
+ }
+ return numCols;
+}
+
+
+sal_Bool SAL_CALL OStatement_Base::execute( const OUString& sql )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OStatement_BASE::rBHelper.bDisposed);
+ m_sSqlStatement = sql;
+
+
+ OString aSql(OUStringToOString(sql,getOwnConnection()->getTextEncoding()));
+
+ bool hasResultSet = false;
+
+ // Reset the statement handle and warning
+
+ reset();
+
+ // Check for a 'FOR UPDATE' statement. If present, change
+ // the concurrency to lock
+
+ lockIfNecessary (sql);
+
+ // Call SQLExecDirect
+ OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!");
+
+ try {
+ THROW_SQL(N3SQLExecDirect(m_aStatementHandle, reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(aSql.getStr())), aSql.getLength()));
+ }
+ catch (const SQLWarning&) {
+
+ //TODO: Save pointer to warning and save with ResultSet
+ // object once it is created.
+ }
+
+ // Now determine if there is a result set associated with
+ // the SQL statement that was executed. Get the column
+ // count, and if it is not zero, there is a result set.
+
+ if (getColumnCount () > 0)
+ {
+ hasResultSet = true;
+ }
+
+ return hasResultSet;
+}
+
+// getResultSet
+// getResultSet returns the current result as a ResultSet. It
+// returns NULL if the current result is not a ResultSet.
+
+Reference< XResultSet > OStatement_Base::getResultSet(bool checkCount)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OStatement_BASE::rBHelper.bDisposed);
+
+
+ if (m_xResultSet.get().is()) // if resultset already retrieved,
+ {
+ // throw exception to avoid sequence error
+ ::dbtools::throwFunctionSequenceException(*this);
+ }
+
+ rtl::Reference<OResultSet> pRs;
+ sal_Int32 numCols = 1;
+
+ // If we already know we have result columns, checkCount
+ // is false. This is an optimization to prevent unneeded
+ // calls to getColumnCount
+
+ if (checkCount)
+ numCols = getColumnCount ();
+
+ // Only return a result set if there are result columns
+
+ if (numCols > 0)
+ {
+ OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!");
+ pRs = createResultSet();
+ pRs->construct();
+
+ // Save a copy of our last result set
+ // Changed to save copy at getResultSet.
+ //m_xResultSet = rs;
+ }
+ else
+ clearMyResultSet ();
+
+ return pRs;
+}
+
+// getStmtOption
+// Invoke SQLGetStmtOption with the given option.
+
+
+template < typename T, SQLINTEGER BufferLength > T OStatement_Base::getStmtOption (SQLINTEGER fOption) const
+{
+ T result (0);
+ OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!");
+ N3SQLGetStmtAttr(m_aStatementHandle, fOption, &result, BufferLength, nullptr);
+ return result;
+}
+template < typename T, SQLINTEGER BufferLength > SQLRETURN OStatement_Base::setStmtOption (SQLINTEGER fOption, T value) const
+{
+ OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!");
+ SQLPOINTER sv = reinterpret_cast<SQLPOINTER>(value);
+ return N3SQLSetStmtAttr(m_aStatementHandle, fOption, sv, BufferLength);
+}
+
+
+Reference< XResultSet > SAL_CALL OStatement_Base::executeQuery( const OUString& sql )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OStatement_BASE::rBHelper.bDisposed);
+
+
+ Reference< XResultSet > xRS;
+
+ // Execute the statement. If execute returns true, a result
+ // set exists.
+
+ if (execute (sql))
+ {
+ xRS = getResultSet (false);
+ m_xResultSet = xRS;
+ }
+ else
+ {
+ // No ResultSet was produced. Raise an exception
+ m_pConnection->throwGenericSQLException(STR_NO_RESULTSET,*this);
+ }
+ return xRS;
+}
+
+
+Reference< XConnection > SAL_CALL OStatement_Base::getConnection( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OStatement_BASE::rBHelper.bDisposed);
+
+ return m_pConnection;
+}
+
+
+Any SAL_CALL OStatement::queryInterface( const Type & rType )
+{
+ Any aRet = ::cppu::queryInterface(rType,static_cast< XBatchExecution*> (this));
+ return aRet.hasValue() ? aRet : OStatement_Base::queryInterface(rType);
+}
+
+
+void SAL_CALL OStatement::addBatch( const OUString& sql )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OStatement_BASE::rBHelper.bDisposed);
+
+
+ m_aBatchVector.push_back(sql);
+}
+
+Sequence< sal_Int32 > SAL_CALL OStatement::executeBatch( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OStatement_BASE::rBHelper.bDisposed);
+
+ OStringBuffer aBatchSql;
+ sal_Int32 nLen = m_aBatchVector.size();
+
+ for (auto const& elem : m_aBatchVector)
+ {
+ aBatchSql.append(OUStringToOString(elem,getOwnConnection()->getTextEncoding())
+ + ";");
+ }
+
+ OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!");
+ auto s = aBatchSql.makeStringAndClear();
+ THROW_SQL(N3SQLExecDirect(m_aStatementHandle, reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(s.getStr())), s.getLength()));
+
+ Sequence< sal_Int32 > aRet(nLen);
+ sal_Int32* pArray = aRet.getArray();
+ for(sal_Int32 j=0;j<nLen;++j)
+ {
+ SQLRETURN nError = N3SQLMoreResults(m_aStatementHandle);
+ if(nError == SQL_SUCCESS)
+ {
+ SQLLEN nRowCount=0;
+ N3SQLRowCount(m_aStatementHandle,&nRowCount);
+ pArray[j] = nRowCount;
+ }
+ }
+ return aRet;
+}
+
+
+sal_Int32 SAL_CALL OStatement_Base::executeUpdate( const OUString& sql )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OStatement_BASE::rBHelper.bDisposed);
+
+
+ sal_Int32 numRows = -1;
+
+ // Execute the statement. If execute returns false, a
+ // row count exists.
+
+ if (!execute (sql)) {
+ numRows = getUpdateCount();
+ }
+ else {
+
+ // No update count was produced (a ResultSet was). Raise
+ // an exception
+
+ ::connectivity::SharedResources aResources;
+ const OUString sError( aResources.getResourceString(STR_NO_ROWCOUNT));
+ throw SQLException (sError, *this,OUString(),0,Any());
+ }
+ return numRows;
+
+}
+
+
+Reference< XResultSet > SAL_CALL OStatement_Base::getResultSet( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OStatement_BASE::rBHelper.bDisposed);
+
+
+ m_xResultSet = getResultSet(true);
+ return m_xResultSet;
+}
+
+
+sal_Int32 SAL_CALL OStatement_Base::getUpdateCount( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OStatement_BASE::rBHelper.bDisposed);
+
+
+ sal_Int32 rowCount = -1;
+
+ // Only return a row count for SQL statements that did not
+ // return a result set.
+
+ if (getColumnCount () == 0)
+ rowCount = getRowCount ();
+
+ return rowCount;
+}
+
+
+sal_Bool SAL_CALL OStatement_Base::getMoreResults( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OStatement_BASE::rBHelper.bDisposed);
+
+
+ SQLWarning warning;
+ bool hasResultSet = false;
+
+ // clear previous warnings
+
+ clearWarnings ();
+
+ // Call SQLMoreResults
+ OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!");
+
+ try {
+ hasResultSet = N3SQLMoreResults(m_aStatementHandle) == SQL_SUCCESS;
+ }
+ catch (const SQLWarning &ex) {
+
+ // Save pointer to warning and save with ResultSet
+ // object once it is created.
+
+ warning = ex;
+ }
+
+ // There are more results (it may not be a result set, though)
+
+ if (hasResultSet)
+ {
+
+ // Now determine if there is a result set associated
+ // with the SQL statement that was executed. Get the
+ // column count, and if it is zero, there is not a
+ // result set.
+
+ if (getColumnCount () == 0)
+ hasResultSet = false;
+ }
+
+ // Set the warning for the statement, if one was generated
+
+ setWarning (warning);
+
+ // Return the result set indicator
+
+ return hasResultSet;
+}
+
+
+Any SAL_CALL OStatement_Base::getWarnings( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OStatement_BASE::rBHelper.bDisposed);
+
+
+ return Any(m_aLastWarning);
+}
+
+
+void SAL_CALL OStatement_Base::clearWarnings( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OStatement_BASE::rBHelper.bDisposed);
+
+
+ m_aLastWarning = SQLWarning();
+}
+
+
+sal_Int64 OStatement_Base::getQueryTimeOut() const
+{
+ return getStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_QUERY_TIMEOUT);
+}
+
+sal_Int64 OStatement_Base::getMaxRows() const
+{
+ return getStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_MAX_ROWS);
+}
+
+sal_Int32 OStatement_Base::getResultSetConcurrency() const
+{
+ OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!");
+ SQLULEN nValue (getStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_CONCURRENCY));
+ if(nValue == SQL_CONCUR_READ_ONLY)
+ nValue = ResultSetConcurrency::READ_ONLY;
+ else
+ nValue = ResultSetConcurrency::UPDATABLE;
+ return nValue;
+}
+
+sal_Int32 OStatement_Base::getResultSetType() const
+{
+ OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!");
+ SQLULEN nValue (getStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_CURSOR_TYPE));
+ switch(nValue)
+ {
+ case SQL_CURSOR_FORWARD_ONLY:
+ nValue = ResultSetType::FORWARD_ONLY;
+ break;
+ case SQL_CURSOR_KEYSET_DRIVEN:
+ case SQL_CURSOR_STATIC:
+ nValue = ResultSetType::SCROLL_INSENSITIVE;
+ break;
+ case SQL_CURSOR_DYNAMIC:
+ nValue = ResultSetType::SCROLL_SENSITIVE;
+ break;
+ default:
+ OSL_FAIL("Unknown ODBC Cursor Type");
+ }
+
+ return nValue;
+}
+
+sal_Int32 OStatement_Base::getFetchDirection() const
+{
+ OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!");
+ SQLULEN nValue (getStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_CURSOR_SCROLLABLE));
+ switch(nValue)
+ {
+ case SQL_SCROLLABLE:
+ nValue = FetchDirection::REVERSE;
+ break;
+ default:
+ nValue = FetchDirection::FORWARD;
+ break;
+ }
+
+ return nValue;
+}
+
+sal_Int32 OStatement_Base::getFetchSize() const
+{
+ OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!");
+ return getStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_ROW_ARRAY_SIZE);
+}
+
+sal_Int64 OStatement_Base::getMaxFieldSize() const
+{
+ return getStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_MAX_LENGTH);
+}
+
+OUString OStatement_Base::getCursorName() const
+{
+ OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!");
+ SQLCHAR pName[258];
+ SQLSMALLINT nRealLen = 0;
+ N3SQLGetCursorName(m_aStatementHandle,pName,256,&nRealLen);
+ return OUString::createFromAscii(reinterpret_cast<char*>(pName));
+}
+
+void OStatement_Base::setQueryTimeOut(sal_Int64 seconds)
+{
+ OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!");
+ setStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_QUERY_TIMEOUT,seconds);
+}
+
+void OStatement_Base::setMaxRows(sal_Int64 _par0)
+{
+ OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!");
+ setStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_MAX_ROWS, _par0);
+}
+
+void OStatement_Base::setResultSetConcurrency(sal_Int32 _par0)
+{
+ SQLULEN nSet;
+ if(_par0 == ResultSetConcurrency::READ_ONLY)
+ nSet = SQL_CONCUR_READ_ONLY;
+ else
+ nSet = SQL_CONCUR_VALUES;
+
+ OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!");
+ setStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_CONCURRENCY, nSet);
+}
+
+void OStatement_Base::setResultSetType(sal_Int32 _par0)
+{
+
+ OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!");
+ setStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_ROW_BIND_TYPE, SQL_BIND_BY_COLUMN);
+
+ bool bUseBookmark = isUsingBookmarks();
+ SQLULEN nSet( SQL_UNSPECIFIED );
+ switch(_par0)
+ {
+ case ResultSetType::FORWARD_ONLY:
+ nSet = SQL_UNSPECIFIED;
+ break;
+ case ResultSetType::SCROLL_INSENSITIVE:
+ nSet = SQL_INSENSITIVE;
+ setStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_CURSOR_TYPE, SQL_CURSOR_KEYSET_DRIVEN);
+ break;
+ case ResultSetType::SCROLL_SENSITIVE:
+ if(bUseBookmark)
+ {
+ SQLUINTEGER nCurProp = getCursorProperties(SQL_CURSOR_DYNAMIC,true);
+ if((nCurProp & SQL_CA1_BOOKMARK) != SQL_CA1_BOOKMARK) // check if bookmark for this type isn't supported
+ { // we have to test the next one
+ nCurProp = getCursorProperties(SQL_CURSOR_KEYSET_DRIVEN,true);
+ bool bNotBookmarks = ((nCurProp & SQL_CA1_BOOKMARK) != SQL_CA1_BOOKMARK);
+ nCurProp = getCursorProperties(SQL_CURSOR_KEYSET_DRIVEN,false);
+ nSet = SQL_CURSOR_KEYSET_DRIVEN;
+ if( bNotBookmarks ||
+ ((nCurProp & SQL_CA2_SENSITIVITY_DELETIONS) != SQL_CA2_SENSITIVITY_DELETIONS) ||
+ ((nCurProp & SQL_CA2_SENSITIVITY_ADDITIONS) != SQL_CA2_SENSITIVITY_ADDITIONS))
+ {
+ // bookmarks for keyset isn't supported so reset bookmark setting
+ setUsingBookmarks(false);
+ nSet = SQL_CURSOR_DYNAMIC;
+ }
+ }
+ else
+ nSet = SQL_CURSOR_DYNAMIC;
+ }
+ else
+ nSet = SQL_CURSOR_DYNAMIC;
+ if( setStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_CURSOR_TYPE, nSet) != SQL_SUCCESS )
+ {
+ setStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_CURSOR_TYPE, SQL_CURSOR_KEYSET_DRIVEN);
+ }
+ nSet = SQL_SENSITIVE;
+ break;
+ default:
+ OSL_FAIL( "OStatement_Base::setResultSetType: invalid result set type!" );
+ break;
+ }
+
+
+ setStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_CURSOR_SENSITIVITY, nSet);
+}
+
+void OStatement_Base::setEscapeProcessing( const bool _bEscapeProc )
+{
+ OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!");
+ SQLULEN nEscapeProc( _bEscapeProc ? SQL_NOSCAN_OFF : SQL_NOSCAN_ON );
+ setStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_NOSCAN, nEscapeProc);
+}
+
+
+void OStatement_Base::setFetchDirection(sal_Int32 _par0)
+{
+ OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!");
+ if(_par0 == FetchDirection::FORWARD)
+ {
+ setStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_CURSOR_SCROLLABLE, SQL_NONSCROLLABLE);
+ }
+ else if(_par0 == FetchDirection::REVERSE)
+ {
+ setStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_CURSOR_SCROLLABLE, SQL_SCROLLABLE);
+ }
+}
+
+void OStatement_Base::setFetchSize(sal_Int32 _par0)
+{
+ OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!");
+ OSL_ENSURE(_par0>0,"Illegal fetch size!");
+ if ( _par0 > 0 )
+ {
+ setStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_ROW_ARRAY_SIZE, _par0);
+
+ delete[] m_pRowStatusArray;
+ m_pRowStatusArray = new SQLUSMALLINT[_par0];
+ setStmtOption<SQLUSMALLINT*, SQL_IS_POINTER>(SQL_ATTR_ROW_STATUS_PTR, m_pRowStatusArray);
+ }
+}
+
+void OStatement_Base::setMaxFieldSize(sal_Int64 _par0)
+{
+ OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!");
+ setStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_MAX_LENGTH, _par0);
+}
+
+void OStatement_Base::setCursorName(std::u16string_view _par0)
+{
+ OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!");
+ OString aName(OUStringToOString(_par0,getOwnConnection()->getTextEncoding()));
+ N3SQLSetCursorName(m_aStatementHandle, reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(aName.getStr())), static_cast<SQLSMALLINT>(aName.getLength()));
+}
+
+bool OStatement_Base::isUsingBookmarks() const
+{
+ OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!");
+ return SQL_UB_OFF != getStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_USE_BOOKMARKS);
+}
+
+bool OStatement_Base::getEscapeProcessing() const
+{
+ OSL_ENSURE( m_aStatementHandle, "StatementHandle is null!" );
+ return SQL_NOSCAN_OFF == getStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_USE_BOOKMARKS);
+}
+
+void OStatement_Base::setUsingBookmarks(bool _bUseBookmark)
+{
+ OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!");
+ SQLULEN nValue = _bUseBookmark ? SQL_UB_VARIABLE : SQL_UB_OFF;
+ setStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_USE_BOOKMARKS, nValue);
+}
+
+::cppu::IPropertyArrayHelper* OStatement_Base::createArrayHelper( ) const
+{
+ return new ::cppu::OPropertyArrayHelper
+ {
+ {
+ {
+ ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_CURSORNAME),
+ PROPERTY_ID_CURSORNAME,
+ cppu::UnoType<OUString>::get(),
+ 0
+ },
+ {
+ ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ESCAPEPROCESSING),
+ PROPERTY_ID_ESCAPEPROCESSING,
+ cppu::UnoType<bool>::get(),
+ 0
+ },
+ {
+ ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHDIRECTION),
+ PROPERTY_ID_FETCHDIRECTION,
+ cppu::UnoType<sal_Int32>::get(),
+ 0
+ },
+ {
+ ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHSIZE),
+ PROPERTY_ID_FETCHSIZE,
+ cppu::UnoType<sal_Int32>::get(),
+ 0
+ },
+ {
+ ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_MAXFIELDSIZE),
+ PROPERTY_ID_MAXFIELDSIZE,
+ cppu::UnoType<sal_Int32>::get(),
+ 0
+ },
+ {
+ ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_MAXROWS),
+ PROPERTY_ID_MAXROWS,
+ cppu::UnoType<sal_Int32>::get(),
+ 0
+ },
+ {
+ ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_QUERYTIMEOUT),
+ PROPERTY_ID_QUERYTIMEOUT,
+ cppu::UnoType<sal_Int32>::get(),
+ 0
+ },
+ {
+ ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETCONCURRENCY),
+ PROPERTY_ID_RESULTSETCONCURRENCY,
+ cppu::UnoType<sal_Int32>::get(),
+ 0
+ },
+ {
+ ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETTYPE),
+ PROPERTY_ID_RESULTSETTYPE,
+ cppu::UnoType<sal_Int32>::get(),
+ 0
+ },
+ {
+ ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_USEBOOKMARKS),
+ PROPERTY_ID_USEBOOKMARKS,
+ cppu::UnoType<bool>::get(),
+ 0
+ }
+ }
+ };
+}
+
+
+::cppu::IPropertyArrayHelper & OStatement_Base::getInfoHelper()
+{
+ return *getArrayHelper();
+}
+
+sal_Bool OStatement_Base::convertFastPropertyValue(
+ Any & rConvertedValue,
+ Any & rOldValue,
+ sal_Int32 nHandle,
+ const Any& rValue )
+{
+ bool bConverted = false;
+ try
+ {
+ switch(nHandle)
+ {
+ case PROPERTY_ID_QUERYTIMEOUT:
+ bConverted = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, getQueryTimeOut());
+ break;
+
+ case PROPERTY_ID_MAXFIELDSIZE:
+ bConverted = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, getMaxFieldSize());
+ break;
+
+ case PROPERTY_ID_MAXROWS:
+ bConverted = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, getMaxRows());
+ break;
+
+ case PROPERTY_ID_CURSORNAME:
+ bConverted = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, getCursorName());
+ break;
+
+ case PROPERTY_ID_RESULTSETCONCURRENCY:
+ bConverted = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, getResultSetConcurrency());
+ break;
+
+ case PROPERTY_ID_RESULTSETTYPE:
+ bConverted = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, getResultSetType());
+ break;
+
+ case PROPERTY_ID_FETCHDIRECTION:
+ bConverted = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, getFetchDirection());
+ break;
+
+ case PROPERTY_ID_FETCHSIZE:
+ bConverted = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, getFetchSize());
+ break;
+
+ case PROPERTY_ID_USEBOOKMARKS:
+ bConverted = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, isUsingBookmarks());
+ break;
+
+ case PROPERTY_ID_ESCAPEPROCESSING:
+ bConverted = ::comphelper::tryPropertyValue( rConvertedValue, rOldValue, rValue, getEscapeProcessing() );
+ break;
+
+ }
+ }
+ catch(const SQLException&)
+ {
+ // throw Exception(e.Message,*this);
+ }
+ return bConverted;
+}
+
+void OStatement_Base::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,const Any& rValue)
+{
+ try
+ {
+ switch(nHandle)
+ {
+ case PROPERTY_ID_QUERYTIMEOUT:
+ setQueryTimeOut(comphelper::getINT64(rValue));
+ break;
+ case PROPERTY_ID_MAXFIELDSIZE:
+ setMaxFieldSize(comphelper::getINT64(rValue));
+ break;
+ case PROPERTY_ID_MAXROWS:
+ setMaxRows(comphelper::getINT64(rValue));
+ break;
+ case PROPERTY_ID_CURSORNAME:
+ setCursorName(comphelper::getString(rValue));
+ break;
+ case PROPERTY_ID_RESULTSETCONCURRENCY:
+ setResultSetConcurrency(comphelper::getINT32(rValue));
+ break;
+ case PROPERTY_ID_RESULTSETTYPE:
+ setResultSetType(comphelper::getINT32(rValue));
+ break;
+ case PROPERTY_ID_FETCHDIRECTION:
+ setFetchDirection(comphelper::getINT32(rValue));
+ break;
+ case PROPERTY_ID_FETCHSIZE:
+ setFetchSize(comphelper::getINT32(rValue));
+ break;
+ case PROPERTY_ID_USEBOOKMARKS:
+ setUsingBookmarks(comphelper::getBOOL(rValue));
+ break;
+ case PROPERTY_ID_ESCAPEPROCESSING:
+ setEscapeProcessing( ::comphelper::getBOOL( rValue ) );
+ break;
+ default:
+ OSL_FAIL( "OStatement_Base::setFastPropertyValue_NoBroadcast: what property?" );
+ break;
+ }
+ }
+ catch(const SQLException& )
+ {
+ // throw Exception(e.Message,*this);
+ }
+}
+
+void OStatement_Base::getFastPropertyValue(Any& rValue,sal_Int32 nHandle) const
+{
+ switch(nHandle)
+ {
+ case PROPERTY_ID_QUERYTIMEOUT:
+ rValue <<= getQueryTimeOut();
+ break;
+ case PROPERTY_ID_MAXFIELDSIZE:
+ rValue <<= getMaxFieldSize();
+ break;
+ case PROPERTY_ID_MAXROWS:
+ rValue <<= getMaxRows();
+ break;
+ case PROPERTY_ID_CURSORNAME:
+ rValue <<= getCursorName();
+ break;
+ case PROPERTY_ID_RESULTSETCONCURRENCY:
+ rValue <<= getResultSetConcurrency();
+ break;
+ case PROPERTY_ID_RESULTSETTYPE:
+ rValue <<= getResultSetType();
+ break;
+ case PROPERTY_ID_FETCHDIRECTION:
+ rValue <<= getFetchDirection();
+ break;
+ case PROPERTY_ID_FETCHSIZE:
+ rValue <<= getFetchSize();
+ break;
+ case PROPERTY_ID_USEBOOKMARKS:
+ rValue <<= isUsingBookmarks();
+ break;
+ case PROPERTY_ID_ESCAPEPROCESSING:
+ rValue <<= getEscapeProcessing();
+ break;
+ default:
+ OSL_FAIL( "OStatement_Base::getFastPropertyValue: what property?" );
+ break;
+ }
+}
+
+IMPLEMENT_SERVICE_INFO(OStatement,"com.sun.star.sdbcx.OStatement","com.sun.star.sdbc.Statement");
+
+void SAL_CALL OStatement_Base::acquire() noexcept
+{
+ OStatement_BASE::acquire();
+}
+
+void SAL_CALL OStatement_Base::release() noexcept
+{
+ OStatement_BASE::release();
+}
+
+void SAL_CALL OStatement::acquire() noexcept
+{
+ OStatement_BASE2::acquire();
+}
+
+void SAL_CALL OStatement::release() noexcept
+{
+ OStatement_BASE2::release();
+}
+
+rtl::Reference<OResultSet> OStatement_Base::createResultSet()
+{
+ return new OResultSet(m_aStatementHandle,this);
+}
+
+Reference< css::beans::XPropertySetInfo > SAL_CALL OStatement_Base::getPropertySetInfo( )
+{
+ return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper());
+}
+
+SQLUINTEGER OStatement_Base::getCursorProperties(SQLINTEGER _nCursorType, bool bFirst)
+{
+ SQLUINTEGER nValueLen = 0;
+ try
+ {
+ SQLUSMALLINT nAskFor = SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES2;
+ if(SQL_CURSOR_KEYSET_DRIVEN == _nCursorType)
+ nAskFor = bFirst ? SQL_KEYSET_CURSOR_ATTRIBUTES1 : SQL_KEYSET_CURSOR_ATTRIBUTES2;
+ else if(SQL_CURSOR_STATIC == _nCursorType)
+ nAskFor = bFirst ? SQL_STATIC_CURSOR_ATTRIBUTES1 : SQL_STATIC_CURSOR_ATTRIBUTES2;
+ else if(SQL_CURSOR_FORWARD_ONLY == _nCursorType)
+ nAskFor = bFirst ? SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES1 : SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES2;
+ else if(SQL_CURSOR_DYNAMIC == _nCursorType)
+ nAskFor = bFirst ? SQL_DYNAMIC_CURSOR_ATTRIBUTES1 : SQL_DYNAMIC_CURSOR_ATTRIBUTES2;
+
+
+ OTools::GetInfo(getOwnConnection(),getConnectionHandle(),nAskFor,nValueLen,nullptr);
+ }
+ catch(const Exception&)
+ { // we don't want our result destroy here
+ nValueLen = 0;
+ }
+ return nValueLen;
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/odbc/OTools.cxx b/connectivity/source/drivers/odbc/OTools.cxx
new file mode 100644
index 0000000000..4781415de4
--- /dev/null
+++ b/connectivity/source/drivers/odbc/OTools.cxx
@@ -0,0 +1,797 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <odbc/OTools.hxx>
+#include <odbc/OFunctions.hxx>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <o3tl/safeint.hxx>
+#include <osl/diagnose.h>
+#include <osl/endian.h>
+#include <odbc/OConnection.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <sal/log.hxx>
+
+#include <string.h>
+
+using namespace connectivity::odbc;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::sdbc;
+using namespace com::sun::star::util;
+
+namespace {
+size_t sqlTypeLen ( SQLSMALLINT _nType )
+{
+ switch (_nType)
+ {
+ case SQL_C_SSHORT:
+ case SQL_C_SHORT:
+ return sizeof(SQLSMALLINT);
+ case SQL_C_USHORT:
+ return sizeof(SQLUSMALLINT);
+ case SQL_C_SLONG:
+ case SQL_C_LONG:
+ return sizeof(SQLINTEGER);
+ case SQL_C_ULONG:
+ return sizeof(SQLUINTEGER);
+ case SQL_C_FLOAT:
+ return sizeof(SQLREAL);
+ case SQL_C_DOUBLE:
+ static_assert(sizeof(SQLDOUBLE) == sizeof(SQLFLOAT), "SQLDOUBLE/SQLFLOAT confusion");
+ return sizeof(SQLDOUBLE);
+ case SQL_C_BIT:
+ return sizeof(SQLCHAR);
+ case SQL_C_STINYINT:
+ case SQL_C_TINYINT:
+ return sizeof(SQLSCHAR);
+ case SQL_C_UTINYINT:
+ return sizeof(SQLCHAR);
+ case SQL_C_SBIGINT:
+ return sizeof(SQLBIGINT);
+ case SQL_C_UBIGINT:
+ return sizeof(SQLUBIGINT);
+ /* UnixODBC gives this the same value as SQL_C_UBIGINT
+ case SQL_C_BOOKMARK:
+ return sizeof(BOOKMARK); */
+ case SQL_C_TYPE_DATE:
+ case SQL_C_DATE:
+ return sizeof(SQL_DATE_STRUCT);
+ case SQL_C_TYPE_TIME:
+ case SQL_C_TIME:
+ return sizeof(SQL_TIME_STRUCT);
+ case SQL_C_TYPE_TIMESTAMP:
+ case SQL_C_TIMESTAMP:
+ return sizeof(SQL_TIMESTAMP_STRUCT);
+ case SQL_C_NUMERIC:
+ return sizeof(SQL_NUMERIC_STRUCT);
+ case SQL_C_GUID:
+ return sizeof(SQLGUID);
+ case SQL_C_INTERVAL_YEAR:
+ case SQL_C_INTERVAL_MONTH:
+ case SQL_C_INTERVAL_DAY:
+ case SQL_C_INTERVAL_HOUR:
+ case SQL_C_INTERVAL_MINUTE:
+ case SQL_C_INTERVAL_SECOND:
+ case SQL_C_INTERVAL_YEAR_TO_MONTH:
+ case SQL_C_INTERVAL_DAY_TO_HOUR:
+ case SQL_C_INTERVAL_DAY_TO_MINUTE:
+ case SQL_C_INTERVAL_DAY_TO_SECOND:
+ case SQL_C_INTERVAL_HOUR_TO_MINUTE:
+ case SQL_C_INTERVAL_HOUR_TO_SECOND:
+ case SQL_C_INTERVAL_MINUTE_TO_SECOND:
+ return sizeof(SQL_INTERVAL_STRUCT);
+ // ** Variable-sized datatypes -> cannot predict length
+ case SQL_C_CHAR:
+ case SQL_C_WCHAR:
+ case SQL_C_BINARY:
+ // UnixODBC gives this the same value as SQL_C_BINARY
+ //case SQL_C_VARBOOKMARK:
+ // Unknown datatype -> cannot predict length
+ default:
+ return static_cast<size_t>(-1);
+ }
+}
+
+void appendSQLWCHARs(OUStringBuffer & s, SQLWCHAR const * d, sal_Int32 n)
+{
+ static_assert(
+ sizeof (SQLWCHAR) == sizeof (sal_Unicode) || sizeof (SQLWCHAR) == 4,
+ "bad SQLWCHAR");
+ if (sizeof (SQLWCHAR) == sizeof (sal_Unicode)) {
+ s.append(reinterpret_cast<sal_Unicode const *>(d), n);
+ } else {
+ for (sal_Int32 i = 0; i != n; ++i) {
+ s.appendUtf32(d[i]);
+ }
+ }
+}
+}
+
+
+void OTools::getValue( OConnection const * _pConnection,
+ SQLHANDLE _aStatementHandle,
+ sal_Int32 columnIndex,
+ SQLSMALLINT _nType,
+ bool &_bWasNull,
+ const css::uno::Reference< css::uno::XInterface >& _xInterface,
+ void* _pValue,
+ SQLLEN _nSize)
+{
+ const size_t properSize = sqlTypeLen(_nType);
+ if ( properSize == static_cast<size_t>(-1) )
+ SAL_WARN( "connectivity.drivers", "connectivity::odbc::OTools::getValue: unknown SQL type - cannot check buffer size");
+ else
+ {
+ OSL_ENSURE(static_cast<size_t>(_nSize) == properSize, "connectivity::odbc::OTools::getValue got wrongly sized memory region to write result to");
+ if ( o3tl::make_unsigned(_nSize) > properSize )
+ {
+ SAL_WARN( "connectivity.drivers", "memory region is too big - trying to fudge it");
+ memset(_pValue, 0, _nSize);
+#ifdef OSL_BIGENDIAN
+ // This is skewed in favour of integer types
+ _pValue = static_cast<char*>(_pValue) + _nSize - properSize;
+#endif
+ }
+ }
+ OSL_ENSURE(o3tl::make_unsigned(_nSize) >= properSize, "memory region is too small");
+ SQLLEN pcbValue = SQL_NULL_DATA;
+ OTools::ThrowException(_pConnection,
+ (*reinterpret_cast<T3SQLGetData>(_pConnection->getOdbcFunction(ODBC3SQLFunctionId::GetData)))(_aStatementHandle,
+ static_cast<SQLUSMALLINT>(columnIndex),
+ _nType,
+ _pValue,
+ _nSize,
+ &pcbValue),
+ _aStatementHandle,SQL_HANDLE_STMT,_xInterface,false);
+ _bWasNull = pcbValue == SQL_NULL_DATA;
+}
+
+void OTools::bindValue( OConnection const * _pConnection,
+ SQLHANDLE _aStatementHandle,
+ sal_Int32 columnIndex,
+ SQLSMALLINT _nType,
+ SQLSMALLINT _nMaxLen,
+ const void* _pValue,
+ void* _pData,
+ SQLLEN * const pLen,
+ const css::uno::Reference< css::uno::XInterface >& _xInterface,
+ rtl_TextEncoding _nTextEncoding,
+ bool _bUseOldTimeDate)
+{
+ SQLRETURN nRetcode;
+ SQLSMALLINT fSqlType;
+ SQLSMALLINT fCType;
+
+ OTools::getBindTypes( false,
+ _bUseOldTimeDate,
+ _nType,
+ fCType,
+ fSqlType);
+
+ if (columnIndex != 0 && !_pValue)
+ {
+ *pLen = SQL_NULL_DATA;
+ nRetcode = (*reinterpret_cast<T3SQLBindCol>(_pConnection->getOdbcFunction(ODBC3SQLFunctionId::BindCol)))(_aStatementHandle,
+ static_cast<SQLUSMALLINT>(columnIndex),
+ fCType,
+ _pData,
+ _nMaxLen,
+ pLen
+ );
+ }
+ else
+ {
+ try
+ {
+ switch (_nType)
+ {
+ case SQL_CHAR:
+ case SQL_VARCHAR:
+ {
+ OString aString(OUStringToOString(*static_cast<OUString const *>(_pValue),_nTextEncoding));
+ *pLen = SQL_NTS;
+ *static_cast<OString*>(_pData) = aString;
+
+ // Pointer on Char*
+ _pData = const_cast<char *>(aString.getStr());
+ } break;
+ case SQL_BIGINT:
+ *static_cast<sal_Int64*>(_pData) = *static_cast<sal_Int64 const *>(_pValue);
+ *pLen = sizeof(sal_Int64);
+ break;
+ case SQL_DECIMAL:
+ case SQL_NUMERIC:
+ {
+ OString aString = OString::number(*static_cast<double const *>(_pValue));
+ *pLen = static_cast<SQLSMALLINT>(aString.getLength());
+ *static_cast<OString*>(_pData) = aString;
+ // Pointer on Char*
+ _pData = const_cast<char *>(static_cast<OString*>(_pData)->getStr());
+ } break;
+ case SQL_BIT:
+ case SQL_TINYINT:
+ *static_cast<sal_Int8*>(_pData) = *static_cast<sal_Int8 const *>(_pValue);
+ *pLen = sizeof(sal_Int8);
+ break;
+
+ case SQL_SMALLINT:
+ *static_cast<sal_Int16*>(_pData) = *static_cast<sal_Int16 const *>(_pValue);
+ *pLen = sizeof(sal_Int16);
+ break;
+ case SQL_INTEGER:
+ *static_cast<sal_Int32*>(_pData) = *static_cast<sal_Int32 const *>(_pValue);
+ *pLen = sizeof(sal_Int32);
+ break;
+ case SQL_FLOAT:
+ *static_cast<float*>(_pData) = *static_cast<float const *>(_pValue);
+ *pLen = sizeof(float);
+ break;
+ case SQL_REAL:
+ case SQL_DOUBLE:
+ *static_cast<double*>(_pData) = *static_cast<double const *>(_pValue);
+ *pLen = sizeof(double);
+ break;
+ case SQL_BINARY:
+ case SQL_VARBINARY:
+ {
+ _pData = const_cast<sal_Int8 *>(static_cast<const css::uno::Sequence< sal_Int8 > *>(_pValue)->getConstArray());
+ *pLen = static_cast<const css::uno::Sequence< sal_Int8 > *>(_pValue)->getLength();
+ } break;
+ case SQL_LONGVARBINARY:
+ {
+ /* see https://msdn.microsoft.com/en-us/library/ms716238%28v=vs.85%29.aspx
+ * for an explanation of that apparently weird cast */
+ _pData = reinterpret_cast<void*>(static_cast<uintptr_t>(columnIndex));
+ sal_Int32 nLen = static_cast<const css::uno::Sequence< sal_Int8 > *>(_pValue)->getLength();
+ *pLen = static_cast<SQLLEN>(SQL_LEN_DATA_AT_EXEC(nLen));
+ }
+ break;
+ case SQL_LONGVARCHAR:
+ {
+ /* see https://msdn.microsoft.com/en-us/library/ms716238%28v=vs.85%29.aspx
+ * for an explanation of that apparently weird cast */
+ _pData = reinterpret_cast<void*>(static_cast<uintptr_t>(columnIndex));
+ sal_Int32 nLen = static_cast<OUString const *>(_pValue)->getLength();
+ *pLen = static_cast<SQLLEN>(SQL_LEN_DATA_AT_EXEC(nLen));
+ } break;
+ case SQL_DATE:
+ *pLen = sizeof(DATE_STRUCT);
+ *static_cast<DATE_STRUCT*>(_pData) = *static_cast<DATE_STRUCT const *>(_pValue);
+ break;
+ case SQL_TIME:
+ *pLen = sizeof(TIME_STRUCT);
+ *static_cast<TIME_STRUCT*>(_pData) = *static_cast<TIME_STRUCT const *>(_pValue);
+ break;
+ case SQL_TIMESTAMP:
+ *pLen = sizeof(TIMESTAMP_STRUCT);
+ *static_cast<TIMESTAMP_STRUCT*>(_pData) = *static_cast<TIMESTAMP_STRUCT const *>(_pValue);
+ break;
+ }
+ }
+ catch ( ... )
+ {
+ }
+
+ nRetcode = (*reinterpret_cast<T3SQLBindCol>(_pConnection->getOdbcFunction(ODBC3SQLFunctionId::BindCol)))(_aStatementHandle,
+ static_cast<SQLUSMALLINT>(columnIndex),
+ fCType,
+ _pData,
+ _nMaxLen,
+ pLen
+ );
+ }
+
+ OTools::ThrowException(_pConnection,nRetcode,_aStatementHandle,SQL_HANDLE_STMT,_xInterface);
+}
+
+void OTools::ThrowException(const OConnection* _pConnection,
+ const SQLRETURN _rRetCode,
+ const SQLHANDLE _pContext,
+ const SQLSMALLINT _nHandleType,
+ const Reference< XInterface >& _xInterface,
+ const bool _bNoFound)
+{
+ switch(_rRetCode)
+ {
+ case SQL_NEED_DATA:
+ case SQL_STILL_EXECUTING:
+ case SQL_SUCCESS:
+
+ case SQL_SUCCESS_WITH_INFO:
+ return;
+ case SQL_NO_DATA_FOUND:
+ if(_bNoFound)
+ return; // no need to throw an exception
+ break;
+ case SQL_ERROR: break;
+
+
+ case SQL_INVALID_HANDLE: SAL_WARN( "connectivity.drivers", "SdbODBC3_SetStatus: SQL_INVALID_HANDLE");
+ throw SQLException();
+ }
+
+ // Additional Information on the latest ODBC-functioncall available
+ // SQLError provides this Information.
+
+ SDB_ODBC_CHAR szSqlState[5];
+ SQLINTEGER pfNativeError;
+ SDB_ODBC_CHAR szErrorMessage[SQL_MAX_MESSAGE_LENGTH];
+ szErrorMessage[0] = '\0';
+ SQLSMALLINT pcbErrorMsg = 0;
+
+ // Information for latest operation:
+ // when hstmt != SQL_NULL_HSTMT is (Used from SetStatus in SdbCursor, SdbTable, ...),
+ // then the status of the latest statements will be fetched, without the Status of the last
+ // statements of this connection [what in this case will probably be the same, but the Reference
+ // Manual isn't totally clear in this...].
+ // corresponding for hdbc.
+ SQLRETURN n = (*reinterpret_cast<T3SQLGetDiagRec>(_pConnection->getOdbcFunction(ODBC3SQLFunctionId::GetDiagRec)))(_nHandleType,_pContext,1,
+ szSqlState,
+ &pfNativeError,
+ szErrorMessage,sizeof szErrorMessage - 1,&pcbErrorMsg);
+ OSL_ENSURE(n != SQL_INVALID_HANDLE,"SdbODBC3_SetStatus: SQLError returned SQL_INVALID_HANDLE");
+ OSL_ENSURE(n == SQL_SUCCESS || n == SQL_SUCCESS_WITH_INFO || n == SQL_NO_DATA_FOUND || n == SQL_ERROR,"SdbODBC3_SetStatus: SQLError failed");
+
+ rtl_TextEncoding _nTextEncoding = osl_getThreadTextEncoding();
+ // For the Return Code of SQLError see ODBC 2.0 Programmer's Reference Page 287ff
+ throw SQLException( OUString(reinterpret_cast<char *>(szErrorMessage), pcbErrorMsg, _nTextEncoding),
+ _xInterface,
+ OUString(reinterpret_cast<char *>(szSqlState), 5, _nTextEncoding),
+ pfNativeError,
+ Any()
+ );
+
+}
+
+Sequence<sal_Int8> OTools::getBytesValue(const OConnection* _pConnection,
+ const SQLHANDLE _aStatementHandle,
+ const sal_Int32 columnIndex,
+ const SQLSMALLINT _fSqlType,
+ bool &_bWasNull,
+ const Reference< XInterface >& _xInterface)
+{
+ sal_Int8 aCharArray[2048];
+ // First try to fetch the data with the little Buffer:
+ const SQLLEN nMaxLen = sizeof aCharArray;
+ SQLLEN pcbValue = SQL_NO_TOTAL;
+ Sequence<sal_Int8> aData;
+
+ OSL_ENSURE( _fSqlType != SQL_CHAR && _fSqlType != SQL_VARCHAR && _fSqlType != SQL_LONGVARCHAR &&
+ _fSqlType != SQL_WCHAR && _fSqlType != SQL_WVARCHAR && _fSqlType != SQL_WLONGVARCHAR,
+ "connectivity::odbc::OTools::getBytesValue called with character _fSqlType");
+
+ while (pcbValue == SQL_NO_TOTAL || pcbValue > nMaxLen)
+ {
+ OTools::ThrowException(_pConnection,
+ (*reinterpret_cast<T3SQLGetData>(_pConnection->getOdbcFunction(ODBC3SQLFunctionId::GetData)))(
+ _aStatementHandle,
+ static_cast<SQLUSMALLINT>(columnIndex),
+ _fSqlType,
+ static_cast<SQLPOINTER>(aCharArray),
+ nMaxLen,
+ &pcbValue),
+ _aStatementHandle,SQL_HANDLE_STMT,_xInterface);
+
+ _bWasNull = pcbValue == SQL_NULL_DATA;
+ if(_bWasNull)
+ return Sequence<sal_Int8>();
+
+ SQLLEN nReadBytes;
+ // After the SQLGetData that wrote out to aCharArray the last byte of the data,
+ // pcbValue will not be SQL_NO_TOTAL -> we have a reliable count
+ if ( (pcbValue == SQL_NO_TOTAL) || (pcbValue >= nMaxLen) )
+ {
+ // we filled the buffer
+ nReadBytes = nMaxLen;
+ }
+ else
+ {
+ nReadBytes = pcbValue;
+ }
+ const sal_Int32 nLen = aData.getLength();
+ aData.realloc(nLen + nReadBytes);
+ memcpy(aData.getArray() + nLen, aCharArray, nReadBytes);
+ }
+ return aData;
+}
+
+OUString OTools::getStringValue(OConnection const * _pConnection,
+ SQLHANDLE _aStatementHandle,
+ sal_Int32 columnIndex,
+ SQLSMALLINT _fSqlType,
+ bool &_bWasNull,
+ const Reference< XInterface >& _xInterface,
+ const rtl_TextEncoding _nTextEncoding)
+{
+ OUStringBuffer aData;
+ switch(_fSqlType)
+ {
+ case SQL_WVARCHAR:
+ case SQL_WCHAR:
+ case SQL_WLONGVARCHAR:
+ {
+ SQLWCHAR waCharArray[2048];
+ static_assert(sizeof(waCharArray) % sizeof(SQLWCHAR) == 0, "must fit in evenly");
+ static_assert(sizeof(SQLWCHAR) == 2 || sizeof(SQLWCHAR) == 4, "must be 2 or 4");
+ // Size == number of bytes, Len == number of UTF-16 or UCS4 code units
+ const SQLLEN nMaxSize = sizeof(waCharArray);
+ const SQLLEN nMaxLen = sizeof(waCharArray) / sizeof(SQLWCHAR);
+ static_assert(nMaxLen * sizeof(SQLWCHAR) == nMaxSize, "sizes must match");
+
+ // read the unicode data
+ SQLLEN pcbValue = SQL_NO_TOTAL;
+ while ((pcbValue == SQL_NO_TOTAL ) || (pcbValue >= nMaxSize) )
+ {
+ OTools::ThrowException(_pConnection,
+ (*reinterpret_cast<T3SQLGetData>(_pConnection->getOdbcFunction(ODBC3SQLFunctionId::GetData)))(
+ _aStatementHandle,
+ static_cast<SQLUSMALLINT>(columnIndex),
+ SQL_C_WCHAR,
+ &waCharArray,
+ SQLLEN(nMaxLen)*sizeof(sal_Unicode),
+ &pcbValue),
+ _aStatementHandle,SQL_HANDLE_STMT,_xInterface);
+ _bWasNull = pcbValue == SQL_NULL_DATA;
+ if(_bWasNull)
+ return OUString();
+
+ SQLLEN nReadChars;
+ OSL_ENSURE( (pcbValue < 0) || (pcbValue % 2 == 0),
+ "ODBC: SQLGetData of SQL_C_WCHAR returned odd number of bytes");
+ if ( (pcbValue == SQL_NO_TOTAL) || (pcbValue >= nMaxSize) )
+ {
+ // we filled the buffer; remove the terminating null character
+ nReadChars = nMaxLen-1;
+ if ( waCharArray[nReadChars] != 0)
+ {
+ SAL_WARN( "connectivity.drivers", "Buggy ODBC driver? Did not null-terminate (variable length) data!");
+ ++nReadChars;
+ }
+ }
+ else
+ {
+ nReadChars = pcbValue/sizeof(SQLWCHAR);
+ }
+
+ appendSQLWCHARs(aData, waCharArray, nReadChars);
+ }
+ break;
+ }
+ default:
+ {
+ char aCharArray[2048];
+ // read the unicode data
+ const SQLLEN nMaxLen = sizeof(aCharArray);
+ SQLLEN pcbValue = SQL_NO_TOTAL;
+
+ while ((pcbValue == SQL_NO_TOTAL ) || (pcbValue >= nMaxLen) )
+ {
+ OTools::ThrowException(_pConnection,
+ (*reinterpret_cast<T3SQLGetData>(_pConnection->getOdbcFunction(ODBC3SQLFunctionId::GetData)))(
+ _aStatementHandle,
+ static_cast<SQLUSMALLINT>(columnIndex),
+ SQL_C_CHAR,
+ &aCharArray,
+ nMaxLen,
+ &pcbValue),
+ _aStatementHandle,SQL_HANDLE_STMT,_xInterface);
+ _bWasNull = pcbValue == SQL_NULL_DATA;
+ if(_bWasNull)
+ return OUString();
+
+ SQLLEN nReadChars;
+ if ( (pcbValue == SQL_NO_TOTAL) || (pcbValue >= nMaxLen) )
+ {
+ // we filled the buffer; remove the terminating null character
+ nReadChars = nMaxLen-1;
+ if ( aCharArray[nReadChars] != 0)
+ {
+ SAL_WARN( "connectivity.drivers", "Buggy ODBC driver? Did not null-terminate (variable length) data!");
+ ++nReadChars;
+ }
+ }
+ else
+ {
+ nReadChars = pcbValue;
+ }
+
+ aData.append(OUString(aCharArray, nReadChars, _nTextEncoding));
+
+ }
+ break;
+ }
+ }
+
+ return aData.makeStringAndClear();
+}
+
+void OTools::GetInfo(OConnection const * _pConnection,
+ SQLHANDLE _aConnectionHandle,
+ SQLUSMALLINT _nInfo,
+ OUString &_rValue,
+ const Reference< XInterface >& _xInterface,
+ rtl_TextEncoding _nTextEncoding)
+{
+ char aValue[512];
+ SQLSMALLINT nValueLen=0;
+ OTools::ThrowException(_pConnection,
+ (*reinterpret_cast<T3SQLGetInfo>(_pConnection->getOdbcFunction(ODBC3SQLFunctionId::GetInfo)))(_aConnectionHandle,_nInfo,aValue,(sizeof aValue)-1,&nValueLen),
+ _aConnectionHandle,SQL_HANDLE_DBC,_xInterface);
+
+ _rValue = OUString(aValue,nValueLen,_nTextEncoding);
+}
+
+void OTools::GetInfo(OConnection const * _pConnection,
+ SQLHANDLE _aConnectionHandle,
+ SQLUSMALLINT _nInfo,
+ sal_Int32 &_rValue,
+ const Reference< XInterface >& _xInterface)
+{
+ SQLSMALLINT nValueLen;
+ _rValue = 0; // in case the driver uses only 16 of the 32 bits (as it does, for example, for SQL_CATALOG_LOCATION)
+ OTools::ThrowException(_pConnection,
+ (*reinterpret_cast<T3SQLGetInfo>(_pConnection->getOdbcFunction(ODBC3SQLFunctionId::GetInfo)))(_aConnectionHandle,_nInfo,&_rValue,sizeof _rValue,&nValueLen),
+ _aConnectionHandle,SQL_HANDLE_DBC,_xInterface);
+}
+
+void OTools::GetInfo(OConnection const * _pConnection,
+ SQLHANDLE _aConnectionHandle,
+ SQLUSMALLINT _nInfo,
+ SQLUINTEGER &_rValue,
+ const Reference< XInterface >& _xInterface)
+{
+ SQLSMALLINT nValueLen;
+ _rValue = 0; // in case the driver uses only 16 of the 32 bits (as it does, for example, for SQL_CATALOG_LOCATION)
+ OTools::ThrowException(_pConnection,
+ (*reinterpret_cast<T3SQLGetInfo>(_pConnection->getOdbcFunction(ODBC3SQLFunctionId::GetInfo)))(_aConnectionHandle,_nInfo,&_rValue,sizeof _rValue,&nValueLen),
+ _aConnectionHandle,SQL_HANDLE_DBC,_xInterface);
+}
+
+void OTools::GetInfo(OConnection const * _pConnection,
+ SQLHANDLE _aConnectionHandle,
+ SQLUSMALLINT _nInfo,
+ SQLUSMALLINT &_rValue,
+ const Reference< XInterface >& _xInterface)
+{
+ SQLSMALLINT nValueLen;
+ _rValue = 0; // in case the driver uses only 16 of the 32 bits (as it does, for example, for SQL_CATALOG_LOCATION)
+ OTools::ThrowException(_pConnection,
+ (*reinterpret_cast<T3SQLGetInfo>(_pConnection->getOdbcFunction(ODBC3SQLFunctionId::GetInfo)))(_aConnectionHandle,_nInfo,&_rValue,sizeof _rValue,&nValueLen),
+ _aConnectionHandle,SQL_HANDLE_DBC,_xInterface);
+}
+
+sal_Int32 OTools::MapOdbcType2Jdbc(SQLSMALLINT _nType)
+{
+ sal_Int32 nValue = DataType::VARCHAR;
+ switch(_nType)
+ {
+ case SQL_BIT:
+ nValue = DataType::BIT;
+ break;
+ case SQL_TINYINT:
+ nValue = DataType::TINYINT;
+ break;
+ case SQL_SMALLINT:
+ nValue = DataType::SMALLINT;
+ break;
+ case SQL_INTEGER:
+ nValue = DataType::INTEGER;
+ break;
+ case SQL_BIGINT:
+ nValue = DataType::BIGINT;
+ break;
+ case SQL_FLOAT:
+ nValue = DataType::FLOAT;
+ break;
+ case SQL_REAL:
+ nValue = DataType::REAL;
+ break;
+ case SQL_DOUBLE:
+ nValue = DataType::DOUBLE;
+ break;
+ case SQL_NUMERIC:
+ nValue = DataType::NUMERIC;
+ break;
+ case SQL_DECIMAL:
+ nValue = DataType::DECIMAL;
+ break;
+ case SQL_WCHAR:
+ case SQL_CHAR:
+ nValue = DataType::CHAR;
+ break;
+ case SQL_WVARCHAR:
+ case SQL_VARCHAR:
+ nValue = DataType::VARCHAR;
+ break;
+ case SQL_WLONGVARCHAR:
+ case SQL_LONGVARCHAR:
+ nValue = DataType::LONGVARCHAR;
+ break;
+ case SQL_TYPE_DATE:
+ case SQL_DATE:
+ nValue = DataType::DATE;
+ break;
+ case SQL_TYPE_TIME:
+ case SQL_TIME:
+ nValue = DataType::TIME;
+ break;
+ case SQL_TYPE_TIMESTAMP:
+ case SQL_TIMESTAMP:
+ nValue = DataType::TIMESTAMP;
+ break;
+ case SQL_BINARY:
+ nValue = DataType::BINARY;
+ break;
+ case SQL_VARBINARY:
+ case SQL_GUID:
+ nValue = DataType::VARBINARY;
+ break;
+ case SQL_LONGVARBINARY:
+ nValue = DataType::LONGVARBINARY;
+ break;
+ default:
+ OSL_FAIL("Invalid type");
+ }
+ return nValue;
+}
+
+// jdbcTypeToOdbc
+// Convert the JDBC SQL type to the correct ODBC type
+
+SQLSMALLINT OTools::jdbcTypeToOdbc(sal_Int32 jdbcType)
+{
+ // For the most part, JDBC types match ODBC types. We'll
+ // just convert the ones that we know are different
+
+ sal_Int32 odbcType = jdbcType;
+
+ switch (jdbcType)
+ {
+ case DataType::DATE:
+ odbcType = SQL_DATE;
+ break;
+ case DataType::TIME:
+ odbcType = SQL_TIME;
+ break;
+ case DataType::TIMESTAMP:
+ odbcType = SQL_TIMESTAMP;
+ break;
+ // ODBC doesn't have any notion of CLOB or BLOB
+ case DataType::CLOB:
+ odbcType = SQL_LONGVARCHAR;
+ break;
+ case DataType::BLOB:
+ odbcType = SQL_LONGVARBINARY;
+ break;
+ }
+
+ return odbcType;
+}
+
+void OTools::getBindTypes(bool _bUseWChar,
+ bool _bUseOldTimeDate,
+ SQLSMALLINT _nOdbcType,
+ SQLSMALLINT& fCType,
+ SQLSMALLINT& fSqlType
+ )
+{
+ switch(_nOdbcType)
+ {
+ case SQL_CHAR: if(_bUseWChar)
+ {
+ fCType = SQL_C_WCHAR;
+ fSqlType = SQL_WCHAR;
+ }
+ else
+ {
+ fCType = SQL_C_CHAR;
+ fSqlType = SQL_CHAR;
+ }
+ break;
+ case SQL_VARCHAR: if(_bUseWChar)
+ {
+ fCType = SQL_C_WCHAR;
+ fSqlType = SQL_WVARCHAR;
+ }
+ else
+ {
+ fCType = SQL_C_CHAR;
+ fSqlType = SQL_VARCHAR;
+ }
+ break;
+ case SQL_LONGVARCHAR: if(_bUseWChar)
+ {
+ fCType = SQL_C_WCHAR;
+ fSqlType = SQL_WLONGVARCHAR;
+ }
+ else
+ {
+ fCType = SQL_C_CHAR;
+ fSqlType = SQL_LONGVARCHAR;
+ }
+ break;
+ case SQL_DECIMAL: fCType = _bUseWChar ? SQL_C_WCHAR : SQL_C_CHAR;
+ fSqlType = SQL_DECIMAL; break;
+ case SQL_NUMERIC: fCType = _bUseWChar ? SQL_C_WCHAR : SQL_C_CHAR;
+ fSqlType = SQL_NUMERIC; break;
+ case SQL_BIT: fCType = SQL_C_TINYINT;
+ fSqlType = SQL_INTEGER; break;
+ case SQL_TINYINT: fCType = SQL_C_TINYINT;
+ fSqlType = SQL_TINYINT; break;
+ case SQL_SMALLINT: fCType = SQL_C_SHORT;
+ fSqlType = SQL_SMALLINT; break;
+ case SQL_INTEGER: fCType = SQL_C_LONG;
+ fSqlType = SQL_INTEGER; break;
+ case SQL_BIGINT: fCType = SQL_C_SBIGINT;
+ fSqlType = SQL_BIGINT; break;
+ case SQL_FLOAT: fCType = SQL_C_FLOAT;
+ fSqlType = SQL_FLOAT; break;
+ case SQL_REAL: fCType = SQL_C_DOUBLE;
+ fSqlType = SQL_REAL; break;
+ case SQL_DOUBLE: fCType = SQL_C_DOUBLE;
+ fSqlType = SQL_DOUBLE; break;
+ case SQL_BINARY: fCType = SQL_C_BINARY;
+ fSqlType = SQL_BINARY; break;
+ case SQL_VARBINARY:
+ fCType = SQL_C_BINARY;
+ fSqlType = SQL_VARBINARY; break;
+ case SQL_LONGVARBINARY: fCType = SQL_C_BINARY;
+ fSqlType = SQL_LONGVARBINARY; break;
+ case SQL_DATE:
+ if(_bUseOldTimeDate)
+ {
+ fCType = SQL_C_DATE;
+ fSqlType = SQL_DATE;
+ }
+ else
+ {
+ fCType = SQL_C_TYPE_DATE;
+ fSqlType = SQL_TYPE_DATE;
+ }
+ break;
+ case SQL_TIME:
+ if(_bUseOldTimeDate)
+ {
+ fCType = SQL_C_TIME;
+ fSqlType = SQL_TIME;
+ }
+ else
+ {
+ fCType = SQL_C_TYPE_TIME;
+ fSqlType = SQL_TYPE_TIME;
+ }
+ break;
+ case SQL_TIMESTAMP:
+ if(_bUseOldTimeDate)
+ {
+ fCType = SQL_C_TIMESTAMP;
+ fSqlType = SQL_TIMESTAMP;
+ }
+ else
+ {
+ fCType = SQL_C_TYPE_TIMESTAMP;
+ fSqlType = SQL_TYPE_TIMESTAMP;
+ }
+ break;
+ default: fCType = SQL_C_BINARY;
+ fSqlType = SQL_LONGVARBINARY; break;
+ }
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/odbc/odbc.component b/connectivity/source/drivers/odbc/odbc.component
new file mode 100644
index 0000000000..4d3348378b
--- /dev/null
+++ b/connectivity/source/drivers/odbc/odbc.component
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ -->
+
+<component loader="com.sun.star.loader.SharedLibrary" environment="@CPPU_ENV@"
+ xmlns="http://openoffice.org/2010/uno-components">
+ <implementation name="com.sun.star.comp.sdbc.ODBCDriver"
+ constructor="connectivity_odbc_ORealOdbcDriver_get_implementation">
+ <service name="com.sun.star.sdbc.Driver"/>
+ </implementation>
+</component>
diff --git a/connectivity/source/drivers/postgresql/postgresql-sdbc-impl.component b/connectivity/source/drivers/postgresql/postgresql-sdbc-impl.component
new file mode 100644
index 0000000000..8c5a6ff052
--- /dev/null
+++ b/connectivity/source/drivers/postgresql/postgresql-sdbc-impl.component
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+-->
+
+<component loader="com.sun.star.loader.SharedLibrary" environment="@CPPU_ENV@"
+ xmlns="http://openoffice.org/2010/uno-components">
+ <implementation name="org.openoffice.comp.connectivity.pq.Connection.noext"
+ constructor="connectivity_postgresql_Connection_get_implementation">
+ <service name="com.sun.star.sdbc.Connection"/>
+ </implementation>
+</component>
diff --git a/connectivity/source/drivers/postgresql/postgresql-sdbc.component b/connectivity/source/drivers/postgresql/postgresql-sdbc.component
new file mode 100644
index 0000000000..a14ab2c96f
--- /dev/null
+++ b/connectivity/source/drivers/postgresql/postgresql-sdbc.component
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+-->
+
+<component loader="com.sun.star.loader.SharedLibrary" environment="@CPPU_ENV@"
+ xmlns="http://openoffice.org/2010/uno-components">
+ <implementation name="org.openoffice.comp.connectivity.pq.Driver.noext"
+ constructor="connectivity_pq_sdbc_driver_get_implementation" single-instance="true">
+ <service name="com.sun.star.sdbc.Driver"/>
+ </implementation>
+</component>
diff --git a/connectivity/source/drivers/postgresql/pq_array.cxx b/connectivity/source/drivers/postgresql/pq_array.cxx
new file mode 100644
index 0000000000..841ed70c6c
--- /dev/null
+++ b/connectivity/source/drivers/postgresql/pq_array.cxx
@@ -0,0 +1,122 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * Effective License of whole file:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011:
+ *
+ * The Contents of this file are made available subject to the terms of
+ * the GNU Lesser General Public License Version 2.1
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * Contributor(s): Joerg Budischewski
+ *
+ * All parts contributed on or after August 2011:
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ ************************************************************************/
+
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <comphelper/sequence.hxx>
+
+
+#include "pq_array.hxx"
+#include "pq_statics.hxx"
+#include "pq_sequenceresultset.hxx"
+
+
+using com::sun::star::sdbc::SQLException;
+using com::sun::star::uno::Any;
+
+using com::sun::star::uno::Sequence;
+namespace pq_sdbc_driver
+{
+
+
+OUString Array::getBaseTypeName( )
+{
+ return "varchar";
+}
+
+sal_Int32 Array::getBaseType( )
+{
+ return css::sdbc::DataType::VARCHAR;
+}
+
+css::uno::Sequence< css::uno::Any > Array::getArray(
+ const css::uno::Reference< css::container::XNameAccess >& /* typeMap */ )
+{
+ return comphelper::containerToSequence(m_data);
+}
+
+css::uno::Sequence< css::uno::Any > Array::getArrayAtIndex(
+ sal_Int32 index,
+ sal_Int32 count,
+ const css::uno::Reference< css::container::XNameAccess >& /* typeMap */ )
+{
+ checkRange( index, count );
+ return Sequence< Any > ( &m_data[index-1], count );
+}
+
+css::uno::Reference< css::sdbc::XResultSet > Array::getResultSet(
+ const css::uno::Reference< css::container::XNameAccess >& typeMap )
+{
+ return getResultSetAtIndex( 0 , m_data.size() , typeMap );
+}
+
+css::uno::Reference< css::sdbc::XResultSet > Array::getResultSetAtIndex(
+ sal_Int32 index,
+ sal_Int32 count,
+ const css::uno::Reference< css::container::XNameAccess >& /* typeMap */ )
+{
+ checkRange( index, count );
+ std::vector< std::vector< Any > > ret( count );
+
+ for( int i = 0 ; i < count ; i ++ )
+ {
+ std::vector< Any > row( 2 );
+ row[0] <<= static_cast<sal_Int32>( i + index );
+ row[1] = m_data[i+index-1];
+ ret[i] = row;
+ }
+
+ return new SequenceResultSet(
+ m_xMutex, m_owner, std::vector(getStatics().resultSetArrayColumnNames), std::move(ret), m_tc );
+}
+
+
+void Array::checkRange( sal_Int32 index, sal_Int32 count )
+{
+ if( index >= 1 && index -1 + count <= static_cast<sal_Int32>(m_data.size()) )
+ return;
+ throw SQLException(
+ "Array::getArrayAtIndex(): allowed range for index + count "
+ + OUString::number( m_data.size() )
+ + ", got " + OUString::number( index )
+ + " + " + OUString::number( count ),
+ *this, OUString(), 1, Any());
+
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/postgresql/pq_array.hxx b/connectivity/source/drivers/postgresql/pq_array.hxx
new file mode 100644
index 0000000000..589fe063d2
--- /dev/null
+++ b/connectivity/source/drivers/postgresql/pq_array.hxx
@@ -0,0 +1,98 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * Effective License of whole file:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011:
+ *
+ * The Contents of this file are made available subject to the terms of
+ * the GNU Lesser General Public License Version 2.1
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * Contributor(s): Joerg Budischewski
+ *
+ * All parts contributed on or after August 2011:
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ ************************************************************************/
+
+#pragma once
+#include <cppuhelper/implbase.hxx>
+#include <com/sun/star/sdbc/XArray.hpp>
+
+#include "pq_connection.hxx"
+#include <utility>
+#include <vector>
+
+namespace pq_sdbc_driver
+{
+
+class Array : public cppu::WeakImplHelper< css::sdbc::XArray >
+{
+ std::vector< css::uno::Any > m_data;
+ css::uno::Reference< css::uno::XInterface > m_owner;
+ css::uno::Reference< css::script::XTypeConverter > m_tc;
+ rtl::Reference< comphelper::RefCountedMutex > m_xMutex;
+
+public:
+ Array(
+ rtl::Reference< comphelper::RefCountedMutex > mutex,
+ std::vector< css::uno::Any > && data,
+ css::uno::Reference< css::uno::XInterface > owner,
+ css::uno::Reference< css::script::XTypeConverter > tc) :
+ m_data( std::move(data) ),
+ m_owner(std::move( owner )),
+ m_tc(std::move( tc )),
+ m_xMutex(std::move( mutex ))
+ {}
+
+public: // XArray
+
+ // Methods
+ virtual OUString SAL_CALL getBaseTypeName( ) override;
+
+ virtual sal_Int32 SAL_CALL getBaseType( ) override;
+
+ virtual css::uno::Sequence< css::uno::Any > SAL_CALL getArray(
+ const css::uno::Reference< css::container::XNameAccess >& typeMap ) override;
+
+ virtual css::uno::Sequence< css::uno::Any > SAL_CALL getArrayAtIndex(
+ sal_Int32 index,
+ sal_Int32 count,
+ const css::uno::Reference< css::container::XNameAccess >& typeMap ) override;
+
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL
+ getResultSet(
+ const css::uno::Reference< css::container::XNameAccess >& typeMap ) override;
+
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getResultSetAtIndex(
+ sal_Int32 index,
+ sal_Int32 count,
+ const css::uno::Reference< css::container::XNameAccess >& typeMap ) override;
+
+private:
+ void checkRange( sal_Int32 index, sal_Int32 count );
+};
+
+
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/postgresql/pq_baseresultset.cxx b/connectivity/source/drivers/postgresql/pq_baseresultset.cxx
new file mode 100644
index 0000000000..9ff5e01e09
--- /dev/null
+++ b/connectivity/source/drivers/postgresql/pq_baseresultset.cxx
@@ -0,0 +1,613 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * Effective License of whole file:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011:
+ *
+ * The Contents of this file are made available subject to the terms of
+ * the GNU Lesser General Public License Version 2.1
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * Contributor(s): Joerg Budischewski
+ *
+ * All parts contributed on or after August 2011:
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ ************************************************************************/
+
+#include <comphelper/sequence.hxx>
+
+#include "pq_tools.hxx"
+#include "pq_array.hxx"
+#include "pq_baseresultset.hxx"
+
+#include <com/sun/star/script/CannotConvertException.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <connectivity/dbconversion.hxx>
+
+using osl::MutexGuard;
+
+
+using com::sun::star::beans::XPropertySetInfo;
+
+using com::sun::star::uno::Any;
+using com::sun::star::uno::Type;
+using com::sun::star::uno::Sequence;
+using com::sun::star::uno::Reference;
+using com::sun::star::uno::XInterface;
+
+using com::sun::star::lang::IllegalArgumentException;
+
+using com::sun::star::sdbc::SQLException;
+
+
+using com::sun::star::beans::Property;
+
+using namespace dbtools;
+
+namespace pq_sdbc_driver
+{
+static ::cppu::IPropertyArrayHelper & getResultSetPropertyArrayHelper()
+{
+ // LEM TODO: this needs to be kept in sync with other, e.g. pq_statics.css:508
+ // Should really share!
+ // At least use for the handles the #define'd values in .hxx file...
+ static ::cppu::OPropertyArrayHelper arrayHelper(
+ Sequence<Property>{
+ Property(
+ "CursorName", 0,
+ ::cppu::UnoType<OUString>::get() , 0 ),
+ Property(
+ "EscapeProcessing", 1,
+ cppu::UnoType<bool>::get() , 0 ),
+ Property(
+ "FetchDirection", 2,
+ ::cppu::UnoType<sal_Int32>::get() , 0 ),
+ Property(
+ "FetchSize", 3,
+ ::cppu::UnoType<sal_Int32>::get() , 0 ),
+ Property(
+ "IsBookmarkable", 4,
+ cppu::UnoType<bool>::get() , 0 ),
+ Property(
+ "ResultSetConcurrency", 5,
+ ::cppu::UnoType<sal_Int32>::get() , 0 ),
+ Property(
+ "ResultSetType", 6,
+ ::cppu::UnoType<sal_Int32>::get() , 0 )},
+ true );
+ return arrayHelper;
+}
+
+BaseResultSet::BaseResultSet(
+ const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex,
+ const Reference< XInterface > & owner,
+ sal_Int32 rowCount,
+ sal_Int32 colCount,
+ const Reference< css::script::XTypeConverter > & tc )
+ : BaseResultSet_BASE( refMutex->GetMutex() )
+ , OPropertySetHelper( BaseResultSet_BASE::rBHelper )
+ , m_owner( owner )
+ , m_tc( tc )
+ , m_xMutex( refMutex )
+ , m_row( -1 )
+ , m_rowCount( rowCount )
+ , m_fieldCount( colCount )
+ , m_wasNull(false)
+{
+}
+
+// LEM TODO: refMutex->GetMutex() should live longer than OComponentHelper,
+// but calling OComponentHelper::dispose explicitly here calls
+// BaseResultSet::~BaseResultSet in an infinite loop :(
+BaseResultSet::~BaseResultSet()
+{
+}
+
+Any BaseResultSet::queryInterface( const Type & rType )
+{
+ Any aRet = BaseResultSet_BASE::queryInterface(rType);
+ return aRet.hasValue() ? aRet : OPropertySetHelper::queryInterface(rType);
+}
+
+// void BaseResultSet::close( ) throw (SQLException, RuntimeException)
+// {
+// Reference< XInterface > owner;
+// {
+// ResultSetGuard guard(*this);
+// if( m_result )
+// {
+// PQclear(m_result );
+// m_result = 0;
+// m_row = -1;
+// }
+// owner = m_owner;
+// m_owner.clear();
+// }
+// }
+
+Sequence<Type > BaseResultSet::getTypes()
+{
+ static Sequence< Type > collection(
+ ::comphelper::concatSequences(
+ OPropertySetHelper::getTypes(),
+ BaseResultSet_BASE::getTypes()));
+ return collection;
+}
+
+Sequence< sal_Int8> BaseResultSet::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+// Reference< XResultSetMetaData > BaseResultSet::getMetaData( ) throw (SQLException, RuntimeException)
+// {
+// ResultSetGuard guard(*this);
+// checkClosed();
+// return new ResultSetMetaData( m_xMutex, this, &m_result );
+// }
+
+sal_Bool BaseResultSet::next( )
+{
+ MutexGuard guard( m_xMutex->GetMutex() );
+ checkClosed();
+ m_row ++;
+ return m_row < m_rowCount;
+}
+
+sal_Bool BaseResultSet::isBeforeFirst( )
+{
+ MutexGuard guard( m_xMutex->GetMutex() );
+ checkClosed();
+ return m_row == -1;
+}
+
+sal_Bool BaseResultSet::isAfterLast( )
+{
+ MutexGuard guard( m_xMutex->GetMutex() );
+ checkClosed();
+ return m_row >= m_rowCount;
+}
+
+sal_Bool BaseResultSet::isFirst( )
+{
+ MutexGuard guard( m_xMutex->GetMutex() );
+ checkClosed();
+ return m_row == 0 && m_rowCount;
+}
+
+sal_Bool BaseResultSet::isLast( )
+{
+ MutexGuard guard( m_xMutex->GetMutex() );
+ checkClosed();
+ return m_row >= 0 && m_row + 1 == m_rowCount;
+}
+
+void BaseResultSet::beforeFirst( )
+{
+ MutexGuard guard( m_xMutex->GetMutex() );
+ checkClosed();
+ m_row = -1;
+}
+
+void BaseResultSet::afterLast( )
+{
+ MutexGuard guard( m_xMutex->GetMutex() );
+ checkClosed();
+ m_row = m_rowCount;
+}
+
+sal_Bool BaseResultSet::first( )
+{
+ MutexGuard guard( m_xMutex->GetMutex() );
+ checkClosed();
+ bool bRet = ( m_rowCount > 0 );
+ if( bRet )
+ m_row = 0;
+ return bRet;
+}
+
+sal_Bool BaseResultSet::last( )
+{
+ MutexGuard guard( m_xMutex->GetMutex() );
+ checkClosed();
+ bool bRet = ( m_rowCount > 0 );
+ if( bRet )
+ m_row = m_rowCount -1;
+ return bRet;
+}
+
+sal_Int32 BaseResultSet::getRow( )
+{
+ MutexGuard guard( m_xMutex->GetMutex() );
+ checkClosed();
+ return m_row +1;
+}
+
+sal_Bool BaseResultSet::absolute( sal_Int32 row )
+{
+ MutexGuard guard( m_xMutex->GetMutex() );
+ checkClosed();
+ if( row > 0 )
+ {
+ m_row = row -1;
+ if( m_row > m_rowCount )
+ m_row = m_rowCount;
+ }
+ else
+ {
+ m_row = m_rowCount + row;
+ if( m_row < -1 )
+ m_row = -1;
+ }
+ return true;
+}
+
+sal_Bool BaseResultSet::relative( sal_Int32 rows )
+{
+ MutexGuard guard( m_xMutex->GetMutex() );
+ checkClosed();
+ m_row += rows;
+
+ if( m_row > m_rowCount )
+ m_row = m_rowCount;
+ else if ( m_row < -1 )
+ m_row = -1;
+ return true;
+}
+
+sal_Bool BaseResultSet::previous( )
+{
+ MutexGuard guard( m_xMutex->GetMutex() );
+ checkClosed();
+ bool bRet = ( m_row != -1 );
+ if( bRet )
+ m_row --;
+ return bRet;
+}
+
+void BaseResultSet::refreshRow( )
+{
+ // TODO: not supported for now
+}
+
+sal_Bool BaseResultSet::rowUpdated( )
+{
+ return false;
+}
+
+sal_Bool BaseResultSet::rowInserted( )
+{
+ return false;
+}
+
+sal_Bool BaseResultSet::rowDeleted( )
+{
+ return false;
+}
+
+Reference< XInterface > BaseResultSet::getStatement()
+{
+ MutexGuard guard( m_xMutex->GetMutex() );
+ checkClosed();
+ return m_owner;
+}
+
+
+//----------------- XRow interface ----------------------------------------------------
+
+sal_Bool BaseResultSet::wasNull( )
+{
+ return m_wasNull;
+}
+
+Any BaseResultSet::convertTo( const Any & val , const Type & type )
+{
+ Any aRet;
+ try
+ {
+ aRet = m_tc->convertTo( val , type );
+ }
+ catch( css::lang::IllegalArgumentException & )
+ {}
+ catch( css::script::CannotConvertException & )
+ {}
+ return aRet;
+}
+
+sal_Bool BaseResultSet::getBoolean( sal_Int32 columnIndex )
+{
+ MutexGuard guard( m_xMutex->GetMutex() );
+ checkClosed();
+ checkColumnIndex( columnIndex );
+ checkRowIndex();
+
+ OUString str = getString( columnIndex );
+
+ if( str.getLength() > 0 )
+ {
+ switch(str[0])
+ {
+ case '1':
+ case 't':
+ case 'T':
+ case 'y':
+ case 'Y':
+
+ return true;
+ }
+ }
+ return false;
+}
+
+sal_Int8 BaseResultSet::getByte( sal_Int32 columnIndex )
+{
+ MutexGuard guard( m_xMutex->GetMutex() );
+ checkClosed();
+ checkColumnIndex( columnIndex );
+ checkRowIndex();
+ sal_Int8 b = 0;
+ convertTo( getValue( columnIndex ), cppu::UnoType<decltype(b)>::get()) >>= b;
+ return b;
+}
+
+sal_Int16 BaseResultSet::getShort( sal_Int32 columnIndex )
+{
+ MutexGuard guard( m_xMutex->GetMutex() );
+ checkClosed();
+ checkColumnIndex( columnIndex );
+ checkRowIndex();
+ sal_Int16 i = 0;
+ convertTo( getValue( columnIndex ), cppu::UnoType<decltype(i)>::get()) >>= i;
+ return i;
+}
+
+OUString BaseResultSet::getString( sal_Int32 columnIndex )
+{
+ MutexGuard guard(m_xMutex->GetMutex());
+ checkClosed();
+ checkColumnIndex( columnIndex );
+ checkRowIndex();
+ OUString ret;
+ convertTo( getValue( columnIndex ), cppu::UnoType<decltype(ret)>::get() ) >>= ret;
+// printf( "BaseResultSet::getString() %s\n" , OUStringToOString( ret, RTL_TEXTENCODING_ASCII_US ).getStr() );
+ return ret;
+}
+
+sal_Int32 BaseResultSet::getInt( sal_Int32 columnIndex )
+{
+ MutexGuard guard( m_xMutex->GetMutex() );
+ checkClosed();
+ checkColumnIndex( columnIndex );
+ checkRowIndex();
+ sal_Int32 i = 0;
+ convertTo( getValue( columnIndex ), cppu::UnoType<decltype(i)>::get()) >>= i;
+ return i;
+}
+
+sal_Int64 BaseResultSet::getLong( sal_Int32 columnIndex )
+{
+ MutexGuard guard( m_xMutex->GetMutex() );
+ checkClosed();
+ checkColumnIndex( columnIndex );
+ checkRowIndex();
+ sal_Int64 i = 0;
+ convertTo( getValue( columnIndex ), cppu::UnoType<decltype(i)>::get()) >>= i;
+ return i;
+}
+
+float BaseResultSet::getFloat( sal_Int32 columnIndex )
+{
+ MutexGuard guard( m_xMutex->GetMutex() );
+ checkClosed();
+ checkColumnIndex( columnIndex );
+ checkRowIndex();
+ float f = 0.;
+ convertTo( getValue( columnIndex ), cppu::UnoType<decltype(f)>::get()) >>= f;
+ return f;
+}
+
+double BaseResultSet::getDouble( sal_Int32 columnIndex )
+{
+ MutexGuard guard( m_xMutex->GetMutex() );
+ checkClosed();
+ checkColumnIndex( columnIndex );
+ double d = 0.;
+ convertTo( getValue( columnIndex ), cppu::UnoType<decltype(d)>::get()) >>= d;
+ return d;
+}
+
+Sequence< sal_Int8 > BaseResultSet::getBytes( sal_Int32 columnIndex )
+{
+ MutexGuard guard( m_xMutex->GetMutex() );
+ checkClosed();
+ checkColumnIndex( columnIndex );
+ checkRowIndex();
+
+ Sequence< sal_Int8 > ret;
+ OUString ustr;
+ if( ! (getValue( columnIndex ) >>= ustr) )
+ m_wasNull = true;
+ else
+ {
+ // if this is a binary, it must contain escaped data !
+ OString val = OUStringToOString( ustr, RTL_TEXTENCODING_ASCII_US );
+
+ size_t length;
+ char * res = reinterpret_cast<char*>(PQunescapeBytea( reinterpret_cast<unsigned char const *>(val.getStr()), &length));
+ ret = Sequence< sal_Int8 > ( reinterpret_cast<sal_Int8*>(res), length );
+ if( res )
+ PQfreemem( res );
+ }
+ return ret;
+}
+
+
+css::util::Date BaseResultSet::getDate( sal_Int32 columnIndex )
+{
+ return DBTypeConversion::toDate( getString( columnIndex ) );
+}
+
+css::util::Time BaseResultSet::getTime( sal_Int32 columnIndex )
+{
+ return DBTypeConversion::toTime( getString( columnIndex ) );
+}
+
+css::util::DateTime BaseResultSet::getTimestamp( sal_Int32 columnIndex )
+{
+ return DBTypeConversion::toDateTime( getString( columnIndex ) );
+}
+
+ // LEM TODO: these look like they are missing an actual implementation
+Reference< css::io::XInputStream > BaseResultSet::getBinaryStream( sal_Int32 /* columnIndex */ )
+{
+ return nullptr;
+}
+
+Reference< css::io::XInputStream > BaseResultSet::getCharacterStream( sal_Int32 /* columnIndex */ )
+{
+ return nullptr;
+}
+
+Any BaseResultSet::getObject(
+ sal_Int32 /* columnIndex */,
+ const Reference< css::container::XNameAccess >& /* typeMap */ )
+{
+ return Any();
+}
+
+Reference< css::sdbc::XRef > BaseResultSet::getRef( sal_Int32 /* columnIndex */ )
+{
+ return Reference< css::sdbc::XRef > ();
+}
+
+Reference< css::sdbc::XBlob > BaseResultSet::getBlob( sal_Int32 /* columnIndex */ )
+{
+ return Reference< css::sdbc::XBlob > ();
+}
+
+Reference< css::sdbc::XClob > BaseResultSet::getClob( sal_Int32 /* columnIndex */ )
+{
+ return Reference< css::sdbc::XClob > ();
+}
+
+Reference< css::sdbc::XArray > BaseResultSet::getArray( sal_Int32 columnIndex )
+{
+ return new Array( m_xMutex, parseArray( getString( columnIndex ) ), *this, m_tc );
+}
+
+::cppu::IPropertyArrayHelper & BaseResultSet::getInfoHelper()
+{
+ return getResultSetPropertyArrayHelper();
+}
+
+sal_Bool BaseResultSet::convertFastPropertyValue(
+ Any & /* rConvertedValue */, Any & /* rOldValue */, sal_Int32 nHandle, const Any& rValue )
+{
+ bool bRet;
+ switch( nHandle )
+ {
+ case BASERESULTSET_CURSOR_NAME:
+ {
+ OUString val;
+ bRet = ( rValue >>= val );
+ m_props[nHandle] <<= val;
+ break;
+ }
+ case BASERESULTSET_ESCAPE_PROCESSING:
+ case BASERESULTSET_IS_BOOKMARKABLE:
+ {
+ bool val(false);
+ bRet = ( rValue >>= val );
+ m_props[nHandle] <<= val;
+ break;
+ }
+ case BASERESULTSET_FETCH_DIRECTION:
+ case BASERESULTSET_FETCH_SIZE:
+ case BASERESULTSET_RESULT_SET_CONCURRENCY:
+ case BASERESULTSET_RESULT_SET_TYPE:
+ {
+ sal_Int32 val;
+ bRet = ( rValue >>= val );
+ m_props[nHandle] <<= val;
+ break;
+ }
+ default:
+ {
+ throw IllegalArgumentException(
+ "pq_resultset: Invalid property handle (" + OUString::number( nHandle ) + ")",
+ *this, 2 );
+ }
+ }
+ return bRet;
+}
+
+
+void BaseResultSet::setFastPropertyValue_NoBroadcast(
+ sal_Int32 nHandle,const Any& rValue )
+{
+ m_props[nHandle] = rValue;
+}
+
+void BaseResultSet::getFastPropertyValue( Any& rValue, sal_Int32 nHandle ) const
+{
+ rValue = m_props[nHandle];
+}
+
+Reference < XPropertySetInfo > BaseResultSet::getPropertySetInfo()
+{
+ return OPropertySetHelper::createPropertySetInfo( getResultSetPropertyArrayHelper() );
+}
+
+void BaseResultSet::disposing()
+{
+ close();
+}
+
+void BaseResultSet::checkColumnIndex(sal_Int32 index )
+{
+ if( index < 1 || index > m_fieldCount )
+ {
+ throw SQLException(
+ "pq_resultset: index out of range ("
+ + OUString::number( index )
+ + ", allowed range is 1 to " + OUString::number( m_fieldCount )
+ + ")",
+ *this, OUString(), 1, Any() );
+ }
+
+}
+
+void BaseResultSet::checkRowIndex()
+{
+ if( m_row < 0 || m_row >= m_rowCount )
+ {
+ throw SQLException(
+ "pq_baseresultset: row index out of range, allowed is 0 to " + OUString::number( m_rowCount -1 )
+ + ", got " + OUString::number( m_row ),
+ *this, OUString(),1, Any() );
+ }
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/postgresql/pq_baseresultset.hxx b/connectivity/source/drivers/postgresql/pq_baseresultset.hxx
new file mode 100644
index 0000000000..90e6609a08
--- /dev/null
+++ b/connectivity/source/drivers/postgresql/pq_baseresultset.hxx
@@ -0,0 +1,203 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * Effective License of whole file:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011:
+ *
+ * The Contents of this file are made available subject to the terms of
+ * the GNU Lesser General Public License Version 2.1
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * Contributor(s): Joerg Budischewski
+ *
+ * All parts contributed on or after August 2011:
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ ************************************************************************/
+
+#pragma once
+
+#include <cppuhelper/propshlp.hxx>
+#include <cppuhelper/component.hxx>
+
+#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XCloseable.hpp>
+#include <com/sun/star/sdbc/XColumnLocate.hpp>
+#include "pq_connection.hxx"
+
+namespace pq_sdbc_driver
+{
+
+const sal_Int32 BASERESULTSET_CURSOR_NAME = 0;
+const sal_Int32 BASERESULTSET_ESCAPE_PROCESSING = 1;
+const sal_Int32 BASERESULTSET_FETCH_DIRECTION = 2;
+const sal_Int32 BASERESULTSET_FETCH_SIZE = 3;
+const sal_Int32 BASERESULTSET_IS_BOOKMARKABLE = 4;
+const sal_Int32 BASERESULTSET_RESULT_SET_CONCURRENCY = 5;
+const sal_Int32 BASERESULTSET_RESULT_SET_TYPE = 6;
+
+#define BASERESULTSET_SIZE 7
+
+typedef ::cppu::WeakComponentImplHelper< css::sdbc::XCloseable,
+ css::sdbc::XResultSetMetaDataSupplier,
+ css::sdbc::XResultSet,
+ css::sdbc::XRow,
+ css::sdbc::XColumnLocate
+ > BaseResultSet_BASE;
+class BaseResultSet : public BaseResultSet_BASE,
+ public cppu::OPropertySetHelper
+{
+protected:
+ css::uno::Any m_props[BASERESULTSET_SIZE];
+ css::uno::Reference< css::uno::XInterface > m_owner;
+ css::uno::Reference< css::script::XTypeConverter > m_tc;
+ ::rtl::Reference< comphelper::RefCountedMutex > m_xMutex;
+ sal_Int32 m_row;
+ sal_Int32 m_rowCount;
+ sal_Int32 m_fieldCount;
+ bool m_wasNull;
+
+protected:
+ /** mutex should be locked before called
+
+ @throws css::sdbc::SQLException
+ @throws css::uno::RuntimeException
+ */
+ virtual void checkClosed() = 0;
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void checkColumnIndex( sal_Int32 index );
+ void checkRowIndex();
+
+ virtual css::uno::Any getValue( sal_Int32 columnIndex ) = 0;
+ css::uno::Any convertTo(
+ const css::uno::Any &str, const css::uno::Type &type );
+
+protected:
+ BaseResultSet(
+ const ::rtl::Reference< comphelper::RefCountedMutex > & mutex,
+ const css::uno::Reference< css::uno::XInterface > &owner,
+ sal_Int32 rowCount,
+ sal_Int32 columnCount,
+ const css::uno::Reference< css::script::XTypeConverter > &tc );
+ virtual ~BaseResultSet() override;
+
+public: // XInterface
+ virtual void SAL_CALL acquire() noexcept override { BaseResultSet_BASE::acquire(); }
+ virtual void SAL_CALL release() noexcept override { BaseResultSet_BASE::release(); }
+ virtual css::uno::Any SAL_CALL queryInterface(
+ const css::uno::Type & reqType ) override;
+
+public: // XCloseable
+// virtual void SAL_CALL close( )
+// throw (css::sdbc::SQLException, css::uno::RuntimeException) = 0;
+
+public: // XTypeProvider, first implemented by OPropertySetHelper
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override;
+ virtual css::uno::Sequence< sal_Int8> SAL_CALL getImplementationId() override;
+
+public: // XResultSetMetaDataSupplier
+// virtual css::uno::Reference< css::sdbc::XResultSetMetaData > SAL_CALL getMetaData( )
+// throw (css::sdbc::SQLException, css::uno::RuntimeException) = 0;
+
+public: // XResultSet
+ // Methods
+ virtual sal_Bool SAL_CALL next( ) override;
+ virtual sal_Bool SAL_CALL isBeforeFirst( ) override;
+ virtual sal_Bool SAL_CALL isAfterLast( ) override;
+ virtual sal_Bool SAL_CALL isFirst( ) override;
+ virtual sal_Bool SAL_CALL isLast( ) override;
+ virtual void SAL_CALL beforeFirst( ) override;
+ virtual void SAL_CALL afterLast( ) override;
+ virtual sal_Bool SAL_CALL first( ) override;
+ virtual sal_Bool SAL_CALL last( ) override;
+ virtual sal_Int32 SAL_CALL getRow( ) override;
+ virtual sal_Bool SAL_CALL absolute( sal_Int32 row ) override;
+ virtual sal_Bool SAL_CALL relative( sal_Int32 rows ) override;
+ virtual sal_Bool SAL_CALL previous( ) override;
+ virtual void SAL_CALL refreshRow( ) override;
+ virtual sal_Bool SAL_CALL rowUpdated( ) override;
+ virtual sal_Bool SAL_CALL rowInserted( ) override;
+ virtual sal_Bool SAL_CALL rowDeleted( ) override;
+ virtual css::uno::Reference< css::uno::XInterface > SAL_CALL getStatement() override;
+
+
+public: // XRow
+ virtual sal_Bool SAL_CALL wasNull( ) override;
+ virtual OUString SAL_CALL getString( sal_Int32 columnIndex ) override;
+ virtual sal_Bool SAL_CALL getBoolean( sal_Int32 columnIndex ) override;
+ virtual sal_Int8 SAL_CALL getByte( sal_Int32 columnIndex ) override;
+ virtual sal_Int16 SAL_CALL getShort( sal_Int32 columnIndex ) override;
+ virtual sal_Int32 SAL_CALL getInt( sal_Int32 columnIndex ) override;
+ virtual sal_Int64 SAL_CALL getLong( sal_Int32 columnIndex ) override;
+ virtual float SAL_CALL getFloat( sal_Int32 columnIndex ) override;
+ virtual double SAL_CALL getDouble( sal_Int32 columnIndex ) override;
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getBytes( sal_Int32 columnIndex ) override;
+ virtual css::util::Date SAL_CALL getDate( sal_Int32 columnIndex ) override;
+ virtual css::util::Time SAL_CALL getTime( sal_Int32 columnIndex ) override;
+ virtual css::util::DateTime SAL_CALL getTimestamp( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getBinaryStream( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getCharacterStream( sal_Int32 columnIndex ) override;
+ virtual css::uno::Any SAL_CALL getObject(
+ sal_Int32 columnIndex,
+ const css::uno::Reference< css::container::XNameAccess >& typeMap ) override;
+ virtual css::uno::Reference< css::sdbc::XRef > SAL_CALL getRef( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XBlob > SAL_CALL getBlob( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XClob > SAL_CALL getClob( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XArray > SAL_CALL getArray( sal_Int32 columnIndex ) override;
+
+public: // XColumnLocate
+// virtual sal_Int32 SAL_CALL findColumn( const OUString& columnName )
+// throw (css::sdbc::SQLException, css::uno::RuntimeException) = 0;
+
+public: // OPropertySetHelper
+ virtual cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override;
+
+ virtual sal_Bool SAL_CALL convertFastPropertyValue(
+ css::uno::Any & rConvertedValue,
+ css::uno::Any & rOldValue,
+ sal_Int32 nHandle,
+ const css::uno::Any& rValue ) override;
+
+ virtual void SAL_CALL setFastPropertyValue_NoBroadcast(
+ sal_Int32 nHandle,
+ const css::uno::Any& rValue ) override;
+
+ using ::cppu::OPropertySetHelper::getFastPropertyValue;
+
+ void SAL_CALL getFastPropertyValue(
+ css::uno::Any& rValue,
+ sal_Int32 nHandle ) const override;
+
+ // XPropertySet
+ css::uno::Reference < css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo() override;
+
+public: // OComponentHelper
+ virtual void SAL_CALL disposing() override;
+
+
+};
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/postgresql/pq_connection.cxx b/connectivity/source/drivers/postgresql/pq_connection.cxx
new file mode 100644
index 0000000000..422d97f76e
--- /dev/null
+++ b/connectivity/source/drivers/postgresql/pq_connection.cxx
@@ -0,0 +1,572 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * Effective License of whole file:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011:
+ *
+ * The Contents of this file are made available subject to the terms of
+ * the GNU Lesser General Public License Version 2.1
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * Contributor(s): Joerg Budischewski
+ *
+ * All parts contributed on or after August 2011:
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ ************************************************************************/
+
+#include <utility>
+#include <vector>
+#include <string.h>
+
+#include <memory>
+
+#include "pq_connection.hxx"
+#include "pq_statement.hxx"
+#include "pq_tools.hxx"
+#include "pq_preparedstatement.hxx"
+#include "pq_databasemetadata.hxx"
+#include "pq_xtables.hxx"
+#include "pq_xviews.hxx"
+#include "pq_xusers.hxx"
+
+#include <rtl/ref.hxx>
+#include <rtl/uuid.h>
+#include <sal/log.hxx>
+
+#include <cppuhelper/implbase.hxx>
+
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/script/Converter.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
+
+using osl::MutexGuard;
+
+using com::sun::star::container::XNameAccess;
+
+using com::sun::star::lang::XComponent;
+using com::sun::star::lang::IllegalArgumentException;
+
+using com::sun::star::script::Converter;
+using com::sun::star::script::XTypeConverter;
+
+using com::sun::star::uno::RuntimeException;
+using com::sun::star::uno::Sequence;
+using com::sun::star::uno::Reference;
+using com::sun::star::uno::XInterface;
+using com::sun::star::uno::UNO_QUERY;
+using com::sun::star::uno::UNO_QUERY_THROW;
+using com::sun::star::uno::XComponentContext;
+using com::sun::star::uno::Any;
+
+using com::sun::star::beans::PropertyValue;
+
+using com::sun::star::sdbc::XCloseable;
+using com::sun::star::sdbc::SQLException;
+using com::sun::star::sdbc::XPreparedStatement;
+using com::sun::star::sdbc::XStatement;
+using com::sun::star::sdbc::XDatabaseMetaData;
+
+namespace pq_sdbc_driver
+{
+
+namespace {
+
+// Helper class for statement lifetime management
+class ClosableReference : public cppu::WeakImplHelper< css::uno::XReference >
+{
+ rtl::Reference<Connection> m_conn;
+ ::rtl::ByteSequence m_id;
+public:
+ ClosableReference( ::rtl::ByteSequence id , Connection *that )
+ : m_conn( that ), m_id(std::move( id ))
+ {
+ }
+
+ virtual void SAL_CALL dispose() override
+ {
+ if( m_conn.is() )
+ {
+ m_conn->removeFromWeakMap(m_id);
+ m_conn.clear();
+ }
+ }
+};
+
+}
+
+Connection::Connection(
+ const rtl::Reference< comphelper::RefCountedMutex > &refMutex,
+ css::uno::Reference< css::uno::XComponentContext > ctx )
+ : ConnectionBase( refMutex->GetMutex() ),
+ m_ctx(std::move( ctx )) ,
+ m_xMutex( refMutex )
+{
+}
+
+Connection::~Connection()
+{
+ if( m_settings.pConnection )
+ {
+ PQfinish( m_settings.pConnection );
+ m_settings.pConnection = nullptr;
+ }
+}
+
+void Connection::close()
+{
+ std::vector< css::uno::Reference< css::sdbc::XCloseable > > vectorCloseable;
+ std::vector< css::uno::Reference< css::lang::XComponent > > vectorDispose;
+ {
+ MutexGuard guard( m_xMutex->GetMutex() );
+ // silently ignore, if the connection has been closed already
+ if( m_settings.pConnection )
+ {
+ SAL_INFO("connectivity.postgresql", "closing connection");
+ PQfinish( m_settings.pConnection );
+ m_settings.pConnection = nullptr;
+ }
+
+ vectorDispose.push_back( Reference< XComponent > ( m_settings.users, UNO_QUERY ) );
+ vectorDispose.push_back( Reference< XComponent > ( m_settings.tables , UNO_QUERY ) );
+ vectorDispose.push_back( Reference< XComponent > ( m_meta, UNO_QUERY ) );
+ m_meta.clear();
+ m_settings.tables.clear();
+ m_settings.users.clear();
+
+ for (auto const& statement : m_myStatements)
+ {
+ Reference< XCloseable > r = statement.second;
+ if( r.is() )
+ vectorCloseable.push_back( r );
+ }
+ }
+
+ // close all created statements
+ for (auto const& elem : vectorCloseable)
+ elem->close();
+
+ // close all created statements
+ for (auto const& elem : vectorDispose)
+ {
+ if( elem.is() )
+ elem->dispose();
+ }
+}
+
+
+void Connection::removeFromWeakMap( const ::rtl::ByteSequence & id )
+{
+ // shrink the list !
+ MutexGuard guard( m_xMutex->GetMutex() );
+ WeakHashMap::iterator ii = m_myStatements.find( id );
+ if( ii != m_myStatements.end() )
+ m_myStatements.erase( ii );
+}
+
+Reference< XStatement > Connection::createStatement()
+{
+ MutexGuard guard( m_xMutex->GetMutex() );
+ checkClosed();
+
+ rtl::Reference<Statement> stmt = new Statement( m_xMutex, this , &m_settings );
+ ::rtl::ByteSequence id( 16 );
+ rtl_createUuid( reinterpret_cast<sal_uInt8*>(id.getArray()), nullptr, false );
+ m_myStatements[ id ] = Reference< XCloseable > ( stmt );
+ stmt->queryAdapter()->addReference( new ClosableReference( id, this ) );
+ return stmt;
+}
+
+Reference< XPreparedStatement > Connection::prepareStatement( const OUString& sql )
+{
+ MutexGuard guard( m_xMutex->GetMutex() );
+ checkClosed();
+
+ OString byteSql = OUStringToOString( sql, ConnectionSettings::encoding );
+ rtl::Reference<PreparedStatement> stmt
+ = new PreparedStatement( m_xMutex, this, &m_settings, byteSql );
+
+ ::rtl::ByteSequence id( 16 );
+ rtl_createUuid( reinterpret_cast<sal_uInt8*>(id.getArray()), nullptr, false );
+ m_myStatements[ id ] = Reference< XCloseable > ( stmt );
+ stmt->queryAdapter()->addReference( new ClosableReference( id, this ) );
+ return stmt;
+}
+
+Reference< XPreparedStatement > Connection::prepareCall( const OUString& )
+{
+ throw SQLException(
+ "pq_driver: Callable statements not supported",
+ Reference< XInterface > (), OUString() , 1, Any() );
+}
+
+
+OUString Connection::nativeSQL( const OUString& sql )
+{
+ return sql;
+}
+
+void Connection::setAutoCommit( sal_Bool )
+{
+ // UNSUPPORTED
+}
+
+sal_Bool Connection::getAutoCommit()
+{
+ // UNSUPPORTED
+ return true;
+}
+
+void Connection::commit()
+{
+ // UNSUPPORTED
+}
+
+void Connection::rollback()
+{
+ // UNSUPPORTED
+}
+
+sal_Bool Connection::isClosed()
+{
+ return m_settings.pConnection == nullptr;
+}
+
+Reference< XDatabaseMetaData > Connection::getMetaData()
+{
+ MutexGuard guard( m_xMutex->GetMutex() );
+ checkClosed();
+ if( ! m_meta.is() )
+ m_meta = new DatabaseMetaData( m_xMutex, this, &m_settings );
+ return m_meta;
+}
+
+void Connection::setReadOnly( sal_Bool )
+{
+ // UNSUPPORTED
+
+}
+
+sal_Bool Connection::isReadOnly()
+{
+ // UNSUPPORTED
+ return false;
+}
+
+void Connection::setCatalog( const OUString& )
+{
+ // UNSUPPORTED
+}
+
+OUString Connection::getCatalog()
+{
+ MutexGuard guard( m_xMutex->GetMutex() );
+ if( m_settings.pConnection == nullptr )
+ {
+ throw SQLException( "pq_connection: connection is closed", *this,
+ OUString(), 1, Any() );
+ }
+ char * p = PQdb(m_settings.pConnection );
+ return OUString( p, strlen(p) , ConnectionSettings::encoding );
+}
+
+void Connection::setTransactionIsolation( sal_Int32 )
+{
+ // UNSUPPORTED
+}
+
+sal_Int32 Connection::getTransactionIsolation()
+{
+ // UNSUPPORTED
+ return 0;
+}
+
+Reference< XNameAccess > Connection::getTypeMap()
+{
+ Reference< XNameAccess > t;
+ {
+ MutexGuard guard( m_xMutex->GetMutex() );
+ t = m_typeMap;
+ }
+ return t;
+}
+
+void Connection::setTypeMap( const Reference< XNameAccess >& typeMap )
+{
+ MutexGuard guard( m_xMutex->GetMutex() );
+ m_typeMap = typeMap;
+}
+Any Connection::getWarnings()
+{
+ return Any();
+}
+
+void Connection::clearWarnings()
+{
+}
+
+namespace {
+
+class cstr_vector
+{
+ std::vector<char*> values;
+ std::vector<bool> acquired;
+public:
+ cstr_vector () { values.reserve(8); acquired.reserve(8); }
+ ~cstr_vector ()
+ {
+ OSL_ENSURE(values.size() == acquired.size(), "pq_connection: cstr_vector values and acquired size mismatch");
+ std::vector<bool>::const_iterator pa = acquired.begin();
+ for( const auto& v : values )
+ {
+ if (*pa)
+ free(v);
+ ++pa;
+ }
+ }
+ void push_back(const char* s, __sal_NoAcquire)
+ {
+ values.push_back(const_cast<char*>(s));
+ acquired.push_back(false);
+ }
+ void push_back(char* s)
+ {
+ values.push_back(s);
+ acquired.push_back(true);
+ }
+ // This const_cast is there for compatibility with PostgreSQL <= 9.1;
+ // PostgreSQL >= 9.2 has the right const qualifiers in the headers
+ // for a return type of "char const*const*".
+ char const** c_array() const { return const_cast <const char**>(values.data()); }
+};
+
+}
+
+static void properties2arrays( const Sequence< PropertyValue > & args,
+ const Reference< XTypeConverter> &tc,
+ rtl_TextEncoding enc,
+ cstr_vector &keywords,
+ cstr_vector &values)
+{
+ // LEM TODO: can we just blindly take all properties?
+ // I.e. they are prefiltered to have only relevant ones?
+ // Else, at least support all keywords from
+ // http://www.postgresql.org/docs/9.0/interactive/libpq-connect.html
+
+ static const char* keyword_list[] = {
+ "password",
+ "user",
+ "port",
+ "dbname",
+ "connect_timeout",
+ "options",
+ "requiressl"
+ };
+
+ for( PropertyValue const & prop : args )
+ {
+ bool append = false;
+ for(const char* j : keyword_list)
+ {
+ if( prop.Name.equalsIgnoreAsciiCaseAscii( j ))
+ {
+ keywords.push_back( j, SAL_NO_ACQUIRE );
+ append = true;
+ break;
+ }
+ }
+
+ if( append )
+ {
+ OUString value;
+ tc->convertTo( prop.Value, cppu::UnoType<decltype(value)>::get() ) >>= value;
+ char *v = strdup(OUStringToOString(value, enc).getStr());
+ values.push_back ( v );
+ }
+ else
+ {
+ // ignore for now
+ SAL_WARN("connectivity.postgresql", "sdbc-postgresql: unknown argument '" << prop.Name << "' having value: " << prop.Value );
+ }
+ }
+}
+
+void Connection::initialize( const Sequence< Any >& aArguments )
+{
+ OUString url;
+ Sequence< PropertyValue > args;
+
+ Reference< XTypeConverter > tc( Converter::create(m_ctx) );
+ if( ! tc.is() )
+ {
+ throw RuntimeException(
+ "pq_driver: Couldn't instantiate converter service" );
+ }
+ if( aArguments.getLength() != 2 )
+ {
+ throw IllegalArgumentException(
+ "pq_driver: expected 2 arguments, got " + OUString::number( aArguments.getLength( ) ),
+ Reference< XInterface > () , 0 );
+ }
+
+ if( ! (aArguments[0] >>= url) )
+ {
+ throw IllegalArgumentException(
+ "pq_driver: expected string as first argument, got "
+ + aArguments[0].getValueType().getTypeName(),
+ *this, 0 );
+ }
+
+ tc->convertTo( aArguments[1], cppu::UnoType<decltype(args)>::get() ) >>= args;
+
+ OString o;
+ int nColon = url.indexOf( ':' );
+ if( nColon != -1 )
+ {
+ nColon = url.indexOf( ':' , 1+ nColon );
+ if( nColon != -1 )
+ {
+ o = rtl::OUStringToOString( url.subView(nColon+1), ConnectionSettings::encoding );
+ }
+ }
+ {
+ cstr_vector keywords;
+ cstr_vector values;
+
+ if ( o.getLength() > 0 )
+ {
+ char *err;
+ const std::unique_ptr<PQconninfoOption, deleter_from_fn<PQconninfoFree>>
+ oOpts(PQconninfoParse(o.getStr(), &err));
+ if (oOpts == nullptr)
+ {
+ OUString errorMessage;
+ if ( err != nullptr)
+ {
+ errorMessage = OUString( err, strlen(err), ConnectionSettings::encoding );
+ PQfreemem(err);
+ }
+ else
+ errorMessage = "#no error message#";
+ // HY092 is "Invalid attribute/option identifier."
+ // Just the most likely error; the error might be HY024 "Invalid attribute value".
+ throw SQLException(
+ "Error in database URL '" + url + "':\n" + errorMessage,
+ *this, "HY092", 5, Any() );
+ }
+
+ for ( PQconninfoOption * opt = oOpts.get(); opt->keyword != nullptr; ++opt)
+ {
+ if ( opt->val != nullptr )
+ {
+ keywords.push_back(strdup(opt->keyword));
+ values.push_back(strdup(opt->val));
+ }
+ }
+ }
+ properties2arrays( args , tc, ConnectionSettings::encoding, keywords, values );
+ keywords.push_back(nullptr, SAL_NO_ACQUIRE);
+ values.push_back(nullptr, SAL_NO_ACQUIRE);
+
+ m_settings.pConnection = PQconnectdbParams( keywords.c_array(), values.c_array(), 0 );
+ }
+ if( ! m_settings.pConnection )
+ throw RuntimeException("pq_driver: out of memory" );
+ if( PQstatus( m_settings.pConnection ) == CONNECTION_BAD )
+ {
+ const char * error = PQerrorMessage( m_settings.pConnection );
+ OUString errorMessage( error, strlen( error) , RTL_TEXTENCODING_ASCII_US );
+ PQfinish( m_settings.pConnection );
+ m_settings.pConnection = nullptr;
+ throw SQLException(
+ "Couldn't establish database connection to '" + url + "'\n"
+ + errorMessage,
+ *this, errorMessage, CONNECTION_BAD, Any() );
+ }
+ PQsetClientEncoding( m_settings.pConnection, "UNICODE" );
+ char *p = PQuser( m_settings.pConnection );
+ m_settings.user = OUString( p, strlen(p), RTL_TEXTENCODING_UTF8);
+ p = PQdb( m_settings.pConnection );
+ m_settings.catalog = OUString( p, strlen(p), RTL_TEXTENCODING_UTF8);
+ m_settings.tc = tc;
+
+ SAL_INFO("connectivity.postgresql", "connection to '" << url << "' successfully opened");
+}
+
+void Connection::disposing()
+{
+ close();
+}
+
+void Connection::checkClosed()
+{
+ if( !m_settings.pConnection )
+ throw SQLException( "pq_connection: Connection already closed",
+ *this, OUString(), 1, Any() );
+}
+
+Reference< XNameAccess > Connection::getTables()
+{
+ SAL_INFO("connectivity.postgresql", "Connection::getTables() got called");
+ MutexGuard guard( m_xMutex->GetMutex() );
+ if( !m_settings.tables.is() )
+ m_settings.tables = Tables::create( m_xMutex, this, &m_settings , &m_settings.pTablesImpl);
+ else
+ // TODO: how to overcome the performance problem ?
+ Reference< css::util::XRefreshable > ( m_settings.tables, UNO_QUERY_THROW )->refresh();
+ return m_settings.tables;
+}
+
+Reference< XNameAccess > Connection::getViews()
+{
+ SAL_INFO("connectivity.postgresql", "Connection::getViews() got called");
+ MutexGuard guard( m_xMutex->GetMutex() );
+ if( !m_settings.views.is() )
+ m_settings.views = Views::create( m_xMutex, this, &m_settings, &(m_settings.pViewsImpl) );
+ else
+ // TODO: how to overcome the performance problem ?
+ Reference< css::util::XRefreshable > ( m_settings.views, UNO_QUERY_THROW )->refresh();
+ return m_settings.views;
+}
+
+
+Reference< XNameAccess > Connection::getUsers()
+{
+ SAL_INFO("connectivity.postgresql", "Connection::getUsers() got called");
+
+ MutexGuard guard( m_xMutex->GetMutex() );
+ if( !m_settings.users.is() )
+ m_settings.users = Users::create( m_xMutex, this, &m_settings );
+ return m_settings.users;
+}
+
+} // end namespace
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+connectivity_postgresql_Connection_get_implementation(
+ css::uno::XComponentContext* context , css::uno::Sequence<css::uno::Any> const&)
+{
+ ::rtl::Reference< comphelper::RefCountedMutex > ref = new comphelper::RefCountedMutex;
+ return cppu::acquire(new pq_sdbc_driver::Connection( ref, context ));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/postgresql/pq_connection.hxx b/connectivity/source/drivers/postgresql/pq_connection.hxx
new file mode 100644
index 0000000000..2bba070a72
--- /dev/null
+++ b/connectivity/source/drivers/postgresql/pq_connection.hxx
@@ -0,0 +1,194 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * Effective License of whole file:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011:
+ *
+ * The Contents of this file are made available subject to the terms of
+ * the GNU Lesser General Public License Version 2.1
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * Contributor(s): Joerg Budischewski
+ *
+ * All parts contributed on or after August 2011:
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ ************************************************************************/
+
+#pragma once
+
+#include <config_lgpl.h>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/script/XTypeConverter.hpp>
+#include <com/sun/star/sdbc/XWarningsSupplier.hpp>
+#include <com/sun/star/sdbcx/XTablesSupplier.hpp>
+#include <com/sun/star/sdbcx/XUsersSupplier.hpp>
+#include <com/sun/star/sdbcx/XViewsSupplier.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+
+#include <com/sun/star/container/XNameAccess.hpp>
+
+#include <rtl/ref.hxx>
+#include <rtl/byteseq.hxx>
+
+#include <comphelper/refcountedmutex.hxx>
+
+#include <cppuhelper/weakref.hxx>
+#include <cppuhelper/compbase.hxx>
+#include <functional>
+
+#include <libpq-fe.h>
+#include <unordered_map>
+
+#include "pq_xtables.hxx"
+#include "pq_xviews.hxx"
+
+namespace pq_sdbc_driver
+{
+struct ConnectionSettings;
+struct ConnectionSettings
+{
+ ConnectionSettings() :
+ pConnection(nullptr),
+ maxNameLen(0),
+ maxIndexKeys(0)
+ {}
+ static const rtl_TextEncoding encoding = RTL_TEXTENCODING_UTF8;
+ PGconn *pConnection;
+ sal_Int32 maxNameLen;
+ sal_Int32 maxIndexKeys;
+ css::uno::Reference< css::script::XTypeConverter > tc;
+ css::uno::Reference< css::container::XNameAccess > tables;
+ css::uno::Reference< css::container::XNameAccess > users;
+ css::uno::Reference< css::container::XNameAccess > views;
+ rtl::Reference<Tables> pTablesImpl; // needed to implement renaming of tables / views
+ rtl::Reference<Views> pViewsImpl; // needed to implement renaming of tables / views
+ OUString user;
+ OUString catalog;
+};
+
+
+typedef cppu::WeakComponentImplHelper<
+ css::sdbc::XConnection,
+ css::sdbc::XWarningsSupplier,
+ css::lang::XInitialization,
+ css::sdbcx::XTablesSupplier,
+ css::sdbcx::XViewsSupplier,
+ css::sdbcx::XUsersSupplier > ConnectionBase;
+
+// some types
+struct HashByteSequence
+{
+ sal_Int32 operator () ( const ::rtl::ByteSequence & seq ) const
+ {
+ return *reinterpret_cast<sal_Int32 const *>(seq.getConstArray());
+ }
+};
+
+typedef std::unordered_map<
+ ::rtl::ByteSequence,
+ css::uno::WeakReference< css::sdbc::XCloseable >,
+ HashByteSequence > WeakHashMap;
+
+
+typedef std::unordered_map
+<
+ sal_Int32,
+ OUString
+> Int2StringMap;
+
+class Connection : public ConnectionBase
+{
+ css::uno::Reference< css::uno::XComponentContext > m_ctx;
+ css::uno::Reference< css::container::XNameAccess > m_typeMap;
+ ConnectionSettings m_settings;
+ ::rtl::Reference< comphelper::RefCountedMutex > m_xMutex;
+ css::uno::Reference< css::sdbc::XDatabaseMetaData > m_meta;
+ WeakHashMap m_myStatements;
+
+private:
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void checkClosed();
+
+public:
+ Connection(
+ const rtl::Reference< comphelper::RefCountedMutex > &refMutex,
+ css::uno::Reference< css::uno::XComponentContext > ctx );
+
+ virtual ~Connection( ) override;
+
+public: // XCloseable
+ virtual void SAL_CALL close() override;
+
+public: // XConnection
+
+ virtual css::uno::Reference< css::sdbc::XStatement > SAL_CALL createStatement( ) override ;
+ virtual css::uno::Reference< css::sdbc::XPreparedStatement > SAL_CALL prepareStatement(
+ const OUString& sql ) override;
+ virtual css::uno::Reference< css::sdbc::XPreparedStatement > SAL_CALL prepareCall(
+ const OUString& sql ) override;
+ virtual OUString SAL_CALL nativeSQL( const OUString& sql ) override;
+ virtual void SAL_CALL setAutoCommit( sal_Bool autoCommit ) override;
+ virtual sal_Bool SAL_CALL getAutoCommit( ) override;
+ virtual void SAL_CALL commit( ) override;
+ virtual void SAL_CALL rollback( ) override;
+ virtual sal_Bool SAL_CALL isClosed( ) override;
+ virtual css::uno::Reference< css::sdbc::XDatabaseMetaData > SAL_CALL getMetaData( ) override;
+ virtual void SAL_CALL setReadOnly( sal_Bool readOnly ) override;
+ virtual sal_Bool SAL_CALL isReadOnly( ) override;
+ virtual void SAL_CALL setCatalog( const OUString& catalog ) override;
+ virtual OUString SAL_CALL getCatalog( ) override;
+ virtual void SAL_CALL setTransactionIsolation( sal_Int32 level ) override;
+ virtual sal_Int32 SAL_CALL getTransactionIsolation( ) override;
+ virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getTypeMap( ) override;
+ virtual void SAL_CALL setTypeMap(
+ const css::uno::Reference< css::container::XNameAccess >& typeMap ) override;
+
+public: // XWarningsSupplier
+ virtual css::uno::Any SAL_CALL getWarnings( ) override;
+ virtual void SAL_CALL clearWarnings( ) override;
+
+public: // XInitialization
+ virtual void SAL_CALL initialize(
+ const css::uno::Sequence< css::uno::Any >& aArguments ) override;
+
+public: // XTablesSupplier
+ virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getTables( ) override;
+
+public: // XUsersSupplier
+ virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getUsers( ) override;
+
+public: // XViewsSupplier
+ virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getViews( ) override;
+
+public:
+ virtual void SAL_CALL disposing() override;
+
+public: // helper function
+ void removeFromWeakMap( const ::rtl::ByteSequence & seq );
+};
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/postgresql/pq_databasemetadata.cxx b/connectivity/source/drivers/postgresql/pq_databasemetadata.cxx
new file mode 100644
index 0000000000..1fbcb1aa69
--- /dev/null
+++ b/connectivity/source/drivers/postgresql/pq_databasemetadata.cxx
@@ -0,0 +1,2511 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * Effective License of whole file:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011:
+ *
+ * The Contents of this file are made available subject to the terms of
+ * the GNU Lesser General Public License Version 2.1
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * Contributor(s): Joerg Budischewski
+ *
+ * All parts contributed on or after August 2011:
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * Some portions were adapted from JDBC PostgreSQL driver:
+ *
+ * Copyright (c) 2004-2008, PostgreSQL Global Development Group
+ *
+ * Licence of original JDBC driver code:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of the PostgreSQL Global Development Group nor the names
+ * of its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ************************************************************************/
+
+#include <algorithm>
+#include <string_view>
+
+#include <sal/log.hxx>
+#include "pq_databasemetadata.hxx"
+#include "pq_driver.hxx"
+#include "pq_sequenceresultset.hxx"
+#include "pq_statics.hxx"
+#include "pq_tools.hxx"
+
+#include <o3tl/string_view.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <sal/macros.h>
+#include <com/sun/star/sdbc/TransactionIsolation.hpp>
+#include <com/sun/star/sdbc/ResultSetType.hpp>
+#include <com/sun/star/sdbc/XParameters.hpp>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <com/sun/star/sdbc/IndexType.hpp>
+#include <com/sun/star/sdbc/ColumnValue.hpp>
+#include <com/sun/star/sdbc/ColumnSearch.hpp>
+#include <utility>
+
+using ::osl::MutexGuard;
+
+
+using namespace com::sun::star::sdbc;
+
+using com::sun::star::uno::Reference;
+using com::sun::star::uno::Sequence;
+using com::sun::star::uno::Any;
+using com::sun::star::uno::UNO_QUERY;
+using com::sun::star::uno::UNO_QUERY_THROW;
+
+namespace pq_sdbc_driver
+{
+// These are pre-processor versions of KeyRule.idl declarations
+// These are inherited from JDBC, and thus won't change anytime soon.
+// Having them as pre-processor definitions allows to include them
+// into compile-time strings (through SAL_STRINGIFY), which can be passed to ASCII_STR.
+// That is without resorting to horrendous hacks in template meta-programming.
+#define KEYRULE_CASCADE 0
+#define KEYRULE_RESTRICT 1
+#define KEYRULE_SET_NULL 2
+#define KEYRULE_NO_ACTION 4
+#define KEYRULE_SET_DEFAULT 4
+// Ditto for Deferrability.idl
+#define DEFERRABILITY_INITIALLY_DEFERRED 5
+#define DEFERRABILITY_INITIALLY_IMMEDIATE 6
+#define DEFERRABILITY_NONE 7
+
+DatabaseMetaData::DatabaseMetaData(
+ ::rtl::Reference< comphelper::RefCountedMutex > refMutex,
+ css::uno::Reference< css::sdbc::XConnection > origin,
+ ConnectionSettings *pSettings )
+ : m_xMutex(std::move( refMutex )),
+ m_pSettings( pSettings ),
+ m_origin(std::move( origin )),
+ m_getIntSetting_stmt ( m_origin->prepareStatement("SELECT setting FROM pg_catalog.pg_settings WHERE name=?") )
+{
+ init_getReferences_stmt();
+ init_getPrivs_stmt();
+}
+
+sal_Bool DatabaseMetaData::allProceduresAreCallable( )
+{
+ // TODO
+ return false;
+}
+
+sal_Bool DatabaseMetaData::allTablesAreSelectable( )
+{
+ return true;
+}
+
+OUString DatabaseMetaData::getURL( )
+{
+ // TODO
+ // LEM TODO: implement
+ return OUString();
+}
+
+OUString DatabaseMetaData::getUserName( )
+{
+ return m_pSettings->user;
+}
+
+sal_Bool DatabaseMetaData::isReadOnly( )
+{
+ return false;
+}
+
+
+sal_Bool DatabaseMetaData::nullsAreSortedHigh( )
+{
+ // Whether NULL values are considered, for sorting purposes, LARGER than any other value.
+ // Specification: http://download.oracle.com/javase/6/docs/api/java/sql/DatabaseMetaData.html#nullsAreSortedHigh()
+ // PostgreSQL behaviour: http://www.postgresql.org/docs/9.1/static/queries-order.html
+ return true;
+}
+
+sal_Bool DatabaseMetaData::nullsAreSortedLow( )
+{
+ return ! nullsAreSortedHigh();
+}
+
+sal_Bool DatabaseMetaData::nullsAreSortedAtStart( )
+{
+ return false;
+}
+
+sal_Bool DatabaseMetaData::nullsAreSortedAtEnd( )
+{
+ return false;
+}
+
+OUString DatabaseMetaData::getDatabaseProductName( )
+{
+ return "PostgreSQL";
+}
+
+OUString DatabaseMetaData::getDatabaseProductVersion( )
+{
+ return OUString::createFromAscii( PQparameterStatus( m_pSettings->pConnection, "server_version" ) );
+}
+OUString DatabaseMetaData::getDriverName( )
+{
+ return "postgresql-sdbc";
+}
+
+OUString DatabaseMetaData::getDriverVersion( )
+{
+ return PQ_SDBC_DRIVER_VERSION;
+}
+
+sal_Int32 DatabaseMetaData::getDriverMajorVersion( )
+{
+ return PQ_SDBC_MAJOR;
+}
+
+sal_Int32 DatabaseMetaData::getDriverMinorVersion( )
+{
+ return PQ_SDBC_MINOR;
+}
+
+sal_Bool DatabaseMetaData::usesLocalFiles( )
+{
+ // LEM TODO:
+ // https://wiki.documentfoundation.org/Documentation/DevGuide/Database_Access#XDatabaseMetaData_Interface
+ // says "Returns true when the catalog name of the
+ // database should not appear in the DatasourceBrowser
+ // of LibreOffice API, otherwise false is returned."
+ // So, hmmm, think about it.
+ return false;
+}
+
+sal_Bool DatabaseMetaData::usesLocalFilePerTable( )
+{
+ return false;
+}
+
+sal_Bool DatabaseMetaData::supportsMixedCaseIdentifiers( )
+{
+ return false;
+}
+
+sal_Bool DatabaseMetaData::storesUpperCaseIdentifiers( )
+{
+ return false;
+}
+
+sal_Bool DatabaseMetaData::storesLowerCaseIdentifiers( )
+{
+ return true;
+}
+
+
+sal_Bool DatabaseMetaData::storesMixedCaseIdentifiers( )
+{
+ return false;
+}
+
+
+sal_Bool DatabaseMetaData::supportsMixedCaseQuotedIdentifiers( )
+{
+ return true;
+}
+
+sal_Bool DatabaseMetaData::storesUpperCaseQuotedIdentifiers( )
+{
+ return false;
+}
+
+
+sal_Bool DatabaseMetaData::storesLowerCaseQuotedIdentifiers( )
+{
+ return false;
+}
+
+
+sal_Bool DatabaseMetaData::storesMixedCaseQuotedIdentifiers( )
+{
+ return false;
+}
+
+
+OUString DatabaseMetaData::getIdentifierQuoteString( )
+{
+ return "\"";
+}
+
+OUString DatabaseMetaData::getSQLKeywords( )
+{
+ // In Java 6, this is all keywords that are not SQL:2003
+ // In Java 2 v1.4 and as per LibreOffice SDK doc, this is all keywords that are not SQL92
+ // I understand this to mean "reserved keywords" only.
+ // See http://www.postgresql.org/docs/current/static/sql-keywords-appendix.html
+ // LEM TODO: consider using pg_get_keywords(), filter on catcode
+ return
+ "ANALYSE,"
+ "ANALYZE,"
+ "ARRAY," //SQL:1999
+ "ASYMMETRIC," //SQL:2003
+ "BINARY," //SQL:1999
+ "CONCURRENTLY,"
+ "CURRENT_CATALOG," //SQL:2008
+ "CURRENT_ROLE," //SQL:1999
+ "CURRENT_SCHEMA," //SQL:2008
+ "DO,"
+ "FREEZE,"
+ "ILIKE,"
+ "ISNULL,"
+ "LIMIT," //SQL:1999; non-reserved in SQL:2003
+ "LOCALTIME," //SQL:1999
+ "LOCALTIMESTAMP," //SQL:1999
+ "NOTNULL,"
+ "OFFSET," //SQL:2008
+ "OVER," //SQL:2003
+ "PLACING," //non-reserved in SQL:2003
+ "RETURNING," //non-reserved in SQL:2008
+ "SIMILAR," //SQL:2003
+ "VARIADIC,"
+ "VERBOSE,"
+ "WINDOW" //SQL:2003
+ ;
+}
+OUString DatabaseMetaData::getNumericFunctions( )
+{
+ // See https://www.postgresql.org/docs/9.1/static/functions-math.html
+ // LEM TODO: Err... https://wiki.documentfoundation.org/Documentation/DevGuide/Database_Access#Support_Scalar_Functions
+ // says this should be "Open Group CLI" names, not PostgreSQL names.
+ // Currently this is just a list of supported functions in PostgreSQL, with PostgreSQL names.
+ // And it is my job to map from Open Group CLI names/syntax to PostgreSQL names/syntax. Where? By parsing the SQL???
+ // Should look at what the JDBC driver is doing.
+ return
+ "abs,"
+ "cbrt,"
+ "ceil,"
+ "ceiling,"
+ "degrees,"
+ "div,"
+ "exp,"
+ "floor,"
+ "ln,"
+ "log,"
+ "mod,"
+ "pi,"
+ "power,"
+ "radians,"
+ "random,"
+ "round,"
+ "setseed,"
+ "sign,"
+ "sqrt,"
+ "trunc,"
+ "width_bucket,"
+ "acos,"
+ "asin,"
+ "atan,"
+ "atan2,"
+ "cos,"
+ "cot,"
+ "sin,"
+ "tan"
+ ;
+}
+
+OUString DatabaseMetaData::getStringFunctions( )
+{
+ // See http://www.postgresql.org/docs/9.1/static/functions-string.html
+ return
+ "bit_length,"
+ "char_length,"
+ "character_length,"
+ "lower,"
+ "octet_length,"
+ "overlay,"
+ "position,"
+ "substring,"
+ "trim,"
+ "upper,"
+ "ascii,"
+ "btrim,"
+ "chr,"
+ "concat,"
+ "concat_ws,"
+ "convert,"
+ "convert_from,"
+ "convert_to,"
+ "decode,"
+ "encode,"
+ "format,"
+ "initcap,"
+ "left,"
+ "length,"
+ "lpad,"
+ "ltrim,"
+ "md5,"
+ "pg_client_encoding,"
+ "quote_ident,"
+ "quote_literal,"
+ "quote_nullable,"
+ "regexp_matches,"
+ "regexp_replace,"
+ "regexp_split_to_array,"
+ "regexp_split_to_table,"
+ "repeat,"
+ "replace,"
+ "reverse,"
+ "right,"
+ "rpad,"
+ "rtrim,"
+ "split_part,"
+ "strpos,"
+ "substr,"
+ "to_ascii,"
+ "to_hex,"
+ "translate"
+ ;
+}
+
+OUString DatabaseMetaData::getSystemFunctions( )
+{
+ // See http://www.postgresql.org/docs/9.1/static/functions-info.html
+ // and http://www.postgresql.org/docs/9.1/static/functions-admin.html
+ return
+ "current_catalog,"
+ "current_database,"
+ "current_query,"
+ "current_schema,"
+ "current_schemas,"
+ "current_user,"
+ "inet_client_addr,"
+ "inet_client_port,"
+ "inet_server_addr,"
+ "inet_server_port,"
+ "pg_backend_pid,"
+ "pg_conf_load_time,"
+ "pg_is_other_temp_schema,"
+ "pg_listening_channels,"
+ "pg_my_temp_schema,"
+ "pg_postmaster_start_time,"
+ "session_user,"
+ "user,"
+ "version,"
+ "has_any_column_privilege,"
+ "has_any_column_privilege,"
+ "has_any_column_privilege,"
+ "has_column_privilege,"
+ "has_database_privilege,"
+ "has_foreign_data_wrapper_privilege,"
+ "has_function_privilege,"
+ "has_language_privilege,"
+ "has_schema_privilege,"
+ "has_sequence_privilege,"
+ "has_server_privilege,"
+ "has_table_privilege,"
+ "has_tablespace_privilege,"
+ "pg_has_role,"
+ "pg_collation_is_visible,"
+ "pg_conversion_is_visible,"
+ "pg_function_is_visible,"
+ "pg_opclass_is_visible,"
+ "pg_operator_is_visible,"
+ "pg_table_is_visible,"
+ "pg_ts_config_is_visible,"
+ "pg_ts_dict_is_visible,"
+ "pg_ts_parser_is_visible,"
+ "pg_ts_template_is_visible,"
+ "pg_type_is_visible,"
+ "format_type,"
+ "pg_describe_object,"
+ "pg_get_constraintdef,"
+ "pg_get_expr,"
+ "pg_get_functiondef,"
+ "pg_get_function_arguments,"
+ "pg_get_function_identity_arguments,"
+ "pg_get_function_result,"
+ "pg_get_indexdef,"
+ "pg_get_keywords,"
+ "pg_get_ruledef,"
+ "pg_get_serial_sequence,"
+ "pg_get_triggerdef,"
+ "pg_get_userbyid,"
+ "pg_get_viewdef,"
+ "pg_options_to_table,"
+ "pg_tablespace_databases,"
+ "pg_typeof,"
+ "col_description,"
+ "obj_description,"
+ "shobj_description,"
+ "txid_current,"
+ "txid_current_snapshot,"
+ "txid_snapshot_xip,"
+ "txid_snapshot_xmax,"
+ "txid_snapshot_xmin,"
+ "txid_visible_in_snapshot,"
+ "xmin,"
+ "xmax,"
+ "xip_list,"
+ "current_setting,"
+ "set_config,"
+ "pg_cancel_backend,"
+ "pg_reload_conf,"
+ "pg_rotate_logfile,"
+ "pg_terminate_backend,"
+ "pg_create_restore_point,"
+ "pg_current_xlog_insert_location,"
+ "pg_current_xlog_location,"
+ "pg_start_backup,"
+ "pg_stop_backup,"
+ "pg_switch_xlog,"
+ "pg_xlogfile_name,"
+ "pg_xlogfile_name_offset,"
+ "pg_is_in_recovery,"
+ "pg_last_xlog_receive_location,"
+ "pg_last_xlog_replay_location,"
+ "pg_last_xact_replay_timestamp,"
+ "pg_is_xlog_replay_paused,"
+ "pg_xlog_replay_pause,"
+ "pg_xlog_replay_resume,"
+ "pg_column_size,"
+ "pg_database_size,"
+ "pg_indexes_size,"
+ "pg_relation_size,"
+ "pg_size_pretty,"
+ "pg_table_size,"
+ "pg_tablespace_size,"
+ "pg_tablespace_size,"
+ "pg_total_relation_size,"
+ "pg_relation_filenode,"
+ "pg_relation_filepath,"
+ "pg_ls_dir,"
+ "pg_read_file,"
+ "pg_read_binary_file,"
+ "pg_stat_file,"
+ "pg_advisory_lock,"
+ "pg_advisory_lock_shared,"
+ "pg_advisory_unlock,"
+ "pg_advisory_unlock_all,"
+ "pg_advisory_unlock_shared,"
+ "pg_advisory_xact_lock,"
+ "pg_advisory_xact_lock_shared,"
+ "pg_try_advisory_lock,"
+ "pg_try_advisory_lock_shared,"
+ "pg_try_advisory_xact_lock,"
+ "pg_try_advisory_xact_lock_shared,"
+ "pg_sleep"
+ ;
+}
+OUString DatabaseMetaData::getTimeDateFunctions( )
+{
+ // TODO
+ return
+ "age,"
+ "age,"
+ "clock_timestamp,"
+ "current_date,"
+ "current_time,"
+ "current_timestamp,"
+ "date_part,"
+ "date_part,"
+ "date_trunc,"
+ "extract,"
+ "extract,"
+ "isfinite,"
+ "isfinite,"
+ "isfinite,"
+ "justify_days,"
+ "justify_hours,"
+ "justify_interval,"
+ "localtime,"
+ "localtimestamp,"
+ "now,"
+ "statement_timestamp,"
+ "timeofday,"
+ "transaction_timestamp,"
+ ;
+}
+OUString DatabaseMetaData::getSearchStringEscape( )
+{
+ return "\\";
+}
+OUString DatabaseMetaData::getExtraNameCharacters( )
+{
+ return "$";
+}
+
+sal_Bool DatabaseMetaData::supportsAlterTableWithAddColumn( )
+{
+ return true;
+}
+
+sal_Bool DatabaseMetaData::supportsAlterTableWithDropColumn( )
+{
+ return true;
+}
+
+sal_Bool DatabaseMetaData::supportsColumnAliasing( )
+{
+ return true;
+}
+
+sal_Bool DatabaseMetaData::nullPlusNonNullIsNull( )
+{
+ return true;
+}
+
+sal_Bool DatabaseMetaData::supportsTypeConversion( )
+{
+ // LEM: this is specifically whether the "CONVERT" function is supported
+ // It seems that in PostgreSQL, that function is only for string encoding, so no.
+ return false;
+}
+
+sal_Bool DatabaseMetaData::supportsConvert( sal_Int32, sal_Int32 )
+{
+ return false;
+}
+
+sal_Bool DatabaseMetaData::supportsTableCorrelationNames( )
+{
+ // LEM: A correlation name is "bar" in "SELECT foo FROM qux [AS] bar WHERE ..."
+ return true;
+}
+
+
+sal_Bool DatabaseMetaData::supportsDifferentTableCorrelationNames( )
+{
+ return false;
+}
+sal_Bool DatabaseMetaData::supportsExpressionsInOrderBy( )
+{
+ return true;
+}
+
+sal_Bool DatabaseMetaData::supportsOrderByUnrelated( )
+{
+ return true;
+}
+
+sal_Bool DatabaseMetaData::supportsGroupBy( )
+{
+ return true;
+}
+
+sal_Bool DatabaseMetaData::supportsGroupByUnrelated( )
+{
+ return true;
+}
+
+sal_Bool DatabaseMetaData::supportsGroupByBeyondSelect( )
+{
+ return true;
+}
+
+sal_Bool DatabaseMetaData::supportsLikeEscapeClause( )
+{
+ return true;
+}
+
+sal_Bool DatabaseMetaData::supportsMultipleResultSets( )
+{
+ return true;
+}
+
+sal_Bool DatabaseMetaData::supportsMultipleTransactions( )
+{
+ // Allows multiple transactions open at once (on different connections!)
+ return true;
+}
+
+sal_Bool DatabaseMetaData::supportsNonNullableColumns( )
+{
+ return true;
+}
+
+
+sal_Bool DatabaseMetaData::supportsMinimumSQLGrammar( )
+{
+ return true;
+}
+
+sal_Bool DatabaseMetaData::supportsCoreSQLGrammar( )
+{
+ // LEM: jdbc driver says not, although the comments in it seem old
+ // fdo#45249 Base query design won't use any aggregate function
+ // (except COUNT(*) unless we say yes, so say yes.
+ // Actually, Base assumes *also* support for aggregate functions "collect, fusion, intersection"
+ // as soon as supportsCoreSQLGrammar() returns true.
+ // Those are *not* Core SQL, though. They are in optional feature S271 "Basic multiset support"
+ return true;
+}
+
+sal_Bool DatabaseMetaData::supportsExtendedSQLGrammar( )
+{
+ return false;
+}
+
+sal_Bool DatabaseMetaData::supportsANSI92EntryLevelSQL( )
+{
+ return true;
+}
+
+sal_Bool DatabaseMetaData::supportsANSI92IntermediateSQL( )
+{
+ // LEM: jdbc driver says not, although the comments in it seem old
+ return false;
+}
+
+sal_Bool DatabaseMetaData::supportsANSI92FullSQL( )
+{
+ // LEM: jdbc driver says not, although the comments in it seem old
+ return false;
+}
+
+sal_Bool DatabaseMetaData::supportsIntegrityEnhancementFacility( )
+{
+ // LEM: jdbc driver says yes, although comment says they are not sure what this means...
+ return true;
+}
+
+sal_Bool DatabaseMetaData::supportsOuterJoins( )
+{
+ return true;
+}
+
+sal_Bool DatabaseMetaData::supportsFullOuterJoins( )
+{
+ return true;
+}
+
+sal_Bool DatabaseMetaData::supportsLimitedOuterJoins( )
+{
+ return true;
+}
+
+
+OUString DatabaseMetaData::getSchemaTerm( )
+{
+ return "SCHEMA";
+}
+
+OUString DatabaseMetaData::getProcedureTerm( )
+{
+ return "function";
+}
+
+OUString DatabaseMetaData::getCatalogTerm( )
+{
+ return "DATABASE";
+}
+
+sal_Bool DatabaseMetaData::isCatalogAtStart( )
+{
+ return true;
+}
+
+OUString DatabaseMetaData::getCatalogSeparator( )
+{
+ return ".";
+}
+
+sal_Bool DatabaseMetaData::supportsSchemasInDataManipulation( )
+{
+ return true;
+}
+
+sal_Bool DatabaseMetaData::supportsSchemasInProcedureCalls( )
+{
+ return true;
+}
+
+sal_Bool DatabaseMetaData::supportsSchemasInTableDefinitions( )
+{
+ return true;
+}
+
+sal_Bool DatabaseMetaData::supportsSchemasInIndexDefinitions( )
+{
+ return true;
+}
+
+sal_Bool DatabaseMetaData::supportsSchemasInPrivilegeDefinitions( )
+{
+ return true;
+}
+
+sal_Bool DatabaseMetaData::supportsCatalogsInDataManipulation( )
+{
+ return false;
+}
+
+sal_Bool DatabaseMetaData::supportsCatalogsInProcedureCalls( )
+{
+ return false;
+}
+
+sal_Bool DatabaseMetaData::supportsCatalogsInTableDefinitions( )
+{
+ return false;
+}
+
+
+sal_Bool DatabaseMetaData::supportsCatalogsInIndexDefinitions( )
+{
+ return false;
+}
+
+
+sal_Bool DatabaseMetaData::supportsCatalogsInPrivilegeDefinitions( )
+{
+ return false;
+}
+
+
+// LEM TODO: positioned (through cursor) updates and deletes seem
+// to be supported; see {UPDATE,DELETE} /table/ (...) WHERE CURRENT OF /cursor_name/" syntax
+// and http://www.postgresql.org/docs/9.1/static/view-pg-cursors.html
+// http://www.postgresql.org/docs/9.1/static/libpq-example.html actually uses a cursor :)
+sal_Bool DatabaseMetaData::supportsPositionedDelete( )
+{
+ // LEM: jdbc driver says not, although the comments in it seem old
+ return false;
+}
+
+sal_Bool DatabaseMetaData::supportsPositionedUpdate( )
+{
+ // LEM: jdbc driver says not, although the comments in it seem old
+ return false;
+}
+
+
+sal_Bool DatabaseMetaData::supportsSelectForUpdate( )
+{
+ return true;
+}
+
+
+sal_Bool DatabaseMetaData::supportsStoredProcedures( )
+{
+ return true;
+}
+
+
+sal_Bool DatabaseMetaData::supportsSubqueriesInComparisons( )
+{
+ return true;
+}
+
+sal_Bool DatabaseMetaData::supportsSubqueriesInExists( )
+{
+ return true;
+}
+
+sal_Bool DatabaseMetaData::supportsSubqueriesInIns( )
+{
+ return true;
+}
+
+sal_Bool DatabaseMetaData::supportsSubqueriesInQuantifieds( )
+{
+ // LEM: jdbc driver says yes, although comment says they don't know what this means...
+ return true;
+}
+
+sal_Bool DatabaseMetaData::supportsCorrelatedSubqueries( )
+{
+ return true;
+}
+sal_Bool DatabaseMetaData::supportsUnion( )
+{
+ return true;
+}
+
+sal_Bool DatabaseMetaData::supportsUnionAll( )
+{
+ return true;
+}
+
+sal_Bool DatabaseMetaData::supportsOpenCursorsAcrossCommit( )
+{
+ return false;
+}
+
+sal_Bool DatabaseMetaData::supportsOpenCursorsAcrossRollback( )
+{
+ return false;
+}
+
+sal_Bool DatabaseMetaData::supportsOpenStatementsAcrossCommit( )
+{
+ return true;
+}
+sal_Bool DatabaseMetaData::supportsOpenStatementsAcrossRollback( )
+{
+ return true;
+}
+
+sal_Int32 DatabaseMetaData::getMaxBinaryLiteralLength( )
+{
+ return 0;
+}
+
+sal_Int32 DatabaseMetaData::getMaxCharLiteralLength( )
+{
+ return 0;
+}
+
+// Copied / adapted / simplified from JDBC driver
+sal_Int32 DatabaseMetaData::getIntSetting(const OUString& settingName)
+{
+ MutexGuard guard( m_xMutex->GetMutex() );
+
+ Reference< XParameters > params(m_getIntSetting_stmt, UNO_QUERY_THROW );
+ params->setString(1, settingName );
+ Reference< XResultSet > rs = m_getIntSetting_stmt->executeQuery();
+ Reference< XRow > xRow( rs , UNO_QUERY_THROW );
+ OSL_VERIFY(rs->next());
+ OSL_ENSURE(rs->isFirst(), "postgresql-sdbc DatabaseMetaData getIntSetting not on first row");
+ OSL_ENSURE(rs->isLast(), "postgresql-sdbc DatabaseMetaData getIntSetting not on last row");
+ return xRow->getInt(1);
+}
+
+sal_Int32 DatabaseMetaData::getMaxNameLength()
+{
+ if ( m_pSettings->maxNameLen == 0)
+ m_pSettings->maxNameLen = getIntSetting( "max_identifier_length" );
+ OSL_ENSURE(m_pSettings->maxNameLen, "postgresql-sdbc: maxNameLen is zero");
+ return m_pSettings->maxNameLen;
+}
+
+sal_Int32 DatabaseMetaData::getMaxIndexKeys()
+{
+ if ( m_pSettings->maxIndexKeys == 0)
+ m_pSettings->maxIndexKeys = getIntSetting("max_index_keys");
+ OSL_ENSURE(m_pSettings->maxIndexKeys, "postgresql-sdbc: maxIndexKeys is zero");
+ return m_pSettings->maxIndexKeys;
+}
+
+sal_Int32 DatabaseMetaData::getMaxColumnNameLength( )
+{
+ return getMaxNameLength();
+}
+
+sal_Int32 DatabaseMetaData::getMaxColumnsInGroupBy( )
+{
+ return 0;
+}
+
+sal_Int32 DatabaseMetaData::getMaxColumnsInIndex( )
+{
+ return getMaxIndexKeys();
+}
+
+sal_Int32 DatabaseMetaData::getMaxColumnsInOrderBy( )
+{
+ return 0;
+}
+
+sal_Int32 DatabaseMetaData::getMaxColumnsInSelect( )
+{
+ return 0;
+}
+
+sal_Int32 DatabaseMetaData::getMaxColumnsInTable( )
+{
+ return 1600;
+}
+
+sal_Int32 DatabaseMetaData::getMaxConnections( )
+{
+ // LEM: The JDBC driver returns an arbitrary 8192; truth is as much as OS / hardware supports
+ return 0;
+}
+
+sal_Int32 DatabaseMetaData::getMaxCursorNameLength( ) //TODO, don't know
+{
+ return getMaxNameLength();
+}
+
+sal_Int32 DatabaseMetaData::getMaxIndexLength( ) //TODO, don't know
+{
+ // LEM: that's the index itself, not its name
+ return 0;
+}
+
+sal_Int32 DatabaseMetaData::getMaxSchemaNameLength( )
+{
+ return getMaxNameLength();
+}
+
+sal_Int32 DatabaseMetaData::getMaxProcedureNameLength( )
+{
+ return getMaxNameLength();
+}
+
+sal_Int32 DatabaseMetaData::getMaxCatalogNameLength( )
+{
+ return getMaxNameLength();
+}
+
+sal_Int32 DatabaseMetaData::getMaxRowSize( )
+{
+ // jdbc driver says 1GB, but http://www.postgresql.org/about/ says 1.6TB
+ // and that 1GB is the maximum _field_ size
+ // The row limit does not fit into a sal_Int32
+ return 0;
+}
+
+sal_Bool DatabaseMetaData::doesMaxRowSizeIncludeBlobs( )
+{
+ // LEM: Err... PostgreSQL basically does not do BLOBs well
+ // In any case, BLOBs do not change the maximal row length AFAIK
+ return true;
+}
+
+sal_Int32 DatabaseMetaData::getMaxStatementLength( )
+{
+ // LEM: actually, that would be 2^sizeof(size_t)-1
+ // on the server? on the client (because of libpq)? minimum of the two? not sure
+ // Anyway, big, so say unlimited.
+ return 0;
+}
+
+sal_Int32 DatabaseMetaData::getMaxStatements( ) //TODO, don't know
+{
+ return 0;
+}
+
+sal_Int32 DatabaseMetaData::getMaxTableNameLength( )
+{
+ return getMaxNameLength();
+}
+
+sal_Int32 DatabaseMetaData::getMaxTablesInSelect( )
+{
+ return 0;
+}
+
+sal_Int32 DatabaseMetaData::getMaxUserNameLength( )
+{
+ return getMaxNameLength();
+}
+
+sal_Int32 DatabaseMetaData::getDefaultTransactionIsolation( )
+{
+ return css::sdbc::TransactionIsolation::READ_COMMITTED;
+}
+
+sal_Bool DatabaseMetaData::supportsTransactions( )
+{
+ return true;
+}
+
+sal_Bool DatabaseMetaData::supportsTransactionIsolationLevel( sal_Int32 level )
+{
+ if ( level == css::sdbc::TransactionIsolation::READ_COMMITTED
+ || level == css::sdbc::TransactionIsolation::SERIALIZABLE
+ || level == css::sdbc::TransactionIsolation::READ_UNCOMMITTED
+ || level == css::sdbc::TransactionIsolation::REPEATABLE_READ)
+ return true;
+ else
+ return false;
+}
+
+sal_Bool DatabaseMetaData::supportsDataDefinitionAndDataManipulationTransactions( )
+{
+ return true;
+}
+
+sal_Bool DatabaseMetaData::supportsDataManipulationTransactionsOnly( )
+{
+ return false;
+}
+
+sal_Bool DatabaseMetaData::dataDefinitionCausesTransactionCommit( )
+{
+ return false;
+}
+
+sal_Bool DatabaseMetaData::dataDefinitionIgnoredInTransactions( )
+{
+ return false;
+}
+
+css::uno::Reference< XResultSet > DatabaseMetaData::getProcedures(
+ const css::uno::Any&,
+ const OUString&,
+ const OUString& )
+{
+// 1. PROCEDURE_CAT string =&gt; procedure catalog (may be NULL )
+// 2. PROCEDURE_SCHEM string =&gt; procedure schema (may be NULL )
+// 3. PROCEDURE_NAME string =&gt; procedure name
+// 4. reserved for future use
+// 5. reserved for future use
+// 6. reserved for future use
+// 7. REMARKS string =&gt; explanatory comment on the procedure
+// 8. PROCEDURE_TYPE short =&gt; kind of procedure:
+// * UNKNOWN - May return a result
+// * NO - Does not return a result
+// * RETURN - Returns a result
+
+// LEM TODO: implement
+// LEM TODO: at least fake the columns, even if no row.
+ MutexGuard guard( m_xMutex->GetMutex() );
+ return new SequenceResultSet(
+ m_xMutex, *this, std::vector< OUString >(), std::vector< std::vector< Any > > (), m_pSettings->tc );
+}
+
+css::uno::Reference< XResultSet > DatabaseMetaData::getProcedureColumns(
+ const css::uno::Any&,
+ const OUString&,
+ const OUString&,
+ const OUString& )
+{
+ MutexGuard guard( m_xMutex->GetMutex() );
+// LEM TODO: implement
+// LEM TODO: at least fake the columns, even if no row.
+ return new SequenceResultSet(
+ m_xMutex, *this, std::vector< OUString >(), std::vector< std::vector< Any > >(), m_pSettings->tc );
+}
+
+css::uno::Reference< XResultSet > DatabaseMetaData::getTables(
+ const css::uno::Any&,
+ const OUString& schemaPattern,
+ const OUString& tableNamePattern,
+ const css::uno::Sequence< OUString >& )
+{
+ Statics &statics = getStatics();
+
+ MutexGuard guard( m_xMutex->GetMutex() );
+
+ SAL_INFO("connectivity.postgresql", "DatabaseMetaData::getTables() got called with " << schemaPattern << "." << tableNamePattern);
+
+ // ignore catalog, as a single pq connection does not support multiple catalogs
+
+ // LEM TODO: this does not give the right column names, not the right number of columns, etc.
+ // Take "inspiration" from JDBC driver
+ // Ah, this is used to create a XResultSet manually... Try to do it directly in SQL
+ Reference< XPreparedStatement > statement = m_origin->prepareStatement(
+ "SELECT "
+ "DISTINCT ON (pg_namespace.nspname, relname ) " // avoid duplicates (pg_settings !)
+ "pg_namespace.nspname, relname, relkind, pg_description.description "
+ "FROM pg_namespace, pg_class LEFT JOIN pg_description ON pg_class.oid = pg_description.objoid "
+ "WHERE relnamespace = pg_namespace.oid "
+ "AND ( relkind = 'r' OR relkind = 'v') "
+ "AND pg_namespace.nspname LIKE ? "
+ "AND relname LIKE ? "
+// "ORDER BY pg_namespace.nspname || relname"
+ );
+
+ Reference< XParameters > parameters( statement, UNO_QUERY_THROW );
+ parameters->setString( 1 , schemaPattern );
+ parameters->setString( 2 , tableNamePattern );
+
+ Reference< XResultSet > rs = statement->executeQuery();
+ Reference< XRow > xRow( rs, UNO_QUERY_THROW );
+ std::vector< std::vector<Any> > vec;
+
+ while( rs->next() )
+ {
+ std::vector< Any > row( 5 );
+
+ row[0] <<= m_pSettings->catalog;
+ row[1] <<= xRow->getString( 1 );
+ row[2] <<= xRow->getString( 2 );
+ OUString type = xRow->getString(3);
+ if( type == "r" )
+ {
+ if( xRow->getString(1) == "pg_catalog" )
+ {
+ row[3] <<= statics.SYSTEM_TABLE;
+ }
+ else
+ {
+ row[3] <<= statics.TABLE;
+ }
+ }
+ else if( type == "v" )
+ {
+ row[3] <<= statics.VIEW;
+ }
+ else
+ {
+ row[3] <<= statics.UNKNOWN;
+ }
+ row[4] <<= xRow->getString(4);
+
+ // no description in postgresql AFAIK
+ vec.push_back( row );
+ }
+ Reference< XCloseable > closeable( statement, UNO_QUERY );
+ if( closeable.is() )
+ closeable->close();
+
+ return new SequenceResultSet(
+ m_xMutex, *this, std::vector(statics.tablesRowNames), std::move(vec), m_pSettings->tc );
+}
+
+namespace
+{
+ // sort no schema first, then "public", then normal schemas, then internal schemas
+ int compare_schema(std::u16string_view nsA, std::u16string_view nsB)
+ {
+ if (nsA.empty())
+ {
+ return nsB.empty() ? 0 : -1;
+ }
+ else if (nsB.empty())
+ {
+ assert(!nsA.empty());
+ return 1;
+ }
+ else if(nsA == u"public")
+ {
+ return (nsB == u"public") ? 0 : -1;
+ }
+ else if(nsB == u"public")
+ {
+ assert(nsA != u"public");
+ return 1;
+ }
+ else if(o3tl::starts_with(nsA, u"pg_"))
+ {
+ if(o3tl::starts_with(nsB, u"pg_"))
+ return nsA.compare(nsB);
+ else
+ return 1;
+ }
+ else if(o3tl::starts_with(nsB, u"pg_"))
+ {
+ return -1;
+ }
+ else
+ {
+ return nsA.compare(nsB);
+ }
+ }
+
+ struct SortInternalSchemasLastAndPublicFirst
+ {
+ bool operator () ( const std::vector< Any > & a, const std::vector< Any > & b )
+ {
+ OUString valueA;
+ OUString valueB;
+ a[0] >>= valueA;
+ b[0] >>= valueB;
+ return compare_schema(valueA, valueB) < 0;
+ }
+ };
+}
+
+css::uno::Reference< XResultSet > DatabaseMetaData::getSchemas( )
+{
+ MutexGuard guard( m_xMutex->GetMutex() );
+
+ SAL_INFO("connectivity.postgresql", "DatabaseMetaData::getSchemas() got called");
+
+ // <b>TABLE_SCHEM</b> string =&amp;gt; schema name
+ Reference< XStatement > statement = m_origin->createStatement();
+ Reference< XResultSet > rs = statement->executeQuery(
+ "SELECT nspname from pg_namespace" );
+ // LEM TODO: look at JDBC driver and consider doing the same
+ // in particular, excluding temporary schemas, but maybe better through pg_is_other_temp_schema(oid) OR == pg_my_temp_schema()
+
+ Reference< XRow > xRow( rs, UNO_QUERY_THROW );
+ std::vector< std::vector<Any> > vec;
+ while( rs->next() )
+ {
+ vec.push_back( { Any(xRow->getString(1)) } );
+ }
+
+ // sort public first, sort internal schemas last, sort rest in alphabetic order
+ std::sort( vec.begin(), vec.end(), SortInternalSchemasLastAndPublicFirst() );
+
+ Reference< XCloseable > closeable( statement, UNO_QUERY );
+ if( closeable.is() )
+ closeable->close();
+ return new SequenceResultSet(
+ m_xMutex, *this, std::vector(getStatics().schemaNames), std::move(vec), m_pSettings->tc );
+}
+
+css::uno::Reference< XResultSet > DatabaseMetaData::getCatalogs( )
+{
+ // LEM TODO: return the current catalog like JDBC driver?
+ // at least fake the columns, even if no content
+ MutexGuard guard( m_xMutex->GetMutex() );
+ return new SequenceResultSet(
+ m_xMutex, *this, std::vector< OUString >(), std::vector< std::vector< Any > >(), m_pSettings->tc );
+}
+
+css::uno::Reference< XResultSet > DatabaseMetaData::getTableTypes( )
+{
+ // LEM TODO: this can be made dynamic, see JDBC driver
+ MutexGuard guard( m_xMutex->GetMutex() );
+ return new SequenceResultSet(
+ m_xMutex, *this, std::vector(getStatics().tableTypeNames), std::vector(getStatics().tableTypeData),
+ m_pSettings->tc );
+}
+
+
+/** returns the constant from sdbc.DataType
+ */
+sal_Int32 typeNameToDataType( const OUString &typeName, std::u16string_view typtype )
+{
+// sal_Int32 ret = css::sdbc::DataType::DISTINCT;
+ // map all unknown types to memo (longvarchar). This allows to show them in
+ // string representation. Additionally, the edit-table-type-selection-box
+ // is not so unusable anymore.
+ sal_Int32 ret = css::sdbc::DataType::LONGVARCHAR;
+ if( typtype == u"b" )
+ {
+ // as long as the OOo framework does not support arrays,
+ // the user is better of with interpreting arrays as strings !
+// if( typeName.getLength() && '_' == typeName[0] )
+// {
+// it's just a naming convention, but as long as we don't have anything better,
+// we take it as granted
+// ret = css::sdbc::DataType::ARRAY;
+// }
+ // base type
+ Statics &statics = getStatics();
+ BaseTypeMap::const_iterator ii = statics.baseTypeMap.find( typeName );
+ if( ii != statics.baseTypeMap.end() )
+ {
+ ret = ii->second;
+ }
+ }
+ else if( typtype == u"c" )
+ {
+ ret = css::sdbc::DataType::STRUCT;
+ }
+ else if( typtype == u"d" )
+ {
+ ret = css::sdbc::DataType::LONGVARCHAR;
+ }
+ return ret;
+}
+
+namespace {
+ bool isSystemColumn( sal_Int16 attnum )
+ {
+ return attnum <= 0;
+ }
+
+ // is not exported by the postgres header
+ const int PQ_VARHDRSZ = sizeof( sal_Int32 );
+
+ // Oh, quelle horreur
+ // LEM TODO: Need to severely rewrite that!
+ // should probably just "do the same" as ODBC or JDBC drivers...
+ void extractPrecisionAndScale(
+ sal_Int32 dataType, sal_Int32 atttypmod, sal_Int32 *precision, sal_Int32 *scale )
+ {
+ if( atttypmod < PQ_VARHDRSZ )
+ {
+ *precision = 0;
+ *scale = 0;
+ }
+ else
+ {
+ switch( dataType )
+ {
+ case css::sdbc::DataType::NUMERIC:
+ case css::sdbc::DataType::DECIMAL:
+ {
+ *precision = ( ( atttypmod - PQ_VARHDRSZ ) >> 16 ) & 0xffff;
+ *scale = (atttypmod - PQ_VARHDRSZ ) & 0xffff;
+ break;
+ }
+ default:
+ *precision = atttypmod - PQ_VARHDRSZ;
+ *scale = 0;
+ }
+ }
+ }
+
+ struct DatabaseTypeDescription
+ {
+ DatabaseTypeDescription()
+ {}
+ DatabaseTypeDescription( OUString name, OUString type ) :
+ typeName(std::move( name )),
+ typeType(std::move( type ))
+ {}
+ DatabaseTypeDescription( const DatabaseTypeDescription &source ) :
+ typeName( source.typeName ),
+ typeType( source.typeType )
+ {}
+ DatabaseTypeDescription & operator = ( const DatabaseTypeDescription & source )
+ {
+ typeName = source.typeName;
+ typeType = source.typeType;
+ return *this;
+ }
+ OUString typeName;
+ OUString typeType;
+ };
+}
+
+typedef std::unordered_map
+<
+ sal_Int32,
+ DatabaseTypeDescription
+> Oid2DatabaseTypeDescriptionMap;
+
+static void columnMetaData2DatabaseTypeDescription(
+ Oid2DatabaseTypeDescriptionMap &oidMap,
+ const Reference< XResultSet > &rs,
+ const Reference< XStatement > &stmt )
+{
+ Reference< XRow > row( rs, UNO_QUERY_THROW );
+ int domains = 0;
+ OUStringBuffer queryBuf(128);
+ queryBuf.append( "SELECT oid,typtype,typname FROM pg_TYPE WHERE " );
+ while( rs->next() )
+ {
+ if( row->getString( 9 ) == "d" && oidMap.find( row->getInt( 12 ) ) == oidMap.end() )
+ {
+ oidMap[row->getInt(12)] = DatabaseTypeDescription();
+ if( domains )
+ queryBuf.append( " OR " );
+ queryBuf.append( "oid = " + OUString::number( row->getInt(12 ) ) );
+ domains ++;
+ }
+ }
+ rs->beforeFirst();
+
+ if( domains )
+ {
+ Reference< XResultSet > rsDomain = stmt->executeQuery( queryBuf.makeStringAndClear() );
+ row.set( rsDomain, UNO_QUERY_THROW );
+ while( rsDomain->next() )
+ {
+ oidMap[row->getInt(1)] = DatabaseTypeDescription(row->getString(3), row->getString(2) );
+ }
+ disposeNoThrow( stmt );
+ }
+
+}
+
+
+css::uno::Reference< XResultSet > DatabaseMetaData::getColumns(
+ const css::uno::Any&,
+ const OUString& schemaPattern,
+ const OUString& tableNamePattern,
+ const OUString& columnNamePattern )
+{
+ // LEM TODO: review in comparison with JDBC driver
+ Statics &statics = getStatics();
+
+ // continue !
+ MutexGuard guard( m_xMutex->GetMutex() );
+
+ SAL_INFO("connectivity.postgresql", "DatabaseMetaData::getColumns() got called with "
+ << schemaPattern << "." << tableNamePattern << "." << columnNamePattern);
+
+ // ignore catalog, as a single pq connection
+ // does not support multiple catalogs anyway
+ // We don't use information_schema.columns because it contains
+ // only the columns the current user has any privilege over.
+
+ // 1. TABLE_CAT string => table catalog (may be NULL)
+ // => not supported
+ // 2. TABLE_SCHEM string => table schema (may be NULL)
+ // => pg_namespace.nspname
+ // 3. TABLE_NAME string => table name
+ // => pg_class.relname
+ // 4. COLUMN_NAME string => column name
+ // => pg_attribute.attname
+ // 5. DATA_TYPE short => SQL type from java.sql.Types
+ // => pg_type.typname => sdbc.DataType
+ // 6. TYPE_NAME string => Data source dependent type name, for a UDT the
+ // type name is fully qualified
+ // => pg_type.typname
+ // 7. COLUMN_SIZE long => column size. For char or date types this is
+ // the maximum number of characters, for numeric
+ // or decimal types this is precision.
+ // => pg_attribute.atttypmod
+ // 8. BUFFER_LENGTH is not used.
+ // => not used
+ // 9. DECIMAL_DIGITS long => the number of fractional digits
+ // => don't know ! TODO !
+ // 10. NUM_PREC_RADIX long => Radix (typically either 10 or 2)
+ // => TODO ??
+ // 11. NULLABLE long => is NULL allowed?
+ // NO_NULLS - might not allow NULL values
+ // NULABLE - definitely allows NULL values
+ // NULLABLE_UNKNOWN - nullability unknown
+ // => pg_attribute.attnotnull
+ // 12. REMARKS string => comment describing column (may be NULL )
+ // => pg_description.description
+ // 13. COLUMN_DEF string => default value (may be NULL)
+ // => pg_type.typdefault
+ // 14. SQL_DATA_TYPE long => unused
+ // => empty
+ // 15. SQL_DATETIME_SUB long => unused
+ // => empty
+ // 16. CHAR_OCTET_LENGTH long => for char types the maximum number of
+ // bytes in the column
+ // => pg_type.typlen
+ // 17. ORDINAL_POSITION int => index of column in table (starting at 1)
+ // pg_attribute.attnum
+ // 18. IS_NULLABLE string => "NO" means column definitely does not allow
+ // NULL values; "YES" means the column might
+ // allow NULL values. An empty string means
+ // nobody knows.
+ // => pg_attribute.attnotnull
+ OUString strDefaultValue = getColExprForDefaultSettingVal(m_pSettings);
+ Reference< XPreparedStatement > statement = m_origin->prepareStatement(
+ "SELECT pg_namespace.nspname, " // 1
+ "pg_class.relname, " // 2
+ "pg_attribute.attname, " // 3
+ "pg_type.typname, " // 4
+ "pg_attribute.atttypmod, " // 5
+ "pg_attribute.attnotnull, " // 6
+ "pg_type.typdefault, " // 7
+ "pg_type.typtype, " // 8
+ + strDefaultValue + // 9
+ ",pg_description.description, " // 10
+ "pg_type.typbasetype, " // 11
+ "pg_attribute.attnum " // 12
+ "FROM pg_class, "
+ "pg_attribute LEFT JOIN pg_attrdef ON pg_attribute.attrelid = pg_attrdef.adrelid AND pg_attribute.attnum = pg_attrdef.adnum "
+ "LEFT JOIN pg_description ON pg_attribute.attrelid = pg_description.objoid AND pg_attribute.attnum=pg_description.objsubid,"
+ " pg_type, pg_namespace "
+ "WHERE pg_attribute.attrelid = pg_class.oid "
+ "AND pg_attribute.atttypid = pg_type.oid "
+ "AND pg_class.relnamespace = pg_namespace.oid "
+ "AND NOT pg_attribute.attisdropped "
+ "AND pg_namespace.nspname LIKE ? "
+ "AND pg_class.relname LIKE ? "
+ "AND pg_attribute.attname LIKE ? "
+ "ORDER BY pg_namespace.nspname, pg_class.relname, pg_attribute.attnum"
+ );
+
+ Reference< XParameters > parameters( statement, UNO_QUERY_THROW );
+ parameters->setString( 1 , schemaPattern );
+ parameters->setString( 2 , tableNamePattern );
+ parameters->setString( 3 , columnNamePattern );
+
+ Reference< XResultSet > rs = statement->executeQuery();
+ Reference< XRow > xRow( rs, UNO_QUERY_THROW );
+ std::vector< std::vector<Any> > vec;
+
+ Oid2DatabaseTypeDescriptionMap domainMap;
+ Reference< XStatement > domainTypeStmt = m_origin->createStatement();
+ columnMetaData2DatabaseTypeDescription( domainMap, rs, domainTypeStmt );
+
+ sal_uInt32 colNum(0);
+ OUString sSchema( "#invalid#" );
+ OUString sTable( "#invalid#" );
+
+ while( rs->next() )
+ {
+ if( ! isSystemColumn( xRow->getShort( 12 ) ) )
+ {
+ OUString sNewSchema( xRow->getString(1) );
+ OUString sNewTable( xRow->getString(2) );
+ if ( sNewSchema != sSchema || sNewTable != sTable )
+ {
+ colNum = 1;
+ sSchema = sNewSchema;
+ sTable = sNewTable;
+ }
+ else
+ ++colNum;
+ sal_Int32 precision, scale, type;
+ std::vector< Any > row( 18 );
+ row[0] <<= m_pSettings->catalog;
+ row[1] <<= sNewSchema;
+ row[2] <<= sNewTable;
+ row[3] <<= xRow->getString(3);
+ if( xRow->getString(8) == "d" )
+ {
+ DatabaseTypeDescription desc( domainMap[xRow->getInt(11)] );
+ type = typeNameToDataType( desc.typeName, desc.typeType );
+ }
+ else
+ {
+ type = typeNameToDataType( xRow->getString(4), xRow->getString(8) );
+ }
+ extractPrecisionAndScale( type, xRow->getInt(5) , &precision, &scale );
+ row[4] <<= type;
+ row[5] <<= xRow->getString(4);
+ row[6] <<= precision;
+ // row[7] BUFFER_LENGTH not used
+ row[8] <<= scale;
+ // row[9] RADIX TODO
+ if( xRow->getBoolean( 6 ) && ! isSystemColumn(xRow->getInt( 12 )) )
+ {
+ row[10] <<= OUString::number(css::sdbc::ColumnValue::NO_NULLS);
+ row[17] <<= statics.NO;
+ }
+ else
+ {
+ row[10] <<= OUString::number(css::sdbc::ColumnValue::NULLABLE);
+ row[17] <<= statics.YES;
+ }
+
+ row[11] <<= xRow->getString( 10 ); // comment
+ row[12] <<= xRow->getString( 9 ); // COLUMN_DEF = pg_type.typdefault
+ // row[13] SQL_DATA_TYPE not used
+ // row[14] SQL_DATETIME_SUB not used
+ row[15] <<= precision;
+ row[16] <<= colNum ;
+
+ vec.push_back( row );
+ }
+ }
+ Reference< XCloseable > closeable( statement, UNO_QUERY );
+ if( closeable.is() )
+ closeable->close();
+
+ return new SequenceResultSet(
+ m_xMutex, *this, std::vector(statics.columnRowNames), std::move(vec), m_pSettings->tc );
+}
+
+css::uno::Reference< XResultSet > DatabaseMetaData::getColumnPrivileges(
+ const css::uno::Any&,
+ const OUString& schema,
+ const OUString& table,
+ const OUString& columnNamePattern )
+{
+ MutexGuard guard( m_xMutex->GetMutex() );
+
+ SAL_INFO("connectivity.postgresql", "DatabaseMetaData::getColumnPrivileges() got called with "
+ << schema << "." << table << "." << columnNamePattern);
+
+ Reference< XParameters > parameters( m_getColumnPrivs_stmt, UNO_QUERY_THROW );
+ parameters->setString( 1 , schema );
+ parameters->setString( 2 , table );
+ parameters->setString( 3 , columnNamePattern );
+
+ Reference< XResultSet > rs = m_getColumnPrivs_stmt->executeQuery();
+
+ return rs;
+}
+
+css::uno::Reference< XResultSet > DatabaseMetaData::getTablePrivileges(
+ const css::uno::Any&,
+ const OUString& schemaPattern,
+ const OUString& tableNamePattern )
+{
+ MutexGuard guard( m_xMutex->GetMutex() );
+
+ SAL_INFO("connectivity.postgresql", "DatabaseMetaData::getTablePrivileges() got called with "
+ << schemaPattern << "." << tableNamePattern);
+
+ Reference< XParameters > parameters( m_getTablePrivs_stmt, UNO_QUERY_THROW );
+ parameters->setString( 1 , schemaPattern );
+ parameters->setString( 2 , tableNamePattern );
+
+ Reference< XResultSet > rs = m_getTablePrivs_stmt->executeQuery();
+
+ return rs;
+}
+
+css::uno::Reference< XResultSet > DatabaseMetaData::getBestRowIdentifier(
+ const css::uno::Any&,
+ const OUString&,
+ const OUString&,
+ sal_Int32,
+ sal_Bool )
+{
+ //LEM TODO: implement! See JDBC driver
+ MutexGuard guard( m_xMutex->GetMutex() );
+ return new SequenceResultSet(
+ m_xMutex, *this, std::vector< OUString >(), std::vector< std::vector< Any > >(), m_pSettings->tc );
+}
+
+css::uno::Reference< XResultSet > DatabaseMetaData::getVersionColumns(
+ const css::uno::Any&,
+ const OUString&,
+ const OUString& )
+{
+ //LEM TODO: implement! See JDBC driver
+ MutexGuard guard( m_xMutex->GetMutex() );
+ return new SequenceResultSet(
+ m_xMutex, *this, std::vector< OUString >(), std::vector< std::vector< Any > >(), m_pSettings->tc );
+}
+
+css::uno::Reference< XResultSet > DatabaseMetaData::getPrimaryKeys(
+ const css::uno::Any&,
+ const OUString& schema,
+ const OUString& table )
+{
+ //LEM TODO: review
+ MutexGuard guard( m_xMutex->GetMutex() );
+
+// 1. TABLE_CAT string =&gt; table catalog (may be NULL )
+// 2. TABLE_SCHEM string =&gt; table schema (may be NULL )
+// 3. TABLE_NAME string =&gt; table name
+// 4. COLUMN_NAME string =&gt; column name
+// 5. KEY_SEQ short =&gt; sequence number within primary key
+// 6. PK_NAME string =&gt; primary key name (may be NULL )
+
+ SAL_INFO("connectivity.postgresql", "DatabaseMetaData::getPrimaryKeys() got called with "
+ << schema << "." << table);
+
+ Reference< XPreparedStatement > statement = m_origin->prepareStatement(
+ "SELECT nmsp.nspname, "
+ "cl.relname, "
+ "con.conkey, "
+ "con.conname, "
+ "con.conrelid "
+ "FROM pg_constraint as con,pg_class as cl, pg_namespace as nmsp "
+ "WHERE con.connamespace = nmsp.oid AND con.conrelid = cl.oid AND con.contype = 'p' "
+ "AND nmsp.nspname LIKE ? AND cl.relname LIKE ?" );
+
+ Reference< XParameters > parameters( statement, UNO_QUERY_THROW );
+ parameters->setString( 1 , schema );
+ parameters->setString( 2 , table );
+
+ Reference< XResultSet > rs = statement->executeQuery();
+ Reference< XRow > xRow( rs, UNO_QUERY_THROW );
+ std::vector< std::vector<Any> > vec;
+
+ while( rs->next() )
+ {
+ std::vector< Any > row( 6 );
+ row[0] <<= m_pSettings->catalog;
+ row[1] <<= xRow->getString(1);
+ row[2] <<= xRow->getString(2);
+ OUString array = xRow->getString(3);
+ row[4] <<= xRow->getString(5); // the relid
+ row[5] <<= xRow->getString(4);
+
+ int i = 0;
+ // now retrieve the columns information
+ // unfortunately, postgresql does not allow array of variable size in
+ // WHERE clauses (in the default installation), so we have to choose
+ // this expensive and somewhat ugly way
+ // annotation: postgresql shouldn't have chosen an array here, instead they
+ // should have multiple rows per table
+ // LEM: to transform an array into several rows, see unnest;
+ // it is as simple as "SELECT foo, bar, unnest(qux) FROM ..."
+ // where qux is the column that contains an array.
+ while( array[i] && '}' != array[i] )
+ {
+ i++;
+ int start = i;
+ while( array[i] && array[i] != '}' && array[i] != ',' ) i++;
+ row[3] <<= array.copy(start, i - start );
+ vec.push_back( row );
+ }
+ }
+
+ {
+ Reference< XCloseable > closeable( statement, UNO_QUERY );
+ if( closeable.is() )
+ closeable->close();
+ }
+
+
+ OUString lastTableOid;
+ sal_Int32 index = 0;
+ std::vector< std::vector< Any > > ret( vec.size() );
+ int elements = 0;
+ for (auto const& elem : vec)
+ {
+
+ std::vector< Any > row = elem;
+ OUString tableOid;
+ OUString attnum;
+
+ row[4] >>= tableOid;
+ row[3] >>= attnum;
+ statement = m_origin->prepareStatement(
+ "SELECT att.attname FROM "
+ "pg_attribute AS att, pg_class AS cl WHERE "
+ "att.attrelid = ? AND att.attnum = ?" );
+
+ parameters.set( statement, UNO_QUERY_THROW );
+ parameters->setString( 1 , tableOid );
+ parameters->setString( 2 , attnum );
+
+ rs = statement->executeQuery();
+ xRow.set( rs, UNO_QUERY_THROW );
+ if( rs->next() )
+ {
+ // column name
+ row[3] <<= xRow->getString( 1 );
+ if( tableOid != lastTableOid )
+ index = 1;
+ lastTableOid = tableOid;
+ row[4] <<= OUString::number( index );
+ index ++;
+ }
+ {
+ Reference< XCloseable > closeable( statement, UNO_QUERY );
+ if( closeable.is() )
+ closeable->close();
+ }
+ ret[elements] = row;
+ elements ++;
+ }
+ return new SequenceResultSet(
+ m_xMutex, *this, std::vector(getStatics().primaryKeyNames), std::move(ret), m_pSettings->tc );
+}
+
+// Copied / adapted / simplified from JDBC driver
+#define SQL_CASE_KEYRULE " WHEN 'c' THEN " SAL_STRINGIFY(KEYRULE_CASCADE) \
+ " WHEN 'n' THEN " SAL_STRINGIFY(KEYRULE_SET_NULL) \
+ " WHEN 'd' THEN " SAL_STRINGIFY(KEYRULE_SET_DEFAULT) \
+ " WHEN 'r' THEN " SAL_STRINGIFY(KEYRULE_RESTRICT) \
+ " WHEN 'a' THEN " SAL_STRINGIFY(KEYRULE_NO_ACTION) \
+ " ELSE NULL "
+
+#define SQL_GET_REFERENCES \
+ "WITH con AS (SELECT oid, conname, contype, condeferrable, condeferred, conrelid, confrelid, confupdtype, confdeltype, generate_subscripts(conkey,1) AS conkeyseq, unnest(conkey) AS conkey , unnest(confkey) AS confkey FROM pg_catalog.pg_constraint) " \
+ "SELECT NULL::text AS PKTABLE_CAT, pkn.nspname AS PKTABLE_SCHEM, pkc.relname AS PKTABLE_NAME, pka.attname AS PKCOLUMN_NAME, " \
+ " NULL::text AS FKTABLE_CAT, fkn.nspname AS FKTABLE_SCHEM, fkc.relname AS FKTABLE_NAME, fka.attname AS FKCOLUMN_NAME, " \
+ " con.conkeyseq AS KEY_SEQ, " \
+ " CASE con.confupdtype " \
+ SQL_CASE_KEYRULE \
+ " END AS UPDATE_RULE, " \
+ " CASE con.confdeltype " \
+ SQL_CASE_KEYRULE \
+ " END AS DELETE_RULE, " \
+ " con.conname AS FK_NAME, pkic.relname AS PK_NAME, " \
+ " CASE " \
+ " WHEN con.condeferrable AND con.condeferred THEN " SAL_STRINGIFY(DEFERRABILITY_INITIALLY_DEFERRED) \
+ " WHEN con.condeferrable THEN " SAL_STRINGIFY(DEFERRABILITY_INITIALLY_IMMEDIATE) \
+ " ELSE " SAL_STRINGIFY(DEFERRABILITY_NONE) \
+ " END AS DEFERRABILITY " \
+ "FROM " \
+ " pg_catalog.pg_namespace pkn, pg_catalog.pg_class pkc, pg_catalog.pg_attribute pka, " \
+ " pg_catalog.pg_namespace fkn, pg_catalog.pg_class fkc, pg_catalog.pg_attribute fka, " \
+ " con, pg_catalog.pg_depend dep, pg_catalog.pg_class pkic " \
+ "WHERE pkn.oid = pkc.relnamespace AND pkc.oid = pka.attrelid AND pka.attnum = con.confkey AND con.confrelid = pkc.oid " \
+ " AND fkn.oid = fkc.relnamespace AND fkc.oid = fka.attrelid AND fka.attnum = con.conkey AND con.conrelid = fkc.oid " \
+ " AND con.contype = 'f' AND con.oid = dep.objid AND pkic.oid = dep.refobjid AND pkic.relkind = 'i' AND dep.classid = 'pg_constraint'::regclass::oid AND dep.refclassid = 'pg_class'::regclass::oid "
+
+#define SQL_GET_REFERENCES_PSCHEMA " AND pkn.nspname = ? "
+#define SQL_GET_REFERENCES_PTABLE " AND pkc.relname = ? "
+#define SQL_GET_REFERENCES_FSCHEMA " AND fkn.nspname = ? "
+#define SQL_GET_REFERENCES_FTABLE " AND fkc.relname = ? "
+#define SQL_GET_REFERENCES_ORDER_SOME_PTABLE "ORDER BY fkn.nspname, fkc.relname, conkeyseq"
+#define SQL_GET_REFERENCES_ORDER_NO_PTABLE "ORDER BY pkn.nspname, pkc.relname, conkeyseq"
+
+#define SQL_GET_REFERENCES_NONE_NONE_NONE_NONE \
+ SQL_GET_REFERENCES \
+ SQL_GET_REFERENCES_ORDER_NO_PTABLE
+
+#define SQL_GET_REFERENCES_SOME_NONE_NONE_NONE \
+ SQL_GET_REFERENCES \
+ SQL_GET_REFERENCES_PSCHEMA \
+ SQL_GET_REFERENCES_ORDER_NO_PTABLE
+
+#define SQL_GET_REFERENCES_NONE_SOME_NONE_NONE \
+ SQL_GET_REFERENCES \
+ SQL_GET_REFERENCES_PTABLE \
+ SQL_GET_REFERENCES_ORDER_SOME_PTABLE
+
+#define SQL_GET_REFERENCES_SOME_SOME_NONE_NONE \
+ SQL_GET_REFERENCES \
+ SQL_GET_REFERENCES_PSCHEMA \
+ SQL_GET_REFERENCES_PTABLE \
+ SQL_GET_REFERENCES_ORDER_SOME_PTABLE
+
+#define SQL_GET_REFERENCES_NONE_NONE_SOME_NONE \
+ SQL_GET_REFERENCES \
+ SQL_GET_REFERENCES_FSCHEMA \
+ SQL_GET_REFERENCES_ORDER_NO_PTABLE
+
+#define SQL_GET_REFERENCES_NONE_NONE_NONE_SOME \
+ SQL_GET_REFERENCES \
+ SQL_GET_REFERENCES_FTABLE \
+ SQL_GET_REFERENCES_ORDER_NO_PTABLE
+
+#define SQL_GET_REFERENCES_NONE_NONE_SOME_SOME \
+ SQL_GET_REFERENCES \
+ SQL_GET_REFERENCES_FSCHEMA \
+ SQL_GET_REFERENCES_FTABLE \
+ SQL_GET_REFERENCES_ORDER_NO_PTABLE
+
+#define SQL_GET_REFERENCES_SOME_NONE_SOME_NONE \
+ SQL_GET_REFERENCES \
+ SQL_GET_REFERENCES_PSCHEMA \
+ SQL_GET_REFERENCES_FSCHEMA \
+ SQL_GET_REFERENCES_ORDER_NO_PTABLE
+
+#define SQL_GET_REFERENCES_SOME_NONE_NONE_SOME \
+ SQL_GET_REFERENCES \
+ SQL_GET_REFERENCES_PSCHEMA \
+ SQL_GET_REFERENCES_FTABLE \
+ SQL_GET_REFERENCES_ORDER_NO_PTABLE
+
+#define SQL_GET_REFERENCES_SOME_NONE_SOME_SOME \
+ SQL_GET_REFERENCES \
+ SQL_GET_REFERENCES_PSCHEMA \
+ SQL_GET_REFERENCES_FSCHEMA \
+ SQL_GET_REFERENCES_FTABLE \
+ SQL_GET_REFERENCES_ORDER_NO_PTABLE
+
+#define SQL_GET_REFERENCES_NONE_SOME_SOME_NONE \
+ SQL_GET_REFERENCES \
+ SQL_GET_REFERENCES_PTABLE \
+ SQL_GET_REFERENCES_FSCHEMA \
+ SQL_GET_REFERENCES_ORDER_SOME_PTABLE
+
+#define SQL_GET_REFERENCES_NONE_SOME_NONE_SOME \
+ SQL_GET_REFERENCES \
+ SQL_GET_REFERENCES_PTABLE \
+ SQL_GET_REFERENCES_FTABLE \
+ SQL_GET_REFERENCES_ORDER_SOME_PTABLE
+
+#define SQL_GET_REFERENCES_NONE_SOME_SOME_SOME \
+ SQL_GET_REFERENCES \
+ SQL_GET_REFERENCES_PTABLE \
+ SQL_GET_REFERENCES_FSCHEMA \
+ SQL_GET_REFERENCES_FTABLE \
+ SQL_GET_REFERENCES_ORDER_SOME_PTABLE
+
+#define SQL_GET_REFERENCES_SOME_SOME_SOME_NONE \
+ SQL_GET_REFERENCES \
+ SQL_GET_REFERENCES_PSCHEMA \
+ SQL_GET_REFERENCES_PTABLE \
+ SQL_GET_REFERENCES_FSCHEMA \
+ SQL_GET_REFERENCES_ORDER_SOME_PTABLE
+
+#define SQL_GET_REFERENCES_SOME_SOME_NONE_SOME \
+ SQL_GET_REFERENCES \
+ SQL_GET_REFERENCES_PSCHEMA \
+ SQL_GET_REFERENCES_PTABLE \
+ SQL_GET_REFERENCES_FTABLE \
+ SQL_GET_REFERENCES_ORDER_SOME_PTABLE
+
+#define SQL_GET_REFERENCES_SOME_SOME_SOME_SOME \
+ SQL_GET_REFERENCES \
+ SQL_GET_REFERENCES_PSCHEMA \
+ SQL_GET_REFERENCES_PTABLE \
+ SQL_GET_REFERENCES_FSCHEMA \
+ SQL_GET_REFERENCES_FTABLE \
+ SQL_GET_REFERENCES_ORDER_SOME_PTABLE
+
+void DatabaseMetaData::init_getReferences_stmt ()
+{
+ m_getReferences_stmt[0] = m_origin->prepareStatement(SQL_GET_REFERENCES_NONE_NONE_NONE_NONE);
+ m_getReferences_stmt[1] = m_origin->prepareStatement(SQL_GET_REFERENCES_SOME_NONE_NONE_NONE);
+ m_getReferences_stmt[2] = m_origin->prepareStatement(SQL_GET_REFERENCES_NONE_SOME_NONE_NONE);
+ m_getReferences_stmt[3] = m_origin->prepareStatement(SQL_GET_REFERENCES_SOME_SOME_NONE_NONE);
+ m_getReferences_stmt[4] = m_origin->prepareStatement(SQL_GET_REFERENCES_NONE_NONE_SOME_NONE);
+ m_getReferences_stmt[5] = m_origin->prepareStatement(SQL_GET_REFERENCES_SOME_NONE_SOME_NONE);
+ m_getReferences_stmt[6] = m_origin->prepareStatement(SQL_GET_REFERENCES_NONE_SOME_SOME_NONE);
+ m_getReferences_stmt[7] = m_origin->prepareStatement(SQL_GET_REFERENCES_SOME_SOME_SOME_NONE);
+ m_getReferences_stmt[8] = m_origin->prepareStatement(SQL_GET_REFERENCES_NONE_NONE_NONE_SOME);
+ m_getReferences_stmt[9] = m_origin->prepareStatement(SQL_GET_REFERENCES_SOME_NONE_NONE_SOME);
+ m_getReferences_stmt[10] = m_origin->prepareStatement(SQL_GET_REFERENCES_NONE_SOME_NONE_SOME);
+ m_getReferences_stmt[11] = m_origin->prepareStatement(SQL_GET_REFERENCES_SOME_SOME_NONE_SOME);
+ m_getReferences_stmt[12] = m_origin->prepareStatement(SQL_GET_REFERENCES_NONE_NONE_SOME_SOME);
+ m_getReferences_stmt[13] = m_origin->prepareStatement(SQL_GET_REFERENCES_SOME_NONE_SOME_SOME);
+ m_getReferences_stmt[14] = m_origin->prepareStatement(SQL_GET_REFERENCES_NONE_SOME_SOME_SOME);
+ m_getReferences_stmt[15] = m_origin->prepareStatement(SQL_GET_REFERENCES_SOME_SOME_SOME_SOME);
+}
+
+void DatabaseMetaData::init_getPrivs_stmt ()
+{
+ OUStringBuffer sSQL(300);
+ sSQL.append(
+ " SELECT dp.TABLE_CAT, dp.TABLE_SCHEM, dp.TABLE_NAME, dp.GRANTOR, pr.rolname AS GRANTEE, dp.privilege, dp.is_grantable "
+ " FROM ("
+ " SELECT table_catalog AS TABLE_CAT, table_schema AS TABLE_SCHEM, table_name,"
+ " grantor, grantee, privilege_type AS PRIVILEGE, is_grantable"
+ " FROM information_schema.table_privileges");
+ if ( PQserverVersion( m_pSettings->pConnection ) < 90200 )
+ // information_schema.table_privileges does not fill in default ACLs when no ACL
+ // assume default ACL is "owner has all privileges" and add it
+ sSQL.append(
+ " UNION "
+ " SELECT current_database() AS TABLE_CAT, pn.nspname AS TABLE_SCHEM, c.relname AS TABLE_NAME,"
+ " ro.rolname AS GRANTOR, rg.rolname AS GRANTEE, p.privilege, 'YES' AS is_grantable"
+ " FROM pg_catalog.pg_class c,"
+ " (VALUES ('SELECT'), ('INSERT'), ('UPDATE'), ('DELETE'), ('TRUNCATE'), ('REFERENCES'), ('TRIGGER')) p (privilege),"
+ " pg_catalog.pg_roles ro,"
+ " ( SELECT oid, rolname FROM pg_catalog.pg_roles"
+ " UNION ALL"
+ " VALUES (0::oid, 'PUBLIC')"
+ " ) AS rg (oid, rolname),"
+ " pg_catalog.pg_namespace pn"
+ " WHERE c.relkind IN ('r', 'v') AND c.relacl IS NULL AND pg_has_role(rg.oid, c.relowner, 'USAGE')"
+ " AND c.relowner=ro.oid AND c.relnamespace = pn.oid");
+ sSQL.append(
+ " ) dp,"
+ " (SELECT oid, rolname FROM pg_catalog.pg_roles UNION ALL VALUES (0, 'PUBLIC')) pr"
+ " WHERE table_schem LIKE ? AND table_name LIKE ? AND (dp.grantee = 'PUBLIC' OR pg_has_role(pr.oid, dp.grantee, 'USAGE'))"
+ " ORDER BY table_schem, table_name, privilege" );
+
+ m_getTablePrivs_stmt = m_origin->prepareStatement( sSQL.makeStringAndClear() );
+
+ sSQL.append(
+ " SELECT dp.TABLE_CAT, dp.TABLE_SCHEM, dp.TABLE_NAME, dp.COLUMN_NAME, dp.GRANTOR, pr.rolname AS GRANTEE, dp.PRIVILEGE, dp.IS_GRANTABLE FROM ("
+ " SELECT table_catalog AS TABLE_CAT, table_schema AS TABLE_SCHEM, table_name, column_name,"
+ " grantor, grantee, privilege_type AS PRIVILEGE, is_grantable"
+ " FROM information_schema.column_privileges");
+ if ( PQserverVersion( m_pSettings->pConnection ) < 90200 )
+ // information_schema.table_privileges does not fill in default ACLs when no ACL
+ // assume default ACL is "owner has all privileges" and add it
+ sSQL.append(
+ " UNION "
+ " SELECT current_database() AS TABLE_CAT, pn.nspname AS TABLE_SCHEM, c.relname AS TABLE_NAME, a.attname AS column_name,"
+ " ro.rolname AS GRANTOR, rg.rolname AS GRANTEE, p.privilege, 'YES' AS is_grantable"
+ " FROM pg_catalog.pg_class c, pg_catalog.pg_attribute a,"
+ " (VALUES ('SELECT'), ('INSERT'), ('UPDATE'), ('REFERENCES')) p (privilege),"
+ " pg_catalog.pg_roles ro,"
+ " ( SELECT oid, rolname FROM pg_catalog.pg_roles"
+ " UNION ALL"
+ " VALUES (0::oid, 'PUBLIC')"
+ " ) AS rg (oid, rolname),"
+ " pg_catalog.pg_namespace pn"
+ " WHERE c.relkind IN ('r', 'v') AND c.relacl IS NULL AND pg_has_role(rg.oid, c.relowner, 'USAGE')"
+ " AND c.relowner=ro.oid AND c.relnamespace = pn.oid AND a.attrelid = c.oid AND a.attnum > 0");
+ sSQL.append(
+ " ) dp,"
+ " (SELECT oid, rolname FROM pg_catalog.pg_roles UNION ALL VALUES (0, 'PUBLIC')) pr"
+ " WHERE table_schem = ? AND table_name = ? AND column_name LIKE ? AND (dp.grantee = 'PUBLIC' OR pg_has_role(pr.oid, dp.grantee, 'USAGE'))"
+ " ORDER BY column_name, privilege" );
+
+ m_getColumnPrivs_stmt = m_origin->prepareStatement( sSQL.makeStringAndClear() );
+}
+
+css::uno::Reference< XResultSet > DatabaseMetaData::getImportedExportedKeys(
+ const Any& /* primaryCatalog */,
+ const OUString& primarySchema,
+ const OUString& primaryTable,
+ const Any& /* foreignCatalog */,
+ const OUString& foreignSchema,
+ const OUString& foreignTable )
+{
+ unsigned int i = 0;
+ if ( ! primarySchema.isEmpty() )
+ i |= 0x01;
+ if ( ! primaryTable.isEmpty() )
+ i |= 0x02;
+ if ( ! foreignSchema.isEmpty() )
+ i |= 0x04;
+ if ( ! foreignTable.isEmpty() )
+ i |= 0x08;
+
+ Reference< XPreparedStatement > stmt = m_getReferences_stmt[i];
+ Reference< XParameters > param ( stmt, UNO_QUERY_THROW );
+
+ unsigned int j = 1;
+ if ( i & 0x01 )
+ param->setString( j++, primarySchema );
+ if ( i & 0x02 )
+ param->setString( j++, primaryTable );
+ if ( i & 0x04 )
+ param->setString( j++, foreignSchema );
+ if ( i & 0x08 )
+ param->setString( j++, foreignTable );
+
+ Reference< XResultSet > rs = stmt->executeQuery();
+
+ return rs;
+}
+
+
+css::uno::Reference< XResultSet > DatabaseMetaData::getImportedKeys(
+ const css::uno::Any& catalog,
+ const OUString& schema,
+ const OUString& table )
+{
+ return getImportedExportedKeys(Any(), OUString(), OUString(), catalog, schema, table);
+}
+
+css::uno::Reference< XResultSet > DatabaseMetaData::getExportedKeys(
+ const css::uno::Any& catalog,
+ const OUString& schema,
+ const OUString& table )
+{
+ return getImportedExportedKeys(catalog, schema, table, Any(), OUString(), OUString());
+}
+
+css::uno::Reference< XResultSet > DatabaseMetaData::getCrossReference(
+ const css::uno::Any& primaryCatalog,
+ const OUString& primarySchema,
+ const OUString& primaryTable,
+ const css::uno::Any& foreignCatalog,
+ const OUString& foreignSchema,
+ const OUString& foreignTable )
+{
+ return getImportedExportedKeys( primaryCatalog, primarySchema, primaryTable, foreignCatalog, foreignSchema, foreignTable );
+}
+
+namespace
+{
+ struct TypeInfoByDataTypeSorter
+ {
+ bool operator () ( const std::vector< Any > & a, const std::vector< Any > & b )
+ {
+ OUString valueA;
+ OUString valueB;
+ a[1 /*DATA_TYPE*/] >>= valueA;
+ b[1 /*DATA_TYPE*/] >>= valueB;
+ if( valueB.toInt32() == valueA.toInt32() )
+ {
+ OUString nameA;
+ OUString nameB;
+ a[0 /*TYPE_NAME*/] >>= nameA;
+ b[0 /*TYPE_NAME*/] >>= nameB;
+ std::u16string_view nsA, tnA, nsB, tnB;
+
+ // parse typename into schema and typename
+ sal_Int32 nIndex=0;
+ nsA = o3tl::getToken(nameA, 0, '.', nIndex);
+ if (nIndex<0)
+ {
+ tnA = nsA;
+ nsA = std::u16string_view();
+ }
+ else
+ {
+ tnA = o3tl::getToken(nameA, 0, '.', nIndex);
+ assert(nIndex < 0);
+ }
+
+ nIndex=0;
+ nsB = o3tl::getToken(nameB, 0, '.', nIndex);
+ if (nIndex<0)
+ {
+ tnB = nsB;
+ nsB = std::u16string_view();
+ }
+ else
+ {
+ tnB = o3tl::getToken(nameB, 0, '.', nIndex);
+ assert(nIndex < 0);
+ }
+
+ const int ns_comp = compare_schema(nsA, nsB);
+ if(ns_comp == 0)
+ {
+ if(nsA.empty())
+ {
+ assert(nsB.empty());
+ // within each type category, sort privileged choice first
+ if( tnA == u"int4" || tnA == u"varchar" || tnA == u"char" || tnA == u"text")
+ return true;
+ if( tnB == u"int4" || tnB == u"varchar" || tnB == u"char" || tnB == u"text")
+ return false;
+ }
+ return nameA.compareTo( nameB ) < 0;
+ }
+ else
+ {
+ return ns_comp < 0;
+ }
+ }
+
+ return valueA.toInt32() < valueB.toInt32();
+ }
+ };
+
+ sal_Int32 calcSearchable( sal_Int32 dataType )
+ {
+ sal_Int32 ret = css::sdbc::ColumnSearch::FULL;
+ if( css::sdbc::DataType::BINARY == dataType ||
+ css::sdbc::DataType::VARBINARY == dataType ||
+ css::sdbc::DataType::LONGVARBINARY == dataType )
+ ret = css::sdbc::ColumnSearch::NONE;
+
+ return ret;
+ }
+
+ sal_Int32 getMaxScale( sal_Int32 dataType )
+ {
+ // LEM TODO: review, see where used, see JDBC, ...
+ sal_Int32 ret = 0;
+ if( dataType == css::sdbc::DataType::NUMERIC )
+ ret = 1000; // see pg-docs DataType/numeric
+// else if( dataType == DataType::DOUBLE )
+// ret = 308;
+// else if( dataType == DataType::FLOAT )
+// ret =
+ return ret;
+ }
+
+ OUString construct_full_typename(std::u16string_view ns, const OUString &tn)
+ {
+ if(ns.empty() || ns == u"pg_catalog")
+ return tn;
+ else
+ return OUString::Concat(ns) + "." + tn;
+ }
+
+ void pgTypeInfo2ResultSet(
+ std::vector< std::vector<Any> > &vec,
+ const Reference< XResultSet > &rs )
+ {
+ static const sal_Int32 TYPE_NAME = 0; // string Type name
+ static const sal_Int32 DATA_TYPE = 1; // short SQL data type from java.sql.Types
+ static const sal_Int32 PRECISION = 2; // long maximum precision
+ static const sal_Int32 CREATE_PARAMS = 5; // string => parameters used in creating the type (may be NULL )
+ static const sal_Int32 NULLABLE = 6; // short ==> can you use NULL for this type?
+ // - NO_NULLS - does not allow NULL values
+ // - NULLABLE - allows NULL values
+ // - NULLABLE_UNKNOWN - nullability unknown
+
+ static const sal_Int32 CASE_SENSITIVE = 7; // boolean==> is it case sensitive
+ static const sal_Int32 SEARCHABLE = 8; // short ==>; can you use
+ // "WHERE" based on this type:
+ // - NONE - No support
+ // - CHAR - Only supported with WHERE .. LIKE
+ // - BASIC - Supported except for WHERE .. LIKE
+ // - FULL - Supported for all WHERE ..
+ static const sal_Int32 UNSIGNED_ATTRIBUTE = 9; // boolean ==> is it unsigned?
+ // FIXED_PREC_SCALE = 10; boolean ==> can it be a money value?
+ static const sal_Int32 AUTO_INCREMENT = 11; // boolean ==> can it be used for
+ // an auto-increment value?
+ static const sal_Int32 MINIMUM_SCALE = 13; // short ==> minimum scale supported
+ static const sal_Int32 MAXIMUM_SCALE = 14; // short ==> maximum scale supported
+ static const sal_Int32 NUM_PREC_RADIX = 17; // long ==> usually 2 or 10
+
+ /* not filled so far
+ 3. LITERAL_PREFIX string ==> prefix used to quote a literal
+ (may be <NULL/>)
+ 4. LITERAL_SUFFIX string ==> suffix used to quote a literal
+ (may be <NULL/>)
+ 5. CREATE_PARAMS string ==> parameters used in creating the type (may be <NULL/>)
+ 12. LOCAL_TYPE_NAME string ==> localized version of type name (may be <NULL/>)
+ 15, SQL_DATA_TYPE long ==> unused
+ 16. SQL_DATETIME_SUB long ==> unused
+ */
+ Reference< XRow > xRow( rs, UNO_QUERY_THROW );
+ while( rs->next() )
+ {
+ std::vector< Any > row(18);
+
+ sal_Int32 dataType =typeNameToDataType(xRow->getString(5),xRow->getString(2));
+ sal_Int32 precision = xRow->getString(3).toInt32();
+
+ if( dataType == css::sdbc::DataType::CHAR ||
+ ( dataType == css::sdbc::DataType::VARCHAR &&
+ xRow->getString(TYPE_NAME+1).equalsIgnoreAsciiCase("varchar") ) )
+ {
+ // reflect varchar as varchar with upper limit !
+ //NOTE: the sql spec requires varchar to have an upper limit, however
+ // in postgresql the upper limit is optional, no limit means unlimited
+ // length (=1GB).
+ precision = 0x40000000; // about 1 GB, see character type docs in postgresql
+ row[CREATE_PARAMS] <<= OUString("length");
+ }
+ else if( dataType == css::sdbc::DataType::NUMERIC )
+ {
+ precision = 1000;
+ row[CREATE_PARAMS] <<= OUString("length, scale");
+ }
+
+ row[TYPE_NAME] <<= construct_full_typename(xRow->getString(6), xRow->getString(1));
+ row[DATA_TYPE] <<= OUString::number(dataType);
+ row[PRECISION] <<= OUString::number( precision );
+ sal_Int32 nullable = xRow->getBoolean(4) ?
+ css::sdbc::ColumnValue::NO_NULLS :
+ css::sdbc::ColumnValue::NULLABLE;
+ row[NULLABLE] <<= OUString::number(nullable);
+ row[CASE_SENSITIVE] <<= OUString::number(1);
+ row[SEARCHABLE] <<= OUString::number( calcSearchable( dataType ) );
+ row[UNSIGNED_ATTRIBUTE] <<= OUString("0");
+ if( css::sdbc::DataType::INTEGER == dataType ||
+ css::sdbc::DataType::BIGINT == dataType )
+ row[AUTO_INCREMENT] <<= OUString("1"); // TODO
+ else
+ row[AUTO_INCREMENT] <<= OUString("0"); // TODO
+ row[MINIMUM_SCALE] <<= OUString("0"); // TODO: what is this ?
+ row[MAXIMUM_SCALE] <<= OUString::number( getMaxScale( dataType ) );
+ row[NUM_PREC_RADIX] <<= OUString("10"); // TODO: what is this ?
+ vec.push_back( row );
+ }
+ }
+}
+
+
+css::uno::Reference< XResultSet > DatabaseMetaData::getTypeInfo( )
+{
+ // Note: Indexes start at 0 (in the API doc, they start at 1)
+ MutexGuard guard( m_xMutex->GetMutex() );
+
+ SAL_INFO("connectivity.postgresql", "DatabaseMetaData::getTypeInfo() got called");
+
+ Reference< XStatement > statement = m_origin->createStatement();
+ Reference< XResultSet > rs = statement->executeQuery(
+ "SELECT pg_type.typname AS typname," //1
+ "pg_type.typtype AS typtype," //2
+ "pg_type.typlen AS typlen," //3
+ "pg_type.typnotnull AS typnotnull," //4
+ "pg_type.typname AS typname, " //5
+ "pg_namespace.nspname as typns " //6
+ "FROM pg_type LEFT JOIN pg_namespace ON pg_type.typnamespace=pg_namespace.oid "
+ "WHERE pg_type.typtype = 'b' "
+ "OR pg_type.typtype = 'p'"
+ );
+
+ std::vector< std::vector<Any> > vec;
+ pgTypeInfo2ResultSet( vec, rs );
+
+ // check for domain types
+ rs = statement->executeQuery(
+ "SELECT t1.typname as typname,"
+ "t2.typtype AS typtype,"
+ "t2.typlen AS typlen,"
+ "t2.typnotnull AS typnotnull,"
+ "t2.typname as realtypname, "
+ "pg_namespace.nspname as typns "
+ "FROM pg_type as t1 LEFT JOIN pg_type AS t2 ON t1.typbasetype=t2.oid LEFT JOIN pg_namespace ON t1.typnamespace=pg_namespace.oid "
+ "WHERE t1.typtype = 'd'" );
+ pgTypeInfo2ResultSet( vec, rs );
+
+ std::sort( vec.begin(), vec.end(), TypeInfoByDataTypeSorter() );
+
+ return new SequenceResultSet(
+ m_xMutex,
+ *this,
+ std::vector(getStatics().typeinfoColumnNames),
+ std::move(vec),
+ m_pSettings->tc,
+ &( getStatics().typeInfoMetaData ));
+}
+
+
+css::uno::Reference< XResultSet > DatabaseMetaData::getIndexInfo(
+ const css::uno::Any& ,
+ const OUString& schema,
+ const OUString& table,
+ sal_Bool unique,
+ sal_Bool )
+{
+ //LEM TODO: review
+ MutexGuard guard( m_xMutex->GetMutex() );
+
+ /*
+ 1. TABLE_CAT string -> table catalog (may be NULL )
+ 2. TABLE_SCHEM string -> table schema (may be NULL )
+ 3. TABLE_NAME string -> table name
+ 4. NON_UNIQUE boolean -> Can index values be non-unique?
+ false when TYPE is tableIndexStatistic
+ 5. INDEX_QUALIFIER string -> index catalog (may be NULL );
+ NULL when TYPE is tableIndexStatistic
+ 6. INDEX_NAME string -> index name; NULL when TYPE is tableIndexStatistic
+ 7. TYPE short -> index type:
+ * 0 - this identifies table statistics that are returned
+ in conjunction with a table's index descriptions
+ * CLUSTERED - this is a clustered index
+ * HASHED - this is a hashed index
+ * OTHER - this is some other style of index
+ 8. ORDINAL_POSITION short -> column sequence number within index;
+ zero when TYPE is tableIndexStatistic
+ 9. COLUMN_NAME string -> column name; NULL when TYPE is tableIndexStatistic
+ 10. ASC_OR_DESC string -> column sort sequence, "A"= ascending,
+ "D" = descending, may be NULL if sort sequence
+ is not supported; NULL when TYPE is tableIndexStatistic
+ 11. CARDINALITY long -> When TYPE is tableIndexStatistic, then this is
+ the number of rows in the table; otherwise, it
+ is the number of unique values in the index.
+ 12. PAGES long -> When TYPE is tableIndexStatistic then this is
+ the number of pages used for the table, otherwise
+ it is the number of pages used for the current index.
+ 13. FILTER_CONDITION string -> Filter condition, if any. (may be NULL )
+
+ */
+ static const sal_Int32 C_SCHEMA = 1;
+ static const sal_Int32 C_TABLENAME = 2;
+ static const sal_Int32 C_INDEXNAME = 3;
+ static const sal_Int32 C_IS_CLUSTERED = 4;
+ static const sal_Int32 C_IS_UNIQUE = 5;
+ // C_IS_PRIMARY = 6
+ static const sal_Int32 C_COLUMNS = 7;
+
+ static const sal_Int32 R_TABLE_SCHEM = 1;
+ static const sal_Int32 R_TABLE_NAME = 2;
+ static const sal_Int32 R_NON_UNIQUE = 3;
+ static const sal_Int32 R_INDEX_NAME = 5;
+ static const sal_Int32 R_TYPE = 6;
+ static const sal_Int32 R_ORDINAL_POSITION = 7;
+ static const sal_Int32 R_COLUMN_NAME = 8;
+
+ Reference< XPreparedStatement > stmt = m_origin->prepareStatement(
+ "SELECT nspname, " // 1
+ "pg_class.relname, " // 2
+ "class2.relname, " // 3
+ "indisclustered, " // 4
+ "indisunique, " // 5
+ "indisprimary, " // 6
+ "indkey " // 7
+ "FROM pg_index INNER JOIN pg_class ON indrelid = pg_class.oid "
+ "INNER JOIN pg_namespace ON pg_class.relnamespace = pg_namespace.oid "
+ "INNER JOIN pg_class as class2 ON pg_index.indexrelid = class2.oid "
+ "WHERE nspname = ? AND pg_class.relname = ?" );
+
+ Reference< XParameters > param ( stmt, UNO_QUERY_THROW );
+ param->setString( 1, schema );
+ param->setString( 2, table );
+ Reference< XResultSet > rs = stmt->executeQuery();
+ Reference< XRow > xRow ( rs, UNO_QUERY_THROW );
+
+ std::vector< std::vector<Any> > vec;
+ while( rs->next() )
+ {
+ std::vector< sal_Int32 > columns = parseIntArray( xRow->getString(C_COLUMNS) );
+ Reference< XPreparedStatement > columnsStmt = m_origin->prepareStatement(
+ "SELECT attnum, attname "
+ "FROM pg_attribute "
+ " INNER JOIN pg_class ON attrelid = pg_class.oid "
+ " INNER JOIN pg_namespace ON pg_class.relnamespace=pg_namespace.oid "
+ " WHERE pg_namespace.nspname=? AND pg_class.relname=?" );
+ Reference< XParameters > paramColumn ( columnsStmt, UNO_QUERY_THROW );
+ OUString currentSchema = xRow->getString( C_SCHEMA );
+ OUString currentTable = xRow->getString( C_TABLENAME );
+ OUString currentIndexName = xRow->getString( C_INDEXNAME );
+ bool isNonUnique = ! xRow->getBoolean( C_IS_UNIQUE );
+ sal_Int32 indexType = xRow->getBoolean( C_IS_CLUSTERED ) ?
+ css::sdbc::IndexType::CLUSTERED :
+ css::sdbc::IndexType::HASHED;
+
+ paramColumn->setString( C_SCHEMA, currentSchema );
+ paramColumn->setString( C_TABLENAME, currentTable );
+
+ Reference< XResultSet > rsColumn = columnsStmt->executeQuery();
+ Reference< XRow > rowColumn( rsColumn, UNO_QUERY_THROW );
+ while( rsColumn->next() )
+ {
+ auto findIt = std::find( columns.begin(), columns.end(), rowColumn->getInt( 1 ) );
+ if( findIt != columns.end() && ( ! isNonUnique || ! unique ) )
+ {
+ std::vector< Any > result( 13 );
+ result[R_TABLE_SCHEM] <<= currentSchema;
+ result[R_TABLE_NAME] <<= currentTable;
+ result[R_INDEX_NAME] <<= currentIndexName;
+ result[R_NON_UNIQUE] <<= isNonUnique;
+ result[R_TYPE] <<= indexType;
+ result[R_COLUMN_NAME] <<= rowColumn->getString(2);
+ sal_Int32 nPos = static_cast<sal_Int32>(findIt - columns.begin() +1); // MSVC++ nonsense
+ result[R_ORDINAL_POSITION] <<= nPos;
+ vec.push_back( result );
+ }
+ }
+ }
+ return new SequenceResultSet(
+ m_xMutex, *this, std::vector(getStatics().indexinfoColumnNames),
+ std::move(vec),
+ m_pSettings->tc );
+}
+
+sal_Bool DatabaseMetaData::supportsResultSetType( sal_Int32 setType )
+{
+ if ( setType == css::sdbc::ResultSetType::SCROLL_SENSITIVE )
+ return false;
+ else
+ return true;
+}
+
+sal_Bool DatabaseMetaData::supportsResultSetConcurrency(
+ sal_Int32 setType, sal_Int32 )
+{
+ if ( ! supportsResultSetType( setType ) )
+ return false;
+ else
+ return true;
+}
+
+sal_Bool DatabaseMetaData::ownUpdatesAreVisible( sal_Int32 /* setType */ )
+{
+ return true;
+}
+
+sal_Bool DatabaseMetaData::ownDeletesAreVisible( sal_Int32 /* setType */ )
+{
+ return true;
+}
+
+sal_Bool DatabaseMetaData::ownInsertsAreVisible( sal_Int32 /* setType */ )
+{
+ return true;
+}
+
+sal_Bool DatabaseMetaData::othersUpdatesAreVisible( sal_Int32 /* setType */ )
+{
+ return false;
+}
+
+sal_Bool DatabaseMetaData::othersDeletesAreVisible( sal_Int32 /* setType */ )
+{
+ return false;
+}
+
+sal_Bool DatabaseMetaData::othersInsertsAreVisible( sal_Int32 /* setType */ )
+{
+ return false;
+}
+
+sal_Bool DatabaseMetaData::updatesAreDetected( sal_Int32 /* setType */ )
+{
+ return false;
+}
+
+sal_Bool DatabaseMetaData::deletesAreDetected( sal_Int32 /* setType */ )
+{
+ return false;
+}
+sal_Bool DatabaseMetaData::insertsAreDetected( sal_Int32 /* setType */ )
+{
+ return false;
+}
+
+sal_Bool DatabaseMetaData::supportsBatchUpdates( )
+{
+ return true;
+}
+
+css::uno::Reference< XResultSet > DatabaseMetaData::getUDTs( const css::uno::Any&, const OUString&, const OUString&, const css::uno::Sequence< sal_Int32 >& )
+{
+ //LEM TODO: implement! See JDBC driver
+ MutexGuard guard( m_xMutex->GetMutex() );
+ return new SequenceResultSet(
+ m_xMutex, *this, std::vector< OUString >(), std::vector< std::vector< Any > >(), m_pSettings->tc );
+}
+
+css::uno::Reference< css::sdbc::XConnection > DatabaseMetaData::getConnection()
+{
+ return m_origin;
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/postgresql/pq_databasemetadata.hxx b/connectivity/source/drivers/postgresql/pq_databasemetadata.hxx
new file mode 100644
index 0000000000..4e8b717a96
--- /dev/null
+++ b/connectivity/source/drivers/postgresql/pq_databasemetadata.hxx
@@ -0,0 +1,237 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * Effective License of whole file:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011:
+ *
+ * The Contents of this file are made available subject to the terms of
+ * the GNU Lesser General Public License Version 2.1
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * Contributor(s): Joerg Budischewski
+ *
+ * All parts contributed on or after August 2011:
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ ************************************************************************/
+
+#pragma once
+
+#include "pq_connection.hxx"
+#include <com/sun/star/sdbc/XDatabaseMetaData.hpp>
+
+#include <cppuhelper/implbase.hxx>
+
+namespace pq_sdbc_driver
+{
+
+class DatabaseMetaData :
+ public ::cppu::WeakImplHelper< css::sdbc::XDatabaseMetaData >
+{
+ ::rtl::Reference< comphelper::RefCountedMutex > m_xMutex;
+ ConnectionSettings *m_pSettings;
+ css::uno::Reference< css::sdbc::XConnection > m_origin;
+ css::uno::Reference< css::sdbc::XPreparedStatement > m_getIntSetting_stmt;
+ css::uno::Reference< css::sdbc::XPreparedStatement > m_getReferences_stmt[16];
+ css::uno::Reference< css::sdbc::XPreparedStatement > m_getTablePrivs_stmt;
+ css::uno::Reference< css::sdbc::XPreparedStatement > m_getColumnPrivs_stmt;
+
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ sal_Int32 getIntSetting(const OUString& settingName);
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ sal_Int32 getMaxIndexKeys();
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ sal_Int32 getMaxNameLength();
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ css::uno::Reference< css::sdbc::XResultSet > getImportedExportedKeys(
+ const css::uno::Any& primaryCatalog, const OUString& primarySchema, const OUString& primaryTable,
+ const css::uno::Any& foreignCatalog, const OUString& foreignSchema, const OUString& foreignTable );
+ void init_getReferences_stmt ();
+ void init_getPrivs_stmt ();
+
+public:
+ DatabaseMetaData(
+ ::rtl::Reference< comphelper::RefCountedMutex > reMutex,
+ css::uno::Reference< css::sdbc::XConnection > origin,
+ ConnectionSettings *pSettings
+ );
+
+public:
+ // Methods
+ virtual sal_Bool SAL_CALL allProceduresAreCallable( ) override;
+ virtual sal_Bool SAL_CALL allTablesAreSelectable( ) override;
+ virtual OUString SAL_CALL getURL( ) override;
+ virtual OUString SAL_CALL getUserName( ) override;
+ virtual sal_Bool SAL_CALL isReadOnly( ) override;
+ virtual sal_Bool SAL_CALL nullsAreSortedHigh( ) override;
+ virtual sal_Bool SAL_CALL nullsAreSortedLow( ) override;
+ virtual sal_Bool SAL_CALL nullsAreSortedAtStart( ) override;
+ virtual sal_Bool SAL_CALL nullsAreSortedAtEnd( ) override;
+ virtual OUString SAL_CALL getDatabaseProductName( ) override;
+ virtual OUString SAL_CALL getDatabaseProductVersion( ) override;
+ virtual OUString SAL_CALL getDriverName( ) override;
+ virtual OUString SAL_CALL getDriverVersion( ) override;
+ virtual sal_Int32 SAL_CALL getDriverMajorVersion( ) override;
+ virtual sal_Int32 SAL_CALL getDriverMinorVersion( ) override;
+ virtual sal_Bool SAL_CALL usesLocalFiles( ) override;
+ virtual sal_Bool SAL_CALL usesLocalFilePerTable( ) override;
+ virtual sal_Bool SAL_CALL supportsMixedCaseIdentifiers( ) override;
+ virtual sal_Bool SAL_CALL storesUpperCaseIdentifiers( ) override;
+ virtual sal_Bool SAL_CALL storesLowerCaseIdentifiers( ) override;
+ virtual sal_Bool SAL_CALL storesMixedCaseIdentifiers( ) override;
+ virtual sal_Bool SAL_CALL supportsMixedCaseQuotedIdentifiers( ) override;
+ virtual sal_Bool SAL_CALL storesUpperCaseQuotedIdentifiers( ) override;
+ virtual sal_Bool SAL_CALL storesLowerCaseQuotedIdentifiers( ) override;
+ virtual sal_Bool SAL_CALL storesMixedCaseQuotedIdentifiers( ) override;
+ virtual OUString SAL_CALL getIdentifierQuoteString( ) override;
+ virtual OUString SAL_CALL getSQLKeywords( ) override;
+ virtual OUString SAL_CALL getNumericFunctions( ) override;
+ virtual OUString SAL_CALL getStringFunctions( ) override;
+ virtual OUString SAL_CALL getSystemFunctions( ) override;
+ virtual OUString SAL_CALL getTimeDateFunctions( ) override;
+ virtual OUString SAL_CALL getSearchStringEscape( ) override;
+ virtual OUString SAL_CALL getExtraNameCharacters( ) override;
+ virtual sal_Bool SAL_CALL supportsAlterTableWithAddColumn( ) override;
+ virtual sal_Bool SAL_CALL supportsAlterTableWithDropColumn( ) override;
+ virtual sal_Bool SAL_CALL supportsColumnAliasing( ) override;
+ virtual sal_Bool SAL_CALL nullPlusNonNullIsNull( ) override;
+ virtual sal_Bool SAL_CALL supportsTypeConversion( ) override;
+ virtual sal_Bool SAL_CALL supportsConvert( sal_Int32 fromType, sal_Int32 toType ) override;
+ virtual sal_Bool SAL_CALL supportsTableCorrelationNames( ) override;
+ virtual sal_Bool SAL_CALL supportsDifferentTableCorrelationNames( ) override;
+ virtual sal_Bool SAL_CALL supportsExpressionsInOrderBy( ) override;
+ virtual sal_Bool SAL_CALL supportsOrderByUnrelated( ) override;
+ virtual sal_Bool SAL_CALL supportsGroupBy( ) override;
+ virtual sal_Bool SAL_CALL supportsGroupByUnrelated( ) override;
+ virtual sal_Bool SAL_CALL supportsGroupByBeyondSelect( ) override;
+ virtual sal_Bool SAL_CALL supportsLikeEscapeClause( ) override;
+ virtual sal_Bool SAL_CALL supportsMultipleResultSets( ) override;
+ virtual sal_Bool SAL_CALL supportsMultipleTransactions( ) override;
+ virtual sal_Bool SAL_CALL supportsNonNullableColumns( ) override;
+ virtual sal_Bool SAL_CALL supportsMinimumSQLGrammar( ) override;
+ virtual sal_Bool SAL_CALL supportsCoreSQLGrammar( ) override;
+ virtual sal_Bool SAL_CALL supportsExtendedSQLGrammar( ) override;
+ virtual sal_Bool SAL_CALL supportsANSI92EntryLevelSQL( ) override;
+ virtual sal_Bool SAL_CALL supportsANSI92IntermediateSQL( ) override;
+ virtual sal_Bool SAL_CALL supportsANSI92FullSQL( ) override;
+ virtual sal_Bool SAL_CALL supportsIntegrityEnhancementFacility( ) override;
+ virtual sal_Bool SAL_CALL supportsOuterJoins( ) override;
+ virtual sal_Bool SAL_CALL supportsFullOuterJoins( ) override;
+ virtual sal_Bool SAL_CALL supportsLimitedOuterJoins( ) override;
+ virtual OUString SAL_CALL getSchemaTerm( ) override;
+ virtual OUString SAL_CALL getProcedureTerm( ) override;
+ virtual OUString SAL_CALL getCatalogTerm( ) override;
+ virtual sal_Bool SAL_CALL isCatalogAtStart( ) override;
+ virtual OUString SAL_CALL getCatalogSeparator( ) override;
+ virtual sal_Bool SAL_CALL supportsSchemasInDataManipulation( ) override;
+ virtual sal_Bool SAL_CALL supportsSchemasInProcedureCalls( ) override;
+ virtual sal_Bool SAL_CALL supportsSchemasInTableDefinitions( ) override;
+ virtual sal_Bool SAL_CALL supportsSchemasInIndexDefinitions( ) override;
+ virtual sal_Bool SAL_CALL supportsSchemasInPrivilegeDefinitions( ) override;
+ virtual sal_Bool SAL_CALL supportsCatalogsInDataManipulation( ) override;
+ virtual sal_Bool SAL_CALL supportsCatalogsInProcedureCalls( ) override;
+ virtual sal_Bool SAL_CALL supportsCatalogsInTableDefinitions( ) override;
+ virtual sal_Bool SAL_CALL supportsCatalogsInIndexDefinitions( ) override;
+ virtual sal_Bool SAL_CALL supportsCatalogsInPrivilegeDefinitions( ) override;
+ virtual sal_Bool SAL_CALL supportsPositionedDelete( ) override;
+ virtual sal_Bool SAL_CALL supportsPositionedUpdate( ) override;
+ virtual sal_Bool SAL_CALL supportsSelectForUpdate( ) override;
+ virtual sal_Bool SAL_CALL supportsStoredProcedures( ) override;
+ virtual sal_Bool SAL_CALL supportsSubqueriesInComparisons( ) override;
+ virtual sal_Bool SAL_CALL supportsSubqueriesInExists( ) override;
+ virtual sal_Bool SAL_CALL supportsSubqueriesInIns( ) override;
+ virtual sal_Bool SAL_CALL supportsSubqueriesInQuantifieds( ) override;
+ virtual sal_Bool SAL_CALL supportsCorrelatedSubqueries( ) override;
+ virtual sal_Bool SAL_CALL supportsUnion( ) override;
+ virtual sal_Bool SAL_CALL supportsUnionAll( ) override;
+ virtual sal_Bool SAL_CALL supportsOpenCursorsAcrossCommit( ) override;
+ virtual sal_Bool SAL_CALL supportsOpenCursorsAcrossRollback( ) override;
+ virtual sal_Bool SAL_CALL supportsOpenStatementsAcrossCommit( ) override;
+ virtual sal_Bool SAL_CALL supportsOpenStatementsAcrossRollback( ) override;
+ virtual sal_Int32 SAL_CALL getMaxBinaryLiteralLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxCharLiteralLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxColumnNameLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxColumnsInGroupBy( ) override;
+ virtual sal_Int32 SAL_CALL getMaxColumnsInIndex( ) override;
+ virtual sal_Int32 SAL_CALL getMaxColumnsInOrderBy( ) override;
+ virtual sal_Int32 SAL_CALL getMaxColumnsInSelect( ) override;
+ virtual sal_Int32 SAL_CALL getMaxColumnsInTable( ) override;
+ virtual sal_Int32 SAL_CALL getMaxConnections( ) override;
+ virtual sal_Int32 SAL_CALL getMaxCursorNameLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxIndexLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxSchemaNameLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxProcedureNameLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxCatalogNameLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxRowSize( ) override;
+ virtual sal_Bool SAL_CALL doesMaxRowSizeIncludeBlobs( ) override;
+ virtual sal_Int32 SAL_CALL getMaxStatementLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxStatements( ) override;
+ virtual sal_Int32 SAL_CALL getMaxTableNameLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxTablesInSelect( ) override;
+ virtual sal_Int32 SAL_CALL getMaxUserNameLength( ) override;
+ virtual sal_Int32 SAL_CALL getDefaultTransactionIsolation( ) override;
+ virtual sal_Bool SAL_CALL supportsTransactions( ) override;
+ virtual sal_Bool SAL_CALL supportsTransactionIsolationLevel( sal_Int32 level ) override;
+ virtual sal_Bool SAL_CALL supportsDataDefinitionAndDataManipulationTransactions( ) override;
+ virtual sal_Bool SAL_CALL supportsDataManipulationTransactionsOnly( ) override;
+ virtual sal_Bool SAL_CALL dataDefinitionCausesTransactionCommit( ) override;
+ virtual sal_Bool SAL_CALL dataDefinitionIgnoredInTransactions( ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getProcedures( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& procedureNamePattern ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getProcedureColumns( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& procedureNamePattern, const OUString& columnNamePattern ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getTables( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& tableNamePattern, const css::uno::Sequence< OUString >& types ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getSchemas( ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getCatalogs( ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getTableTypes( ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getColumns( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& tableNamePattern, const OUString& columnNamePattern ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getColumnPrivileges( const css::uno::Any& catalog, const OUString& schema, const OUString& table, const OUString& columnNamePattern ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getTablePrivileges( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& tableNamePattern ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getBestRowIdentifier( const css::uno::Any& catalog, const OUString& schema, const OUString& table, sal_Int32 scope, sal_Bool nullable ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getVersionColumns( const css::uno::Any& catalog, const OUString& schema, const OUString& table ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getPrimaryKeys( const css::uno::Any& catalog, const OUString& schema, const OUString& table ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getImportedKeys( const css::uno::Any& catalog, const OUString& schema, const OUString& table ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getExportedKeys( const css::uno::Any& catalog, const OUString& schema, const OUString& table ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getCrossReference( const css::uno::Any& primaryCatalog, const OUString& primarySchema, const OUString& primaryTable, const css::uno::Any& foreignCatalog, const OUString& foreignSchema, const OUString& foreignTable ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getTypeInfo( ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getIndexInfo( const css::uno::Any& catalog, const OUString& schema, const OUString& table, sal_Bool unique, sal_Bool approximate ) override;
+ virtual sal_Bool SAL_CALL supportsResultSetType( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL supportsResultSetConcurrency( sal_Int32 setType, sal_Int32 concurrency ) override;
+ virtual sal_Bool SAL_CALL ownUpdatesAreVisible( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL ownDeletesAreVisible( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL ownInsertsAreVisible( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL othersUpdatesAreVisible( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL othersDeletesAreVisible( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL othersInsertsAreVisible( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL updatesAreDetected( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL deletesAreDetected( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL insertsAreDetected( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL supportsBatchUpdates( ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getUDTs( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& typeNamePattern, const css::uno::Sequence< sal_Int32 >& types ) override;
+ virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL getConnection( ) override;
+};
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/postgresql/pq_driver.cxx b/connectivity/source/drivers/postgresql/pq_driver.cxx
new file mode 100644
index 0000000000..8e07123a2b
--- /dev/null
+++ b/connectivity/source/drivers/postgresql/pq_driver.cxx
@@ -0,0 +1,142 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * Effective License of whole file:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011:
+ *
+ * The Contents of this file are made available subject to the terms of
+ * the GNU Lesser General Public License Version 2.1
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * Contributor(s): Joerg Budischewski
+ *
+ * All parts contributed on or after August 2011:
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ ************************************************************************/
+
+#include <cppuhelper/supportsservice.hxx>
+#include <cppuhelper/weak.hxx>
+#include <com/sun/star/lang/XSingleComponentFactory.hpp>
+
+#include "pq_driver.hxx"
+
+using com::sun::star::uno::Sequence;
+using com::sun::star::uno::Reference;
+using com::sun::star::uno::XInterface;
+using com::sun::star::uno::UNO_QUERY;
+using com::sun::star::uno::XComponentContext;
+using com::sun::star::uno::Any;
+
+using com::sun::star::beans::PropertyValue;
+
+using com::sun::star::sdbc::XConnection;
+using com::sun::star::sdbc::DriverPropertyInfo;
+
+using com::sun::star::sdbcx::XTablesSupplier;
+
+
+namespace pq_sdbc_driver
+{
+
+Reference< XConnection > Driver::connect(
+ const OUString& url,const Sequence< PropertyValue >& info )
+{
+ if( ! acceptsURL( url ) ) // XDriver spec tells me to do so ...
+ return Reference< XConnection > ();
+
+ Sequence< Any > seq{ Any(url), Any(info) };
+ return Reference< XConnection> (
+ m_smgr->createInstanceWithArgumentsAndContext(
+ "org.openoffice.comp.connectivity.pq.Connection.noext",
+ seq, m_ctx ),
+ UNO_QUERY );
+}
+
+sal_Bool Driver::acceptsURL( const OUString& url )
+{
+ return url.startsWith( "sdbc:postgresql:" );
+}
+
+Sequence< DriverPropertyInfo > Driver::getPropertyInfo(
+ const OUString&,const Sequence< PropertyValue >& )
+{
+ return Sequence< DriverPropertyInfo > ();
+}
+
+sal_Int32 Driver::getMajorVersion( )
+{
+ return PQ_SDBC_MAJOR;
+}
+
+
+sal_Int32 Driver::getMinorVersion( )
+{
+ return PQ_SDBC_MINOR;
+}
+
+ // XServiceInfo
+OUString SAL_CALL Driver::getImplementationName()
+{
+ return "org.openoffice.comp.connectivity.pq.Driver.noext";
+}
+
+sal_Bool Driver::supportsService(const OUString& ServiceName)
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+Sequence< OUString > Driver::getSupportedServiceNames()
+{
+ return { "com.sun.star.sdbc.Driver" };
+}
+
+// XComponent
+void Driver::disposing()
+{
+
+}
+
+
+Reference< XTablesSupplier > Driver::getDataDefinitionByConnection(
+ const Reference< XConnection >& connection )
+{
+ return Reference< XTablesSupplier >( connection , UNO_QUERY );
+}
+
+Reference< XTablesSupplier > Driver::getDataDefinitionByURL(
+ const OUString& url, const Sequence< PropertyValue >& info )
+{
+ return Reference< XTablesSupplier > ( connect( url, info ), UNO_QUERY );
+}
+
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+connectivity_pq_sdbc_driver_get_implementation(
+ css::uno::XComponentContext* context , css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new pq_sdbc_driver::Driver(context));
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/postgresql/pq_driver.hxx b/connectivity/source/drivers/postgresql/pq_driver.hxx
new file mode 100644
index 0000000000..31d407f369
--- /dev/null
+++ b/connectivity/source/drivers/postgresql/pq_driver.hxx
@@ -0,0 +1,116 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * Effective License of whole file:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011:
+ *
+ * The Contents of this file are made available subject to the terms of
+ * the GNU Lesser General Public License Version 2.1
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * Contributor(s): Joerg Budischewski
+ *
+ * All parts contributed on or after August 2011:
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ ************************************************************************/
+
+#pragma once
+
+#include <sal/macros.h>
+#include <cppuhelper/compbase.hxx>
+#include <cppuhelper/basemutex.hxx>
+
+#include <com/sun/star/lang/XServiceInfo.hpp>
+
+#include <com/sun/star/sdbc/XDriver.hpp>
+#include <com/sun/star/sdbcx/XDataDefinitionSupplier.hpp>
+
+#include <com/sun/star/uno/XComponentContext.hpp>
+
+namespace pq_sdbc_driver
+{
+
+#define PQ_SDBC_DRIVER_VERSION SAL_STRINGIFY(PQ_SDBC_MAJOR) "." \
+ SAL_STRINGIFY(PQ_SDBC_MINOR) "." \
+ SAL_STRINGIFY(PQ_SDBC_MICRO)
+
+// use this to switch off sdbc support !
+// typedef cppu::WeakComponentImplHelper<
+// css::sdbc::XDriver,
+// css::lang::XServiceInfo
+// > DriverBase ;
+typedef cppu::WeakComponentImplHelper<
+ css::sdbc::XDriver,
+ css::lang::XServiceInfo,
+ css::sdbcx::XDataDefinitionSupplier > DriverBase ;
+class Driver : public cppu::BaseMutex, public DriverBase
+{
+ css::uno::Reference< css::uno::XComponentContext > m_ctx;
+ css::uno::Reference< css::lang::XMultiComponentFactory > m_smgr;
+
+public:
+ explicit Driver ( const css::uno::Reference < css::uno::XComponentContext > & ctx )
+ : DriverBase( m_aMutex ),
+ m_ctx( ctx ),
+ m_smgr( ctx->getServiceManager() )
+ {}
+
+public: // XDriver
+ virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL connect(
+ const OUString& url,
+ const css::uno::Sequence< css::beans::PropertyValue >& info ) override;
+
+ virtual sal_Bool SAL_CALL acceptsURL( const OUString& url ) override;
+
+ virtual css::uno::Sequence< css::sdbc::DriverPropertyInfo > SAL_CALL getPropertyInfo(
+ const OUString& url,
+ const css::uno::Sequence< css::beans::PropertyValue >& info ) override;
+
+ virtual sal_Int32 SAL_CALL getMajorVersion( ) override;
+ virtual sal_Int32 SAL_CALL getMinorVersion( ) override;
+
+public:
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override;
+
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+ // XDataDefinitionSupplier
+ virtual css::uno::Reference< css::sdbcx::XTablesSupplier > SAL_CALL
+ getDataDefinitionByConnection(
+ const css::uno::Reference< css::sdbc::XConnection >& connection ) override;
+ virtual css::uno::Reference< css::sdbcx::XTablesSupplier > SAL_CALL
+ getDataDefinitionByURL(
+ const OUString& url,
+ const css::uno::Sequence< css::beans::PropertyValue >& info ) override;
+
+ // XComponent
+ virtual void SAL_CALL disposing() override;
+
+};
+
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/postgresql/pq_fakedupdateableresultset.cxx b/connectivity/source/drivers/postgresql/pq_fakedupdateableresultset.cxx
new file mode 100644
index 0000000000..216a252203
--- /dev/null
+++ b/connectivity/source/drivers/postgresql/pq_fakedupdateableresultset.cxx
@@ -0,0 +1,215 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * Effective License of whole file:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011:
+ *
+ * The Contents of this file are made available subject to the terms of
+ * the GNU Lesser General Public License Version 2.1
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * Contributor(s): Joerg Budischewski
+ *
+ * All parts contributed on or after August 2011:
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ ************************************************************************/
+
+#include "pq_fakedupdateableresultset.hxx"
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <cppuhelper/typeprovider.hxx>
+#include <cppuhelper/queryinterface.hxx>
+#include <utility>
+
+
+using com::sun::star::uno::Sequence;
+using com::sun::star::uno::Any;
+using com::sun::star::uno::Type;
+
+using com::sun::star::sdbc::SQLException;
+using com::sun::star::sdbc::XResultSetUpdate;
+using com::sun::star::sdbc::XRowUpdate;
+
+namespace pq_sdbc_driver
+{
+
+FakedUpdateableResultSet::FakedUpdateableResultSet(
+ const ::rtl::Reference< comphelper::RefCountedMutex > & mutex,
+ const css::uno::Reference< css::uno::XInterface > &owner,
+ ConnectionSettings **pSettings,
+ PGresult *result,
+ const OUString &schema,
+ const OUString &table,
+ OUString aReason )
+ : ResultSet( mutex, owner, pSettings, result, schema, table ),
+ m_aReason(std::move( aReason ))
+{}
+
+
+css::uno::Any FakedUpdateableResultSet::queryInterface(
+ const css::uno::Type & reqType )
+{
+ Any ret = ResultSet::queryInterface( reqType );
+ if( ! ret.hasValue() )
+ ret = ::cppu::queryInterface(
+ reqType,
+ static_cast< XResultSetUpdate * > ( this ),
+ static_cast< XRowUpdate * > ( this ) );
+ return ret;
+}
+
+
+css::uno::Sequence< css::uno::Type > FakedUpdateableResultSet::getTypes()
+{
+ static cppu::OTypeCollection s_collection(
+ cppu::UnoType<XResultSetUpdate>::get(),
+ cppu::UnoType<XRowUpdate>::get(),
+ ResultSet::getTypes());
+
+ return s_collection.getTypes();
+
+}
+
+css::uno::Sequence< sal_Int8> FakedUpdateableResultSet::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+void FakedUpdateableResultSet::insertRow( )
+{
+ throw SQLException( m_aReason, *this, OUString(),1,Any() );
+}
+
+void FakedUpdateableResultSet::updateRow( )
+{
+ throw SQLException( m_aReason, *this, OUString(),1,Any() );
+}
+
+void FakedUpdateableResultSet::deleteRow( )
+{
+ throw SQLException( m_aReason, *this, OUString(),1,Any() );
+ }
+
+void FakedUpdateableResultSet::cancelRowUpdates( )
+{
+ throw SQLException( m_aReason, *this, OUString(),1,Any() );
+}
+
+void FakedUpdateableResultSet::moveToInsertRow( )
+{
+ throw SQLException( m_aReason, *this, OUString(),1,Any() );
+}
+
+void FakedUpdateableResultSet::moveToCurrentRow( )
+{
+ throw SQLException( m_aReason, *this, OUString(),1,Any() );
+}
+
+
+void FakedUpdateableResultSet::updateNull( sal_Int32 /* columnIndex */ )
+{
+ throw SQLException( m_aReason, *this, OUString(),1,Any() );
+}
+
+void FakedUpdateableResultSet::updateBoolean( sal_Int32 /* columnIndex */, sal_Bool /* x */ )
+{
+ throw SQLException( m_aReason, *this, OUString(),1,Any() );
+}
+
+void FakedUpdateableResultSet::updateByte( sal_Int32 /* columnIndex */, sal_Int8 /* x */ )
+{
+ throw SQLException( m_aReason, *this, OUString(),1,Any() );
+}
+
+void FakedUpdateableResultSet::updateShort( sal_Int32 /* columnIndex */, sal_Int16 /* x */ )
+{
+ throw SQLException( m_aReason, *this, OUString(),1,Any() );
+}
+
+void FakedUpdateableResultSet::updateInt( sal_Int32 /* columnIndex */, sal_Int32 /* x */ )
+{
+ throw SQLException( m_aReason, *this, OUString(),1,Any() );
+}
+
+void FakedUpdateableResultSet::updateLong( sal_Int32 /* columnIndex */, sal_Int64 /* x */ )
+{
+ throw SQLException( m_aReason, *this, OUString(),1,Any() );
+}
+
+void FakedUpdateableResultSet::updateFloat( sal_Int32 /* columnIndex */, float /* x */ )
+{
+ throw SQLException( m_aReason, *this, OUString(),1,Any() );
+}
+
+void FakedUpdateableResultSet::updateDouble( sal_Int32 /* columnIndex */, double /* x */ )
+{
+ throw SQLException( m_aReason, *this, OUString(),1,Any() );
+}
+
+void FakedUpdateableResultSet::updateString( sal_Int32 /* columnIndex */, const OUString& /* x */ )
+{
+ throw SQLException( m_aReason, *this, OUString(),1,Any() );
+}
+
+void FakedUpdateableResultSet::updateBytes( sal_Int32 /* columnIndex */, const css::uno::Sequence< sal_Int8 >& /* x */ )
+{
+ throw SQLException( m_aReason, *this, OUString(),1,Any() );
+}
+
+void FakedUpdateableResultSet::updateDate( sal_Int32 /* columnIndex */, const css::util::Date& /* x */ )
+{
+ throw SQLException( m_aReason, *this, OUString(),1,Any() );
+}
+
+void FakedUpdateableResultSet::updateTime( sal_Int32 /* columnIndex */, const css::util::Time& /* x */ )
+{
+ throw SQLException( m_aReason, *this, OUString(),1,Any() );
+}
+
+void FakedUpdateableResultSet::updateTimestamp( sal_Int32 /* columnIndex */, const css::util::DateTime& /* x */ )
+{
+ throw SQLException( m_aReason, *this, OUString(),1,Any() );
+}
+
+void FakedUpdateableResultSet::updateBinaryStream( sal_Int32 /* columnIndex */, const css::uno::Reference< css::io::XInputStream >& /* x */, sal_Int32 /* length */ )
+{
+ throw SQLException( m_aReason, *this, OUString(),1,Any() );
+}
+
+void FakedUpdateableResultSet::updateCharacterStream( sal_Int32 /* columnIndex */, const css::uno::Reference< css::io::XInputStream >& /* x */, sal_Int32 /* length */ )
+{
+ throw SQLException( m_aReason, *this, OUString(),1,Any() );
+}
+
+void FakedUpdateableResultSet::updateObject( sal_Int32 /* columnIndex */, const css::uno::Any& /* x */ )
+{
+ throw SQLException( m_aReason, *this, OUString(),1,Any() );
+}
+
+void FakedUpdateableResultSet::updateNumericObject( sal_Int32 /* columnIndex */, const css::uno::Any& /* x */, sal_Int32 /* scale */ )
+{
+ throw SQLException( m_aReason, *this, OUString(),1,Any() );
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/postgresql/pq_fakedupdateableresultset.hxx b/connectivity/source/drivers/postgresql/pq_fakedupdateableresultset.hxx
new file mode 100644
index 0000000000..44e7dc9bcf
--- /dev/null
+++ b/connectivity/source/drivers/postgresql/pq_fakedupdateableresultset.hxx
@@ -0,0 +1,106 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * Effective License of whole file:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011:
+ *
+ * The Contents of this file are made available subject to the terms of
+ * the GNU Lesser General Public License Version 2.1
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * Contributor(s): Joerg Budischewski
+ *
+ * All parts contributed on or after August 2011:
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ ************************************************************************/
+
+#pragma once
+
+#include <com/sun/star/sdbc/XResultSetUpdate.hpp>
+#include <com/sun/star/sdbc/XRowUpdate.hpp>
+
+#include "pq_resultset.hxx"
+
+namespace pq_sdbc_driver
+{
+/** necessary to avoid crashes in OOo, when an updateable result set is requested,
+ but cannot be delivered.
+ */
+class FakedUpdateableResultSet :
+ public ResultSet,
+ public css::sdbc::XResultSetUpdate,
+ public css::sdbc::XRowUpdate
+{
+ OUString m_aReason;
+
+public:
+ FakedUpdateableResultSet(
+ const ::rtl::Reference< comphelper::RefCountedMutex > & mutex,
+ const css::uno::Reference< css::uno::XInterface > &owner,
+ ConnectionSettings **pSettings,
+ PGresult *result,
+ const OUString &schema,
+ const OUString &table,
+ OUString aReason );
+
+public: // XInterface
+ virtual void SAL_CALL acquire() noexcept override { ResultSet::acquire(); }
+ virtual void SAL_CALL release() noexcept override { ResultSet::release(); }
+ virtual css::uno::Any SAL_CALL queryInterface(
+ const css::uno::Type & reqType ) override;
+
+public: // XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override;
+ virtual css::uno::Sequence< sal_Int8> SAL_CALL getImplementationId() override;
+
+public: // XResultSetUpdate
+ virtual void SAL_CALL insertRow( ) override;
+ virtual void SAL_CALL updateRow( ) override;
+ virtual void SAL_CALL deleteRow( ) override;
+ virtual void SAL_CALL cancelRowUpdates( ) override;
+ virtual void SAL_CALL moveToInsertRow( ) override;
+ virtual void SAL_CALL moveToCurrentRow( ) override;
+
+public: // XRowUpdate
+ virtual void SAL_CALL updateNull( sal_Int32 columnIndex ) override;
+ virtual void SAL_CALL updateBoolean( sal_Int32 columnIndex, sal_Bool x ) override;
+ virtual void SAL_CALL updateByte( sal_Int32 columnIndex, sal_Int8 x ) override;
+ virtual void SAL_CALL updateShort( sal_Int32 columnIndex, sal_Int16 x ) override;
+ virtual void SAL_CALL updateInt( sal_Int32 columnIndex, sal_Int32 x ) override;
+ virtual void SAL_CALL updateLong( sal_Int32 columnIndex, sal_Int64 x ) override;
+ virtual void SAL_CALL updateFloat( sal_Int32 columnIndex, float x ) override;
+ virtual void SAL_CALL updateDouble( sal_Int32 columnIndex, double x ) override;
+ virtual void SAL_CALL updateString( sal_Int32 columnIndex, const OUString& x ) override;
+ virtual void SAL_CALL updateBytes( sal_Int32 columnIndex, const css::uno::Sequence< sal_Int8 >& x ) override;
+ virtual void SAL_CALL updateDate( sal_Int32 columnIndex, const css::util::Date& x ) override;
+ virtual void SAL_CALL updateTime( sal_Int32 columnIndex, const css::util::Time& x ) override;
+ virtual void SAL_CALL updateTimestamp( sal_Int32 columnIndex, const css::util::DateTime& x ) override;
+ virtual void SAL_CALL updateBinaryStream( sal_Int32 columnIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override;
+ virtual void SAL_CALL updateCharacterStream( sal_Int32 columnIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override;
+ virtual void SAL_CALL updateObject( sal_Int32 columnIndex, const css::uno::Any& x ) override;
+ virtual void SAL_CALL updateNumericObject( sal_Int32 columnIndex, const css::uno::Any& x, sal_Int32 scale ) override;
+
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/postgresql/pq_preparedstatement.cxx b/connectivity/source/drivers/postgresql/pq_preparedstatement.cxx
new file mode 100644
index 0000000000..e616e9b229
--- /dev/null
+++ b/connectivity/source/drivers/postgresql/pq_preparedstatement.cxx
@@ -0,0 +1,738 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * Effective License of whole file:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011:
+ *
+ * The Contents of this file are made available subject to the terms of
+ * the GNU Lesser General Public License Version 2.1
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * Contributor(s): Joerg Budischewski
+ *
+ * All parts contributed on or after August 2011:
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ ************************************************************************/
+
+#include <sal/log.hxx>
+#include "pq_preparedstatement.hxx"
+#include "pq_tools.hxx"
+#include "pq_statics.hxx"
+#include "pq_statement.hxx"
+
+#include <o3tl/safeint.hxx>
+#include <rtl/strbuf.hxx>
+#include <rtl/ustrbuf.hxx>
+
+
+#include <comphelper/sequence.hxx>
+
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <com/sun/star/sdbc/ResultSetConcurrency.hpp>
+#include <com/sun/star/sdbc/ResultSetType.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
+
+#include <memory>
+#include <string.h>
+#include <string_view>
+
+#include <connectivity/dbconversion.hxx>
+#include <utility>
+
+using osl::MutexGuard;
+
+
+using com::sun::star::uno::Any;
+using com::sun::star::uno::Type;
+using com::sun::star::uno::Sequence;
+using com::sun::star::uno::Reference;
+using com::sun::star::uno::UNO_QUERY;
+
+using com::sun::star::lang::IllegalArgumentException;
+
+using com::sun::star::sdbc::XCloseable;
+using com::sun::star::sdbc::XResultSet;
+using com::sun::star::sdbc::XRef;
+using com::sun::star::sdbc::XBlob;
+using com::sun::star::sdbc::XClob;
+using com::sun::star::sdbc::XArray;
+using com::sun::star::sdbc::XConnection;
+using com::sun::star::sdbc::SQLException;
+
+using com::sun::star::beans::Property;
+using com::sun::star::beans::XPropertySetInfo;
+
+using namespace dbtools;
+
+namespace pq_sdbc_driver
+{
+static ::cppu::IPropertyArrayHelper & getPreparedStatementPropertyArrayHelper()
+{
+ static ::cppu::OPropertyArrayHelper arrayHelper(
+ Sequence<Property>{
+ Property(
+ "CursorName", 0,
+ ::cppu::UnoType<OUString>::get() , 0 ),
+ Property(
+ "EscapeProcessing", 1,
+ cppu::UnoType<bool>::get() , 0 ),
+ Property(
+ "FetchDirection", 2,
+ ::cppu::UnoType<sal_Int32>::get() , 0 ),
+ Property(
+ "FetchSize", 3,
+ ::cppu::UnoType<sal_Int32>::get() , 0 ),
+ Property(
+ "MaxFieldSize", 4,
+ ::cppu::UnoType<sal_Int32>::get() , 0 ),
+ Property(
+ "MaxRows", 5,
+ ::cppu::UnoType<sal_Int32>::get() , 0 ),
+ Property(
+ "QueryTimeOut", 6,
+ ::cppu::UnoType<sal_Int32>::get() , 0 ),
+ Property(
+ "ResultSetConcurrency", 7,
+ ::cppu::UnoType<sal_Int32>::get() , 0 ),
+ Property(
+ "ResultSetType", 8,
+ ::cppu::UnoType<sal_Int32>::get() , 0 )},
+ true );
+ static ::cppu::IPropertyArrayHelper *pArrayHelper = &arrayHelper;
+
+ return *pArrayHelper;
+}
+
+static bool isOperator( char c )
+{
+ static const char * const operators = "<>=()!/&%.,;";
+
+ const char * w = operators;
+ while (*w && *w != c)
+ {
+ ++w;
+ }
+ return *w != 0;
+}
+
+static bool isNamedParameterStart( std::string_view o , int index )
+{
+ return o[index] == ':' && (
+ isWhitespace( o[index-1] ) || isOperator(o[index-1]) );
+}
+
+static bool isQuoted( std::string_view str )
+{
+ return str[0] == '"' || str[0] == '\'';
+}
+
+PreparedStatement::PreparedStatement(
+ const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex,
+ const Reference< XConnection > & conn,
+ struct ConnectionSettings *pSettings,
+ OString stmt )
+ : PreparedStatement_BASE(refMutex->GetMutex())
+ , OPropertySetHelper(PreparedStatement_BASE::rBHelper)
+ , m_connection(conn)
+ , m_pSettings(pSettings)
+ , m_stmt(std::move(stmt))
+ , m_xMutex(refMutex)
+ , m_multipleResultAvailable(false)
+ , m_multipleResultUpdateCount(0)
+ , m_lastOidInserted( InvalidOid )
+{
+ m_props[PREPARED_STATEMENT_QUERY_TIME_OUT] <<= sal_Int32(0);
+ m_props[PREPARED_STATEMENT_MAX_ROWS] <<= sal_Int32(0);
+ m_props[PREPARED_STATEMENT_RESULT_SET_CONCURRENCY] <<=
+ css::sdbc::ResultSetConcurrency::READ_ONLY;
+ m_props[PREPARED_STATEMENT_RESULT_SET_TYPE] <<=
+ css::sdbc::ResultSetType::SCROLL_INSENSITIVE;
+
+ splitSQL( m_stmt, m_splittedStatement );
+ int elements = 0;
+ for(const OString & str : m_splittedStatement)
+ {
+ // ignore quoted strings...
+ if( ! isQuoted( str ) )
+ {
+ // the ':' cannot be the first or the last part of the
+ // token,
+ // the ? cannot be the first part of the token , so we start
+ // at one
+ for( int index = 1 ; index < str.getLength() ; index ++ )
+ {
+ if( str[index] == '?' ||
+ isNamedParameterStart( str , index )
+ )
+ {
+ elements ++;
+ }
+ }
+ }
+ }
+ m_vars = std::vector< OString >( elements );
+}
+
+PreparedStatement::~PreparedStatement()
+{
+}
+
+void PreparedStatement::checkColumnIndex( sal_Int32 parameterIndex )
+{
+ if( parameterIndex < 1 || o3tl::make_unsigned(parameterIndex) > m_vars.size() )
+ {
+ throw SQLException(
+ "pq_preparedstatement: parameter index out of range (expected 1 to "
+ + OUString::number( m_vars.size() )
+ + ", got " + OUString::number( parameterIndex )
+ + ", statement '" + OStringToOUString( m_stmt, ConnectionSettings::encoding )
+ + "')",
+ *this, OUString(), 1, Any () );
+ }
+}
+void PreparedStatement::checkClosed()
+{
+ if( ! m_pSettings || ! m_pSettings->pConnection )
+ throw SQLException(
+ "pq_driver: PreparedStatement or connection has already been closed !",
+ *this, OUString(),1,Any());
+}
+
+Any PreparedStatement::queryInterface( const Type & rType )
+{
+ Any aRet = PreparedStatement_BASE::queryInterface(rType);
+ return aRet.hasValue() ? aRet : OPropertySetHelper::queryInterface(rType);
+}
+
+
+Sequence< Type > PreparedStatement::getTypes()
+{
+ static Sequence< Type > collection(
+ ::comphelper::concatSequences(
+ OPropertySetHelper::getTypes(),
+ PreparedStatement_BASE::getTypes()));
+
+ return collection;
+}
+
+Sequence< sal_Int8> PreparedStatement::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+void PreparedStatement::close( )
+{
+ // let the connection die without acquired mutex !
+ Reference< XConnection > r;
+ Reference< XCloseable > resultSet;
+ {
+ MutexGuard guard( m_xMutex->GetMutex() );
+ m_pSettings = nullptr;
+ r = m_connection;
+ m_connection.clear();
+
+ resultSet = m_lastResultset;
+ m_lastResultset.clear();
+ }
+ if( resultSet.is() )
+ {
+ resultSet->close();
+ }
+}
+
+void PreparedStatement::raiseSQLException( const char * errorMsg )
+{
+ OUStringBuffer buf(128);
+ buf.append( "pq_driver: "
+ + OUString( errorMsg, strlen(errorMsg) , ConnectionSettings::encoding )
+ + " (caused by statement '" );
+ buf.appendAscii( m_executedStatement.getStr() );
+ buf.append( "')" );
+ OUString error = buf.makeStringAndClear();
+ SAL_WARN("connectivity.postgresql", error);
+ throw SQLException( error, *this, OUString(), 1, Any() );
+}
+
+Reference< XResultSet > PreparedStatement::executeQuery( )
+{
+ if( ! execute( ) )
+ {
+ raiseSQLException( "not a query" );
+ }
+ return Reference< XResultSet > ( m_lastResultset, css::uno::UNO_QUERY );
+}
+
+sal_Int32 PreparedStatement::executeUpdate( )
+{
+ if( execute( ) )
+ {
+ raiseSQLException( "not a command" );
+ }
+ return m_multipleResultUpdateCount;
+}
+
+sal_Bool PreparedStatement::execute( )
+{
+ osl::MutexGuard guard( m_xMutex->GetMutex() );
+
+ OStringBuffer buf( m_stmt.getLength() *2 );
+
+ std::vector< OString >::size_type vars = 0;
+ for(const OString & str : m_splittedStatement)
+ {
+ // LEM TODO: instead of this manual mucking with SQL
+ // could we use PQexecParams / PQExecPrepared / ...?
+ // Only snafu is giving the types of the parameters and
+ // that it needs $1, $2, etc instead of "?"
+
+// printf( "Split %d %s\n" , i , str.getStr() );
+ if( isQuoted( str ) )
+ {
+ buf.append( str );
+ }
+ else
+ {
+ int start = 0,index;
+ for( index = 1 ; index < str.getLength() ; index ++ )
+ {
+ if( str[index] == '?' )
+ {
+ buf.append( str.getStr()+start, index - start );
+ buf.append( m_vars[vars] );
+ vars ++;
+ start =index+1;
+ }
+ else
+ {
+ if ( isNamedParameterStart( str, index ) )
+ {
+ buf.append( str.getStr()+start, index -start );
+ buf.append( m_vars[vars] );
+
+ // skip to the end of the named parameter
+ while ( index < str.getLength()
+ && !( isWhitespace(str[index])
+ || isOperator (str[index])))
+ {
+ ++index;
+ }
+ start = index;
+ vars ++;
+ }
+ }
+ }
+// if( index +1 >= str.getLength() )
+// {
+ buf.append( str.getStr() + start, index -start );
+// }
+ }
+ }
+
+ m_executedStatement = buf.makeStringAndClear();
+
+ Reference< XCloseable > lastResultSet = m_lastResultset;
+ if( lastResultSet.is() )
+ lastResultSet->close();
+
+ m_lastResultset.clear();
+ m_lastTableInserted.clear();
+
+ struct CommandData data;
+ data.refMutex = m_xMutex;
+ data.ppSettings = &m_pSettings;
+ data.pLastOidInserted = &m_lastOidInserted;
+ data.pLastQuery = &m_lastQuery;
+ data.pMultipleResultUpdateCount = &m_multipleResultUpdateCount;
+ data.pMultipleResultAvailable = &m_multipleResultAvailable;
+ data.pLastTableInserted = &m_lastTableInserted;
+ data.pLastResultset = &m_lastResultset;
+ data.owner = *this;
+ data.tableSupplier.set( m_connection, UNO_QUERY );
+ data.concurrency = extractIntProperty( this, getStatics().RESULT_SET_CONCURRENCY );
+
+ return executePostgresCommand( m_executedStatement , &data ); // see pq_statement.cxx
+}
+
+Reference< XConnection > PreparedStatement::getConnection( )
+{
+ Reference< XConnection > ret;
+ {
+ MutexGuard guard( m_xMutex->GetMutex() );
+ checkClosed();
+ ret = m_connection;
+ }
+ return ret;
+}
+
+
+void PreparedStatement::setNull( sal_Int32 parameterIndex, sal_Int32 )
+{
+ MutexGuard guard( m_xMutex->GetMutex() );
+ checkClosed();
+ checkColumnIndex( parameterIndex );
+ m_vars[parameterIndex-1] = "NULL"_ostr;
+}
+
+void PreparedStatement::setObjectNull(
+ sal_Int32 parameterIndex, sal_Int32, const OUString& )
+{
+ MutexGuard guard( m_xMutex->GetMutex() );
+ checkClosed();
+ checkColumnIndex( parameterIndex );
+ m_vars[parameterIndex-1] = "NULL"_ostr;
+}
+
+
+void PreparedStatement::setBoolean( sal_Int32 parameterIndex, sal_Bool x )
+{
+ MutexGuard guard(m_xMutex->GetMutex() );
+ checkClosed();
+ checkColumnIndex( parameterIndex );
+ if( x )
+ m_vars[parameterIndex-1] = "'t'"_ostr;
+ else
+ m_vars[parameterIndex-1] = "'f'"_ostr;
+}
+
+void PreparedStatement::setByte( sal_Int32 parameterIndex, sal_Int8 x )
+{
+ setInt(parameterIndex,x);
+}
+
+void PreparedStatement::setShort( sal_Int32 parameterIndex, sal_Int16 x )
+{
+ setInt(parameterIndex, x );
+}
+
+void PreparedStatement::setInt( sal_Int32 parameterIndex, sal_Int32 x )
+{
+// printf( "setString %d %d\n ", parameterIndex, x);
+ MutexGuard guard(m_xMutex->GetMutex() );
+ checkClosed();
+ checkColumnIndex( parameterIndex );
+ m_vars[parameterIndex-1] = "'" + OString::number(x) + "'";
+}
+
+void PreparedStatement::setLong( sal_Int32 parameterIndex, sal_Int64 x )
+{
+ MutexGuard guard(m_xMutex->GetMutex() );
+ checkClosed();
+ checkColumnIndex( parameterIndex );
+ m_vars[parameterIndex-1] = "'" + OString::number(x) + "'";
+}
+
+void PreparedStatement::setFloat( sal_Int32 parameterIndex, float x )
+{
+ MutexGuard guard(m_xMutex->GetMutex() );
+ checkClosed();
+ checkColumnIndex( parameterIndex );
+ m_vars[parameterIndex-1] = "'" + OString::number(x) + "'";
+}
+
+void PreparedStatement::setDouble( sal_Int32 parameterIndex, double x )
+{
+ MutexGuard guard(m_xMutex->GetMutex() );
+ checkClosed();
+ checkColumnIndex( parameterIndex );
+ m_vars[parameterIndex-1] = "'" + OString::number(x) + "'";
+}
+
+void PreparedStatement::setString( sal_Int32 parameterIndex, const OUString& x )
+{
+// printf( "setString %d %s\n ", parameterIndex,
+// OUStringToOString( x , RTL_TEXTENCODING_ASCII_US ).getStr());
+ MutexGuard guard(m_xMutex->GetMutex() );
+ checkClosed();
+ checkColumnIndex( parameterIndex );
+ OStringBuffer buf( 20 );
+ buf.append( "'" );
+ OString y = OUStringToOString( x, ConnectionSettings::encoding );
+ buf.ensureCapacity( y.getLength() * 2 + 2 );
+ int len = PQescapeString( const_cast<char*>(buf.getStr())+1, y.getStr() , y.getLength() );
+ buf.setLength( 1 + len );
+ buf.append( "'" );
+ m_vars[parameterIndex-1] = buf.makeStringAndClear();
+}
+
+void PreparedStatement::setBytes(
+ sal_Int32 parameterIndex, const Sequence< sal_Int8 >& x )
+{
+ MutexGuard guard(m_xMutex->GetMutex() );
+ checkClosed();
+ checkColumnIndex( parameterIndex );
+ size_t len;
+ const std::unique_ptr<unsigned char, deleter_from_fn<PQfreemem>> escapedString(
+ PQescapeBytea( reinterpret_cast<unsigned char const *>(x.getConstArray()), x.getLength(), &len));
+ if( ! escapedString )
+ {
+ throw SQLException(
+ "pq_preparedstatement.setBytes: Error during converting bytesequence to an SQL conform string",
+ *this, OUString(), 1, Any() );
+ }
+ m_vars[parameterIndex-1]
+ = OString::Concat("'") + std::string_view(reinterpret_cast<char *>(escapedString.get()), len -1) + "'";
+}
+
+
+void PreparedStatement::setDate( sal_Int32 parameterIndex, const css::util::Date& x )
+{
+ setString( parameterIndex, DBTypeConversion::toDateString( x ) );
+}
+
+void PreparedStatement::setTime( sal_Int32 parameterIndex, const css::util::Time& x )
+{
+ setString( parameterIndex, DBTypeConversion::toTimeString( x ) );
+}
+
+void PreparedStatement::setTimestamp(
+ sal_Int32 parameterIndex, const css::util::DateTime& x )
+{
+ setString( parameterIndex, DBTypeConversion::toDateTimeString( x ) );
+}
+
+void PreparedStatement::setBinaryStream(
+ sal_Int32,
+ const Reference< css::io::XInputStream >&,
+ sal_Int32 )
+{
+ throw SQLException(
+ "pq_preparedstatement: setBinaryStream not implemented",
+ *this, OUString(), 1, Any () );
+}
+
+void PreparedStatement::setCharacterStream(
+ sal_Int32,
+ const Reference< css::io::XInputStream >&,
+ sal_Int32 )
+{
+ throw SQLException(
+ "pq_preparedstatement: setCharacterStream not implemented",
+ *this, OUString(), 1, Any () );
+}
+
+void PreparedStatement::setObject( sal_Int32 parameterIndex, const Any& x )
+{
+ if( ! implSetObject( this, parameterIndex, x ))
+ {
+ throw SQLException(
+ "pq_preparedstatement::setObject: can't convert value of type " + x.getValueTypeName(),
+ *this, OUString(), 1, Any () );
+ }
+}
+
+void PreparedStatement::setObjectWithInfo(
+ sal_Int32 parameterIndex,
+ const Any& x,
+ sal_Int32 targetSqlType,
+ sal_Int32 )
+{
+ if( css::sdbc::DataType::DECIMAL == targetSqlType ||
+ css::sdbc::DataType::NUMERIC == targetSqlType )
+ {
+ double myDouble = 0.0;
+ OUString myString;
+ if( x >>= myDouble )
+ {
+ myString = OUString::number( myDouble );
+ }
+ else
+ {
+ x >>= myString;
+ }
+ if( myString.isEmpty() )
+ {
+ throw SQLException(
+ "pq_preparedstatement::setObjectWithInfo: can't convert value of type "
+ + x.getValueTypeName() + " to type DECIMAL or NUMERIC",
+ *this, OUString(), 1, Any () );
+ }
+
+ setString( parameterIndex, myString );
+ }
+ else
+ {
+ setObject( parameterIndex, x );
+ }
+
+}
+
+void PreparedStatement::setRef(
+ sal_Int32,
+ const Reference< XRef >& )
+{
+ throw SQLException(
+ "pq_preparedstatement: setRef not implemented",
+ *this, OUString(), 1, Any () );
+}
+
+void PreparedStatement::setBlob(
+ sal_Int32,
+ const Reference< XBlob >& )
+{
+ throw SQLException(
+ "pq_preparedstatement: setBlob not implemented",
+ *this, OUString(), 1, Any () );
+}
+
+void PreparedStatement::setClob(
+ sal_Int32,
+ const Reference< XClob >& )
+{
+ throw SQLException(
+ "pq_preparedstatement: setClob not implemented",
+ *this, OUString(), 1, Any () );
+}
+
+void PreparedStatement::setArray(
+ sal_Int32 parameterIndex,
+ const Reference< XArray >& x )
+{
+ setString( parameterIndex, array2String( x->getArray( nullptr ) ) );
+}
+
+void PreparedStatement::clearParameters( )
+{
+ MutexGuard guard(m_xMutex->GetMutex() );
+ m_vars = std::vector< OString >( m_vars.size() );
+}
+
+Any PreparedStatement::getWarnings( )
+{
+ return Any();
+}
+
+void PreparedStatement::clearWarnings( )
+{
+}
+
+Reference< css::sdbc::XResultSetMetaData > PreparedStatement::getMetaData()
+{
+ Reference< css::sdbc::XResultSetMetaData > ret;
+ Reference< css::sdbc::XResultSetMetaDataSupplier > supplier( m_lastResultset, UNO_QUERY );
+ if( supplier.is() )
+ ret = supplier->getMetaData();
+ return ret;
+}
+
+::cppu::IPropertyArrayHelper & PreparedStatement::getInfoHelper()
+{
+ return getPreparedStatementPropertyArrayHelper();
+}
+
+
+sal_Bool PreparedStatement::convertFastPropertyValue(
+ Any & rConvertedValue, Any & rOldValue, sal_Int32 nHandle, const Any& rValue )
+{
+ bool bRet;
+ rOldValue = m_props[nHandle];
+ switch( nHandle )
+ {
+ case PREPARED_STATEMENT_CURSOR_NAME:
+ {
+ OUString val;
+ bRet = ( rValue >>= val );
+ rConvertedValue <<= val;
+ break;
+ }
+ case PREPARED_STATEMENT_ESCAPE_PROCESSING:
+ {
+ bool val(false);
+ bRet = ( rValue >>= val );
+ rConvertedValue <<= val;
+ break;
+ }
+ case PREPARED_STATEMENT_FETCH_DIRECTION:
+ case PREPARED_STATEMENT_FETCH_SIZE:
+ case PREPARED_STATEMENT_MAX_FIELD_SIZE:
+ case PREPARED_STATEMENT_MAX_ROWS:
+ case PREPARED_STATEMENT_QUERY_TIME_OUT:
+ case PREPARED_STATEMENT_RESULT_SET_CONCURRENCY:
+ case PREPARED_STATEMENT_RESULT_SET_TYPE:
+ {
+ sal_Int32 val;
+ bRet = ( rValue >>= val );
+ rConvertedValue <<= val;
+ break;
+ }
+ default:
+ {
+ throw IllegalArgumentException(
+ "pq_statement: Invalid property handle ("
+ + OUString::number( nHandle ) + ")",
+ *this, 2 );
+ }
+ }
+ return bRet;
+}
+
+
+void PreparedStatement::setFastPropertyValue_NoBroadcast(
+ sal_Int32 nHandle,const Any& rValue )
+{
+ m_props[nHandle] = rValue;
+}
+
+void PreparedStatement::getFastPropertyValue( Any& rValue, sal_Int32 nHandle ) const
+{
+ rValue = m_props[nHandle];
+}
+
+Reference < XPropertySetInfo > PreparedStatement::getPropertySetInfo()
+{
+ return OPropertySetHelper::createPropertySetInfo( getPreparedStatementPropertyArrayHelper() );
+}
+
+void PreparedStatement::disposing()
+{
+ close();
+}
+
+
+Reference< XResultSet > PreparedStatement::getResultSet( )
+{
+ return Reference< XResultSet > ( m_lastResultset, css::uno::UNO_QUERY );
+}
+sal_Int32 PreparedStatement::getUpdateCount( )
+{
+ return m_multipleResultUpdateCount;
+}
+sal_Bool PreparedStatement::getMoreResults( )
+{
+ Reference< XCloseable > lastResultSet = m_lastResultset;
+ if( lastResultSet.is() )
+ lastResultSet->close();
+ m_multipleResultUpdateCount = -1;
+ return false;
+}
+
+Reference< XResultSet > PreparedStatement::getGeneratedValues( )
+{
+ osl::MutexGuard guard( m_xMutex->GetMutex() );
+ return getGeneratedValuesFromLastInsert(
+ m_pSettings, m_connection, m_lastOidInserted, m_lastTableInserted, m_lastQuery );
+}
+
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/postgresql/pq_preparedstatement.hxx b/connectivity/source/drivers/postgresql/pq_preparedstatement.hxx
new file mode 100644
index 0000000000..ed81420cec
--- /dev/null
+++ b/connectivity/source/drivers/postgresql/pq_preparedstatement.hxx
@@ -0,0 +1,221 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * Effective License of whole file:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011:
+ *
+ * The Contents of this file are made available subject to the terms of
+ * the GNU Lesser General Public License Version 2.1
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * Contributor(s): Joerg Budischewski
+ *
+ * All parts contributed on or after August 2011:
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ ************************************************************************/
+
+#pragma once
+#include <vector>
+
+#include <libpq-fe.h>
+
+#include <cppuhelper/propshlp.hxx>
+#include <cppuhelper/component.hxx>
+
+#include <com/sun/star/sdbc/XParameters.hpp>
+#include <com/sun/star/sdbc/XMultipleResults.hpp>
+#include <com/sun/star/sdbc/XGeneratedResultSet.hpp>
+#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
+
+#include "pq_connection.hxx"
+namespace pq_sdbc_driver
+{
+
+const sal_Int32 PREPARED_STATEMENT_CURSOR_NAME = 0;
+const sal_Int32 PREPARED_STATEMENT_ESCAPE_PROCESSING = 1;
+const sal_Int32 PREPARED_STATEMENT_FETCH_DIRECTION = 2;
+const sal_Int32 PREPARED_STATEMENT_FETCH_SIZE = 3;
+const sal_Int32 PREPARED_STATEMENT_MAX_FIELD_SIZE = 4;
+const sal_Int32 PREPARED_STATEMENT_MAX_ROWS = 5;
+const sal_Int32 PREPARED_STATEMENT_QUERY_TIME_OUT = 6;
+const sal_Int32 PREPARED_STATEMENT_RESULT_SET_CONCURRENCY = 7;
+const sal_Int32 PREPARED_STATEMENT_RESULT_SET_TYPE = 8;
+
+#define PREPARED_STATEMENT_SIZE 9
+
+typedef ::cppu::WeakComponentImplHelper< css::sdbc::XPreparedStatement,
+ css::sdbc::XParameters,
+ css::sdbc::XCloseable,
+ css::sdbc::XWarningsSupplier,
+ css::sdbc::XMultipleResults,
+ css::sdbc::XGeneratedResultSet,
+ css::sdbc::XResultSetMetaDataSupplier
+ > PreparedStatement_BASE;
+class PreparedStatement : public PreparedStatement_BASE,
+ public cppu::OPropertySetHelper
+{
+private:
+ css::uno::Any m_props[PREPARED_STATEMENT_SIZE];
+ css::uno::Reference< css::sdbc::XConnection > m_connection;
+ ConnectionSettings *m_pSettings;
+ css::uno::Reference< css::sdbc::XCloseable > m_lastResultset;
+ OString m_stmt;
+ OString m_executedStatement;
+ ::rtl::Reference< comphelper::RefCountedMutex > m_xMutex;
+ std::vector< OString > m_vars;
+ std::vector< OString > m_splittedStatement;
+ bool m_multipleResultAvailable;
+ sal_Int32 m_multipleResultUpdateCount;
+ sal_Int32 m_lastOidInserted;
+ OUString m_lastTableInserted;
+ OString m_lastQuery;
+
+public:
+ /**
+ * @param ppConnection The piece of memory, pConnection points to, is accessible
+ * as long as a reference to parameter con is held.
+ */
+ PreparedStatement( const rtl::Reference< comphelper::RefCountedMutex > & refMutex,
+ const css::uno::Reference< css::sdbc::XConnection> & con,
+ struct ConnectionSettings *pSettings,
+ OString stmt );
+
+ virtual ~PreparedStatement() override;
+public: // XInterface
+ virtual void SAL_CALL acquire() noexcept override { PreparedStatement_BASE::acquire(); }
+ virtual void SAL_CALL release() noexcept override { PreparedStatement_BASE::release(); }
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & reqType ) override;
+
+public: // XCloseable
+ virtual void SAL_CALL close( ) override;
+
+public: // XPreparedStatement
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL executeQuery() override;
+ virtual sal_Int32 SAL_CALL executeUpdate( ) override;
+ virtual sal_Bool SAL_CALL execute( ) override;
+ virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL getConnection( ) override;
+public: // XParameters
+ virtual void SAL_CALL setNull( sal_Int32 parameterIndex, sal_Int32 sqlType ) override;
+ virtual void SAL_CALL setObjectNull(
+ sal_Int32 parameterIndex, sal_Int32 sqlType, const OUString& typeName ) override;
+ virtual void SAL_CALL setBoolean( sal_Int32 parameterIndex, sal_Bool x ) override;
+ virtual void SAL_CALL setByte( sal_Int32 parameterIndex, sal_Int8 x ) override;
+ virtual void SAL_CALL setShort( sal_Int32 parameterIndex, sal_Int16 x ) override;
+ virtual void SAL_CALL setInt( sal_Int32 parameterIndex, sal_Int32 x ) override;
+ virtual void SAL_CALL setLong( sal_Int32 parameterIndex, sal_Int64 x ) override;
+ virtual void SAL_CALL setFloat( sal_Int32 parameterIndex, float x ) override;
+ virtual void SAL_CALL setDouble( sal_Int32 parameterIndex, double x ) override;
+ virtual void SAL_CALL setString( sal_Int32 parameterIndex, const OUString& x ) override;
+ virtual void SAL_CALL setBytes(
+ sal_Int32 parameterIndex, const css::uno::Sequence< sal_Int8 >& x ) override;
+ virtual void SAL_CALL setDate( sal_Int32 parameterIndex, const css::util::Date& x ) override;
+ virtual void SAL_CALL setTime( sal_Int32 parameterIndex, const css::util::Time& x ) override;
+ virtual void SAL_CALL setTimestamp(
+ sal_Int32 parameterIndex, const css::util::DateTime& x ) override;
+ virtual void SAL_CALL setBinaryStream(
+ sal_Int32 parameterIndex,
+ const css::uno::Reference< css::io::XInputStream >& x,
+ sal_Int32 length ) override;
+ virtual void SAL_CALL setCharacterStream(
+ sal_Int32 parameterIndex,
+ const css::uno::Reference< css::io::XInputStream >& x,
+ sal_Int32 length ) override;
+ virtual void SAL_CALL setObject( sal_Int32 parameterIndex, const css::uno::Any& x ) override;
+ virtual void SAL_CALL setObjectWithInfo(
+ sal_Int32 parameterIndex,
+ const css::uno::Any& x,
+ sal_Int32 targetSqlType,
+ sal_Int32 scale ) override;
+ virtual void SAL_CALL setRef(
+ sal_Int32 parameterIndex,
+ const css::uno::Reference< css::sdbc::XRef >& x ) override;
+ virtual void SAL_CALL setBlob(
+ sal_Int32 parameterIndex,
+ const css::uno::Reference< css::sdbc::XBlob >& x ) override;
+ virtual void SAL_CALL setClob(
+ sal_Int32 parameterIndex,
+ const css::uno::Reference< css::sdbc::XClob >& x ) override;
+ virtual void SAL_CALL setArray(
+ sal_Int32 parameterIndex,
+ const css::uno::Reference< css::sdbc::XArray >& x ) override;
+ virtual void SAL_CALL clearParameters( ) override;
+
+public: // XWarningsSupplier
+ virtual css::uno::Any SAL_CALL getWarnings( ) override;
+ virtual void SAL_CALL clearWarnings( ) override;
+
+public: // XTypeProvider, first implemented by OPropertySetHelper
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override;
+ virtual css::uno::Sequence< sal_Int8> SAL_CALL getImplementationId() override;
+
+public: // OPropertySetHelper
+ virtual cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override;
+
+ virtual sal_Bool SAL_CALL convertFastPropertyValue(
+ css::uno::Any & rConvertedValue,
+ css::uno::Any & rOldValue,
+ sal_Int32 nHandle,
+ const css::uno::Any& rValue ) override;
+
+ virtual void SAL_CALL setFastPropertyValue_NoBroadcast(
+ sal_Int32 nHandle,
+ const css::uno::Any& rValue ) override;
+
+ using ::cppu::OPropertySetHelper::getFastPropertyValue;
+
+ void SAL_CALL getFastPropertyValue(
+ css::uno::Any& rValue,
+ sal_Int32 nHandle ) const override;
+
+ // XPropertySet
+ css::uno::Reference < css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo() override;
+
+public: // XGeneratedResultSet
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL
+ getGeneratedValues( ) override;
+
+public: // XMultipleResults
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getResultSet( ) override;
+ virtual sal_Int32 SAL_CALL getUpdateCount( ) override;
+ virtual sal_Bool SAL_CALL getMoreResults( ) override;
+
+public: // XResultSetMetaDataSupplier (is required by framework (see
+ // dbaccess/source/core/api/preparedstatement.cxx::getMetaData() )
+ virtual css::uno::Reference< css::sdbc::XResultSetMetaData > SAL_CALL getMetaData( ) override;
+
+public: // OComponentHelper
+ virtual void SAL_CALL disposing() override;
+
+private:
+ void checkColumnIndex( sal_Int32 parameterIndex );
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void checkClosed();
+ /// @throws css::sdbc::SQLException
+ void raiseSQLException( const char * errorMsg );
+// PGresult *pgExecute( OString *pQuery );
+};
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/postgresql/pq_resultset.cxx b/connectivity/source/drivers/postgresql/pq_resultset.cxx
new file mode 100644
index 0000000000..0058041c87
--- /dev/null
+++ b/connectivity/source/drivers/postgresql/pq_resultset.cxx
@@ -0,0 +1,309 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * Effective License of whole file:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011:
+ *
+ * The Contents of this file are made available subject to the terms of
+ * the GNU Lesser General Public License Version 2.1
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * Contributor(s): Joerg Budischewski
+ *
+ * All parts contributed on or after August 2011:
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ ************************************************************************/
+
+#include "pq_resultset.hxx"
+#include "pq_resultsetmetadata.hxx"
+
+#include <connectivity/dbexception.hxx>
+
+#include <com/sun/star/sdbc/FetchDirection.hpp>
+#include <com/sun/star/sdbc/ResultSetConcurrency.hpp>
+#include <com/sun/star/sdbc/ResultSetType.hpp>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <utility>
+
+
+using osl::MutexGuard;
+
+using com::sun::star::uno::Any;
+using com::sun::star::uno::Reference;
+using com::sun::star::uno::XInterface;
+
+using com::sun::star::sdbc::SQLException;
+using com::sun::star::sdbc::XResultSetMetaData;
+
+
+namespace pq_sdbc_driver
+{
+
+void ResultSet::checkClosed()
+{
+ if( ! m_result )
+ {
+ throw SQLException( "pq_resultset: already closed",
+ *this, OUString(), 1, Any() );
+ }
+
+ if( ! m_ppSettings || ! *m_ppSettings || ! (*m_ppSettings)->pConnection )
+ {
+ throw SQLException( "pq_resultset: statement has been closed already",
+ *this, OUString(), 1, Any() );
+ }
+
+}
+
+ResultSet::ResultSet( const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex,
+ const Reference< XInterface > & owner,
+ ConnectionSettings **ppSettings,
+ PGresult * result,
+ OUString schema,
+ OUString table)
+ : BaseResultSet(
+ refMutex, owner, PQntuples( result ),
+ PQnfields( result ),(*ppSettings)->tc ),
+ m_result( result ),
+ m_schema(std::move( schema )),
+ m_table(std::move( table )),
+ m_ppSettings( ppSettings )
+{
+ // LEM TODO: shouldn't these things be inherited from the statement or something like that?
+ // Positioned update/delete not supported, so no cursor name
+ // Fetch direction and size are cursor-specific things, so not used now.
+ // Fetch size not set
+ m_props[ BASERESULTSET_FETCH_DIRECTION ] <<= css::sdbc::FetchDirection::UNKNOWN;
+ // No escape processing for now
+ m_props[ BASERESULTSET_ESCAPE_PROCESSING ] <<= false;
+ // Bookmarks not implemented for now
+ m_props[ BASERESULTSET_IS_BOOKMARKABLE ] <<= false;
+ m_props[ BASERESULTSET_RESULT_SET_CONCURRENCY ] <<= css::sdbc::ResultSetConcurrency::READ_ONLY;
+ m_props[ BASERESULTSET_RESULT_SET_TYPE ] <<= css::sdbc::ResultSetType::SCROLL_INSENSITIVE;
+}
+
+
+Any ResultSet::getValue( sal_Int32 columnIndex )
+{
+ Any ret;
+ if( PQgetisnull( m_result, m_row, columnIndex -1 ) )
+ {
+ m_wasNull = true;
+ }
+ else
+ {
+ m_wasNull = false;
+ ret <<= OUString(
+ PQgetvalue( m_result, m_row , columnIndex -1 ) ,
+ PQgetlength( m_result, m_row , columnIndex -1 ) ,
+ ConnectionSettings::encoding );
+
+ }
+ return ret;
+}
+
+ResultSet::~ResultSet()
+{}
+
+void ResultSet::close( )
+{
+ Reference< XInterface > owner;
+ {
+ MutexGuard guard( m_xMutex->GetMutex() );
+ if( m_result )
+ {
+ PQclear(m_result );
+ m_result = nullptr;
+ m_row = -1;
+ }
+ owner = m_owner;
+ m_owner.clear();
+ }
+}
+
+Reference< XResultSetMetaData > ResultSet::getMetaData( )
+{
+ MutexGuard guard( m_xMutex->GetMutex() );
+ checkClosed();
+ return new ResultSetMetaData(
+ m_xMutex, this, this, m_ppSettings, m_result, m_schema, m_table );
+}
+
+sal_Int32 ResultSet::findColumn( const OUString& columnName )
+{
+ MutexGuard guard( m_xMutex->GetMutex() );
+ checkClosed();
+ sal_Int32 res = PQfnumber( m_result,
+ OUStringToOString( columnName, ConnectionSettings::encoding ).getStr());
+ /* PQfnumber return -1 for not found, which is what we want
+ * other than that we use col number as 1-based not 0-based */
+ if(res >= 0)
+ {
+ res += 1;
+ }
+ else
+ {
+ ::dbtools::throwInvalidColumnException( columnName, *this );
+ assert(false);
+ }
+ return res;
+}
+
+static bool isNumber( const char * data, sal_Int32 len )
+{
+ bool ret = false;
+ if( len )
+ {
+ ret = true;
+ for( int i = 0 ; i < len ; i ++ )
+ {
+ if( ( data[i] >= '0' && data[i] <= '9' ) ||
+ data[i] == '-' || data[i] == '+' || data[i] == '.' || data[i] == ',' )
+ {
+ if( data[i] == '-' && i != 0 && i != len-1 )
+ {
+ // no number, maybe a date
+ ret = false;
+ break;
+ }
+ }
+ else
+ {
+ ret = false;
+ break;
+ }
+ }
+ }
+ return ret;
+}
+
+static bool isInteger( const char * data, sal_Int32 len )
+{
+ bool ret = false;
+ if( len )
+ {
+ ret = true;
+ for( int i = 0 ; i < len ; i ++ )
+ {
+ if( ( data[i] >= '0' && data[i] <= '9' ) ||
+ data[i] == '-' || data[i] == '+' )
+ {
+ if( data[i] == '-' && i != 0 && i != len-1 )
+ {
+ // no number, maybe a date
+ ret = false;
+ break;
+ }
+ }
+ else
+ {
+ ret = false;
+ break;
+ }
+ }
+ }
+ return ret;
+}
+
+static bool isDate( const char * data, sal_Int32 len )
+{
+ return 10 == len &&
+ '-' == data[4] &&
+ '-' == data[7] &&
+ isInteger( &(data[0]),4 ) &&
+ isInteger( &(data[5]),2) &&
+ isInteger( &(data[8]),2 );
+}
+
+static bool isTime( const char * data, sal_Int32 len )
+{
+ return 8 == len &&
+ ':' == data[2] &&
+ ':' == data[5] &&
+ isInteger( &(data[0]),2 ) &&
+ isInteger( &(data[3]),2) &&
+ isInteger( &(data[6]),2 );
+
+}
+
+static bool isTimestamp( const char * data, sal_Int32 len )
+{
+ return len == 19 && isDate( data, 10) && isTime( &(data[11]),8 );
+}
+
+sal_Int32 ResultSet::guessDataType( sal_Int32 column )
+{
+ // we don't look into more than 100 rows ...
+ sal_Int32 ret = css::sdbc::DataType::INTEGER;
+
+ int maxRows = std::min<sal_Int32>( m_rowCount, 100 );
+ for( int i = 0 ; i < maxRows ; i ++ )
+ {
+ if( ! PQgetisnull( m_result, i , column-1 ) )
+ {
+ const char * p = PQgetvalue( m_result, i , column -1 );
+ int len = PQgetlength( m_result, i , column -1 );
+
+ if( css::sdbc::DataType::INTEGER == ret )
+ {
+ if( ! isInteger( p,len ) )
+ ret = css::sdbc::DataType::NUMERIC;
+ }
+ if( css::sdbc::DataType::NUMERIC == ret )
+ {
+ if( ! isNumber( p,len ) )
+ {
+ ret = css::sdbc::DataType::DATE;
+ }
+ }
+ if( css::sdbc::DataType::DATE == ret )
+ {
+ if( ! isDate( p,len ) )
+ {
+ ret = css::sdbc::DataType::TIME;
+ }
+ }
+ if( css::sdbc::DataType::TIME == ret )
+ {
+ if( ! isTime( p,len ) )
+ {
+ ret = css::sdbc::DataType::TIMESTAMP;
+ }
+ }
+ if( css::sdbc::DataType::TIMESTAMP == ret )
+ {
+ if( ! isTimestamp( p,len ) )
+ {
+ ret = css::sdbc::DataType::LONGVARCHAR;
+ break;
+ }
+ }
+ }
+ }
+ return ret;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/postgresql/pq_resultset.hxx b/connectivity/source/drivers/postgresql/pq_resultset.hxx
new file mode 100644
index 0000000000..cf2888bf5b
--- /dev/null
+++ b/connectivity/source/drivers/postgresql/pq_resultset.hxx
@@ -0,0 +1,94 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * Effective License of whole file:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011:
+ *
+ * The Contents of this file are made available subject to the terms of
+ * the GNU Lesser General Public License Version 2.1
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * Contributor(s): Joerg Budischewski
+ *
+ * All parts contributed on or after August 2011:
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ ************************************************************************/
+
+#pragma once
+
+#include <cppuhelper/propshlp.hxx>
+#include <cppuhelper/component.hxx>
+
+#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XCloseable.hpp>
+#include <com/sun/star/sdbc/XColumnLocate.hpp>
+#include "pq_connection.hxx"
+#include "pq_baseresultset.hxx"
+
+namespace pq_sdbc_driver
+{
+
+class ResultSet : public BaseResultSet
+{
+protected:
+ PGresult *m_result;
+ OUString m_schema;
+ OUString m_table;
+ ConnectionSettings **m_ppSettings;
+
+protected:
+ /** mutex should be locked before called
+ */
+ virtual void checkClosed() override;
+
+ /** unchecked, acquire mutex before calling
+ */
+ virtual css::uno::Any getValue( sal_Int32 columnIndex ) override;
+
+public:
+ ResultSet(
+ const ::rtl::Reference< comphelper::RefCountedMutex > & mutex,
+ const css::uno::Reference< css::uno::XInterface > &owner,
+ ConnectionSettings **pSettings,
+ PGresult *result,
+ OUString schema,
+ OUString table );
+ virtual ~ResultSet() override;
+
+public: // XCloseable
+ virtual void SAL_CALL close( ) override;
+
+public: // XResultSetMetaDataSupplier
+ virtual css::uno::Reference< css::sdbc::XResultSetMetaData > SAL_CALL getMetaData( ) override;
+
+public: // XColumnLocate
+ virtual sal_Int32 SAL_CALL findColumn( const OUString& columnName ) override;
+
+public:
+ sal_Int32 guessDataType( sal_Int32 column );
+};
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/postgresql/pq_resultsetmetadata.cxx b/connectivity/source/drivers/postgresql/pq_resultsetmetadata.cxx
new file mode 100644
index 0000000000..26b11de279
--- /dev/null
+++ b/connectivity/source/drivers/postgresql/pq_resultsetmetadata.cxx
@@ -0,0 +1,441 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * Effective License of whole file:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011:
+ *
+ * The Contents of this file are made available subject to the terms of
+ * the GNU Lesser General Public License Version 2.1
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * Contributor(s): Joerg Budischewski
+ *
+ * All parts contributed on or after August 2011:
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ ************************************************************************/
+
+#include <rtl/ustrbuf.hxx>
+
+#include "pq_resultsetmetadata.hxx"
+#include "pq_resultset.hxx"
+#include "pq_tools.hxx"
+#include "pq_statics.hxx"
+
+#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
+#include <com/sun/star/sdbc/ColumnValue.hpp>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <utility>
+
+#include <string.h>
+
+using osl::MutexGuard;
+
+
+using com::sun::star::uno::Any;
+using com::sun::star::uno::Exception;
+using com::sun::star::uno::Reference;
+using com::sun::star::uno::UNO_QUERY;
+
+
+using com::sun::star::sdbc::SQLException;
+using com::sun::star::sdbc::XStatement;
+using com::sun::star::sdbc::XRow;
+using com::sun::star::sdbc::XResultSet;
+using com::sun::star::sdbcx::XColumnsSupplier;
+using com::sun::star::sdbcx::XTablesSupplier;
+
+using com::sun::star::beans::XPropertySet;
+using com::sun::star::container::XNameAccess;
+
+
+namespace pq_sdbc_driver
+{
+
+// struct ColumnMetaData
+// {
+// OUString tableName;
+// OUString schemaTableName;
+// OUString typeName;
+// css::sdbc::DataType type;
+// sal_Int32 precision;
+// sal_Int32 scale;
+// sal_Bool isCurrency;
+// sal_Bool isNullable;
+// sal_Bool isAutoIncrement;
+// sal_Bool isReadOnly;
+// sal_Bool isSigned;
+// };
+
+// is not exported by the postgres header
+const int PQ_VARHDRSZ = sizeof( sal_Int32 );
+
+static void extractPrecisionAndScale( sal_Int32 atttypmod, sal_Int32 *precision, sal_Int32 *scale )
+{
+ if( atttypmod < PQ_VARHDRSZ )
+ {
+ *precision = 0;
+ *scale = 0;
+ }
+ else
+ {
+ if( atttypmod & 0xffff0000 )
+ {
+ *precision = ( ( atttypmod - PQ_VARHDRSZ ) >> 16 ) & 0xffff;
+ *scale = (atttypmod - PQ_VARHDRSZ ) & 0xffff;
+ }
+ else
+ {
+ *precision = atttypmod - PQ_VARHDRSZ;
+ *scale = 0;
+ }
+ }
+}
+
+ResultSetMetaData::ResultSetMetaData(
+ ::rtl::Reference< comphelper::RefCountedMutex > refMutex,
+ css::uno::Reference< css::sdbc::XResultSet > origin,
+ ResultSet * pResultSet,
+ ConnectionSettings **ppSettings,
+ PGresult const *pResult,
+ OUString schemaName,
+ OUString tableName ) :
+ m_xMutex(std::move( refMutex )),
+ m_ppSettings( ppSettings ),
+ m_origin(std::move( origin )),
+ m_tableName(std::move( tableName )),
+ m_schemaName(std::move( schemaName )),
+ m_colDesc( PQnfields( pResult ) ),
+ m_pResultSet( pResultSet ),
+ m_checkedForTable( false ),
+ m_checkedForTypes( false ),
+ m_colCount( PQnfields( pResult ) )
+{
+
+ // extract all needed information from the result object, so that we don't
+ // need it anymore after this call !
+ for( int col = 0; col < m_colCount ; col ++ )
+ {
+ sal_Int32 size = PQfsize( pResult, col );
+ size = -1 == size ? 25 : size;
+ m_colDesc[col].displaySize = size;
+
+ extractPrecisionAndScale(
+ PQfmod( pResult, col ),
+ & ( m_colDesc[col].precision ),
+ & ( m_colDesc[col].scale ) );
+ char *name = PQfname( pResult, col );
+ m_colDesc[col].name = OUString( name, strlen(name) , ConnectionSettings::encoding );
+ m_colDesc[col].typeOid = PQftype( pResult, col );
+ m_colDesc[col].type = css::sdbc::DataType::LONGVARCHAR;
+ }
+}
+
+void ResultSetMetaData::checkForTypes()
+{
+ if( m_checkedForTypes )
+ return;
+
+ Reference< XStatement > stmt =
+ extractConnectionFromStatement( m_origin->getStatement() )->createStatement();
+ DisposeGuard guard( stmt );
+ OUStringBuffer buf(128);
+ buf.append( "SELECT oid, typname, typtype FROM pg_type WHERE ");
+ for( int i = 0 ; i < m_colCount ; i ++ )
+ {
+ if( i > 0 )
+ buf.append( " OR " );
+ int oid = m_colDesc[i].typeOid;
+ buf.append( "oid=" + OUString::number(static_cast<sal_Int32>(oid)) );
+ }
+ Reference< XResultSet > rs = stmt->executeQuery( buf.makeStringAndClear() );
+ Reference< XRow > xRow( rs, UNO_QUERY );
+ while( rs->next() )
+ {
+ Oid oid = xRow->getInt( 1 );
+ OUString typeName = xRow->getString( 2 );
+ OUString typType = xRow->getString( 3 );
+
+ sal_Int32 type = typeNameToDataType( typeName, typType );
+
+ for( sal_Int32 j = 0; j < m_colCount ; j ++ )
+ {
+ if( m_colDesc[j].typeOid == oid )
+ {
+ m_colDesc[j].typeName = typeName;
+ m_colDesc[j].type = type;
+ }
+ }
+ }
+ m_checkedForTypes = true;
+}
+
+void ResultSetMetaData::checkTable()
+{
+ if( m_checkedForTable )
+ return;
+
+ m_checkedForTable = true;
+ if( !m_tableName.getLength() )
+ return;
+
+ Reference< css::container::XNameAccess > tables = (*m_ppSettings)->tables;
+ if( ! tables.is() )
+ {
+
+ Reference< XTablesSupplier > supplier(
+ extractConnectionFromStatement( m_origin->getStatement() ), UNO_QUERY);
+ if( supplier.is() )
+ tables = supplier->getTables();
+ }
+ if( tables.is() )
+ {
+ const OUString name (getTableName ( 1 ));
+ const OUString schema (getSchemaName( 1 ));
+ const OUString composedName( schema.isEmpty() ? name : (schema + "." + name) );
+ tables->getByName( composedName ) >>= m_table;
+ }
+}
+
+sal_Int32 ResultSetMetaData::getIntColumnProperty( const OUString & name, int index, int def )
+{
+ sal_Int32 ret = def; // give defensive answers, when data is not available
+ try
+ {
+ MutexGuard guard( m_xMutex->GetMutex() );
+ checkColumnIndex( index );
+ Reference< XPropertySet > set = getColumnByIndex( index );
+
+ if( set.is() )
+ {
+ set->getPropertyValue( name ) >>= ret;
+ }
+ }
+ catch( css::uno::Exception & )
+ {
+ }
+ return ret;
+}
+
+bool ResultSetMetaData::getBoolColumnProperty( const OUString & name, int index, bool def )
+{
+ bool ret = def;
+ try
+ {
+ MutexGuard guard( m_xMutex->GetMutex() );
+ checkColumnIndex( index );
+ Reference< XPropertySet > set = getColumnByIndex( index );
+ if( set.is() )
+ {
+ set->getPropertyValue( name ) >>= ret;
+ }
+ }
+ catch( css::uno::Exception & )
+ {
+ }
+
+ return ret;
+}
+
+Reference< css::beans::XPropertySet > ResultSetMetaData::getColumnByIndex( int index )
+{
+ Reference< XPropertySet > ret;
+ checkTable();
+ if( m_table.is() )
+ {
+ OUString columnName = getColumnName( index );
+ Reference< XColumnsSupplier > supplier( m_table, UNO_QUERY );
+ if( supplier.is() )
+ {
+ Reference< XNameAccess > columns = supplier->getColumns();
+ if( columns.is() && columns->hasByName( columnName ) )
+ {
+ columns->getByName( columnName ) >>= ret;
+ }
+ }
+ }
+ return ret;
+}
+
+// Methods
+sal_Int32 ResultSetMetaData::getColumnCount( )
+{
+ return m_colCount;
+}
+
+sal_Bool ResultSetMetaData::isAutoIncrement( sal_Int32 column )
+{
+
+ bool ret = getBoolColumnProperty( getStatics().IS_AUTO_INCREMENT, column, false );
+ return ret;
+}
+
+sal_Bool ResultSetMetaData::isCaseSensitive( sal_Int32 )
+{
+ return true; // ??? hmm, numeric types or
+}
+
+sal_Bool ResultSetMetaData::isSearchable( sal_Int32 )
+{
+ return true; // mmm, what types are not searchable ?
+}
+
+sal_Bool ResultSetMetaData::isCurrency( sal_Int32 column )
+{
+ return getBoolColumnProperty( getStatics().IS_CURRENCY, column, false );
+}
+
+sal_Int32 ResultSetMetaData::isNullable( sal_Int32 column )
+{
+ return getIntColumnProperty(
+ getStatics().IS_NULLABLE, column, css::sdbc::ColumnValue::NULLABLE_UNKNOWN );
+}
+
+sal_Bool ResultSetMetaData::isSigned( sal_Int32 )
+{
+ return true;
+}
+
+sal_Int32 ResultSetMetaData::getColumnDisplaySize( sal_Int32 column )
+{
+ MutexGuard guard( m_xMutex->GetMutex() );
+ checkColumnIndex( column );
+ return m_colDesc[column-1].displaySize;
+}
+
+OUString ResultSetMetaData::getColumnLabel( sal_Int32 column )
+{
+ return getColumnName( column);
+}
+
+OUString ResultSetMetaData::getColumnName( sal_Int32 column )
+{
+ MutexGuard guard( m_xMutex->GetMutex() );
+ checkColumnIndex( column );
+
+ return m_colDesc[column-1].name;
+}
+
+OUString ResultSetMetaData::getSchemaName( sal_Int32 )
+{
+ return m_schemaName;
+}
+
+sal_Int32 ResultSetMetaData::getPrecision( sal_Int32 column )
+{
+ MutexGuard guard( m_xMutex->GetMutex() );
+ checkColumnIndex( column );
+ return m_colDesc[column-1].precision;
+}
+
+sal_Int32 ResultSetMetaData::getScale( sal_Int32 column )
+{
+ MutexGuard guard( m_xMutex->GetMutex() );
+ checkColumnIndex( column );
+ return m_colDesc[column-1].scale;
+}
+
+OUString ResultSetMetaData::getTableName( sal_Int32 )
+{
+// LEM TODO This is very fishy... Should probably return the table to which that column belongs!
+ return m_tableName;
+}
+
+OUString ResultSetMetaData::getCatalogName( sal_Int32 )
+{
+ // can do this through XConnection.getCatalog() !
+ return OUString();
+}
+sal_Int32 ResultSetMetaData::getColumnType( sal_Int32 column )
+{
+ int ret = getIntColumnProperty( getStatics().TYPE, column, -100 );
+ if( -100 == ret )
+ {
+ checkForTypes();
+ if( css::sdbc::DataType::LONGVARCHAR == m_colDesc[column-1].type && m_pResultSet )
+ m_colDesc[column-1].type = m_pResultSet->guessDataType( column );
+ ret = m_colDesc[column-1].type;
+ }
+ return ret;
+}
+
+OUString ResultSetMetaData::getColumnTypeName( sal_Int32 column )
+{
+ OUString ret; // give defensive answers, when data is not available
+ try
+ {
+ MutexGuard guard( m_xMutex->GetMutex() );
+ checkColumnIndex( column );
+ Reference< XPropertySet > set = getColumnByIndex( column );
+
+ if( set.is() )
+ {
+ set->getPropertyValue( getStatics().TYPE_NAME ) >>= ret;
+ }
+ else
+ {
+ checkForTypes();
+ ret = m_colDesc[column-1].typeName;
+ }
+ }
+ catch( css::uno::Exception & )
+ {
+ }
+ return ret;
+}
+
+
+sal_Bool ResultSetMetaData::isReadOnly( sal_Int32 )
+{
+ return false;
+}
+
+sal_Bool ResultSetMetaData::isWritable( sal_Int32 column )
+{
+ return ! isReadOnly( column ); // what's the sense if this method ?
+}
+
+sal_Bool ResultSetMetaData::isDefinitelyWritable( sal_Int32 column )
+{
+ return isWritable(column); // uhh, now it becomes really esoteric...
+}
+OUString ResultSetMetaData::getColumnServiceName( sal_Int32 )
+{
+ return OUString();
+}
+
+void ResultSetMetaData::checkColumnIndex(sal_Int32 columnIndex)
+{
+ if( columnIndex < 1 || columnIndex > m_colCount )
+ {
+ throw SQLException(
+ "pq_resultsetmetadata: index out of range (expected 1 to "
+ + OUString::number( m_colCount ) + ", got " + OUString::number( columnIndex ),
+ *this, OUString(), 1, Any() );
+ }
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/postgresql/pq_resultsetmetadata.hxx b/connectivity/source/drivers/postgresql/pq_resultsetmetadata.hxx
new file mode 100644
index 0000000000..71c98190ba
--- /dev/null
+++ b/connectivity/source/drivers/postgresql/pq_resultsetmetadata.hxx
@@ -0,0 +1,127 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * Effective License of whole file:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011:
+ *
+ * The Contents of this file are made available subject to the terms of
+ * the GNU Lesser General Public License Version 2.1
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * Contributor(s): Joerg Budischewski
+ *
+ * All parts contributed on or after August 2011:
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ ************************************************************************/
+
+#pragma once
+#include <vector>
+
+#include "pq_connection.hxx"
+
+#include <com/sun/star/sdbc/XResultSetMetaData.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+
+#include <cppuhelper/implbase.hxx>
+
+namespace pq_sdbc_driver
+{
+
+struct ColDesc
+{
+ OUString name;
+ sal_Int32 precision;
+ sal_Int32 scale;
+ sal_Int32 displaySize;
+ Oid typeOid;
+ OUString typeName;
+ sal_Int32 type;
+};
+
+class ResultSet;
+
+class ResultSetMetaData :
+ public ::cppu::WeakImplHelper< css::sdbc::XResultSetMetaData >
+{
+ ::rtl::Reference< comphelper::RefCountedMutex > m_xMutex;
+ ConnectionSettings **m_ppSettings;
+ css::uno::Reference< css::sdbc::XResultSet > m_origin;
+ css::uno::Reference< css::beans::XPropertySet > m_table;
+ OUString m_tableName;
+ OUString m_schemaName;
+ std::vector< ColDesc > m_colDesc;
+ ResultSet *m_pResultSet;
+
+ bool m_checkedForTable;
+ bool m_checkedForTypes;
+
+ sal_Int32 m_colCount;
+
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void checkColumnIndex( sal_Int32 columnIndex );
+ void checkTable();
+ void checkForTypes();
+ css::uno::Reference< css::beans::XPropertySet > getColumnByIndex( int index );
+
+ sal_Int32 getIntColumnProperty( const OUString & name, int index, int def );
+ bool getBoolColumnProperty( const OUString & name, int index, bool def );
+
+public:
+ ResultSetMetaData(
+ ::rtl::Reference< comphelper::RefCountedMutex > reMutex,
+ css::uno::Reference< css::sdbc::XResultSet > origin,
+ ResultSet *pResultSet,
+ ConnectionSettings **pSettings,
+ PGresult const *pResult,
+ OUString schemaName,
+ OUString tableName );
+
+public:
+ // Methods
+ virtual sal_Int32 SAL_CALL getColumnCount( ) override;
+ virtual sal_Bool SAL_CALL isAutoIncrement( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isCaseSensitive( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isSearchable( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isCurrency( sal_Int32 column ) override;
+ virtual sal_Int32 SAL_CALL isNullable( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isSigned( sal_Int32 column ) override;
+ virtual sal_Int32 SAL_CALL getColumnDisplaySize( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getColumnLabel( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getColumnName( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getSchemaName( sal_Int32 column ) override;
+ virtual sal_Int32 SAL_CALL getPrecision( sal_Int32 column ) override;
+ virtual sal_Int32 SAL_CALL getScale( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getTableName( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getCatalogName( sal_Int32 column ) override;
+ virtual sal_Int32 SAL_CALL getColumnType( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getColumnTypeName( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isReadOnly( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isWritable( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isDefinitelyWritable( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getColumnServiceName( sal_Int32 column ) override;
+};
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/postgresql/pq_sequenceresultset.cxx b/connectivity/source/drivers/postgresql/pq_sequenceresultset.cxx
new file mode 100644
index 0000000000..defb999060
--- /dev/null
+++ b/connectivity/source/drivers/postgresql/pq_sequenceresultset.cxx
@@ -0,0 +1,125 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * Effective License of whole file:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011:
+ *
+ * The Contents of this file are made available subject to the terms of
+ * the GNU Lesser General Public License Version 2.1
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * Contributor(s): Joerg Budischewski
+ *
+ * All parts contributed on or after August 2011:
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ ************************************************************************/
+
+
+#include "pq_sequenceresultset.hxx"
+#include "pq_sequenceresultsetmetadata.hxx"
+
+#include <connectivity/dbexception.hxx>
+
+#include <com/sun/star/sdbc/SQLException.hpp>
+
+using com::sun::star::sdbc::XResultSetMetaData;
+
+using com::sun::star::uno::Reference;
+using com::sun::star::uno::Any;
+
+namespace pq_sdbc_driver
+{
+
+void SequenceResultSet::checkClosed()
+{
+ // we never close :o)
+}
+
+
+Any SequenceResultSet::getValue( sal_Int32 columnIndex )
+{
+ m_wasNull = ! m_data[m_row][columnIndex -1 ].hasValue();
+ return m_data[m_row][columnIndex -1 ];
+}
+
+SequenceResultSet::SequenceResultSet(
+ const ::rtl::Reference< comphelper::RefCountedMutex > & mutex,
+ const css::uno::Reference< css::uno::XInterface > &owner,
+ std::vector< OUString >&& colNames,
+ std::vector< std::vector< Any > >&& data,
+ const Reference< css::script::XTypeConverter > & tc,
+ const ColumnMetaDataVector *pVec) :
+ BaseResultSet( mutex, owner, data.size(), colNames.size(), tc ),
+ m_data(std::move(data) ),
+ m_columnNames( std::move(colNames) )
+{
+ if( pVec )
+ {
+ m_meta = new SequenceResultSetMetaData( std::vector(*pVec), m_columnNames.size() );
+ }
+}
+
+SequenceResultSet::~SequenceResultSet()
+{
+
+}
+
+void SequenceResultSet::close( )
+{
+ // a noop
+}
+
+Reference< XResultSetMetaData > SAL_CALL SequenceResultSet::getMetaData( )
+{
+ if( ! m_meta.is() )
+ {
+ // Oh no, not again
+ throw css::sdbc::SQLException(
+ "pq_sequenceresultset: no meta supported ", *this,
+ // I did not find "IM001" in a specific standard,
+ // but it seems to be used by other systems (such as ODBC)
+ // and some parts of LibreOffice special-case it.
+ "IM001", 1, Any() );
+ }
+ return m_meta;
+}
+
+
+sal_Int32 SAL_CALL SequenceResultSet::findColumn(
+ const OUString& columnName )
+{
+ // no need to guard, as all members are readonly !
+ for( int i = 0 ;i < m_fieldCount ; i ++ )
+ {
+ if( columnName == m_columnNames[i] )
+ {
+ return i+1;
+ }
+ }
+ ::dbtools::throwInvalidColumnException( columnName, *this );
+ assert(false);
+ return 0; // Never reached
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/postgresql/pq_sequenceresultset.hxx b/connectivity/source/drivers/postgresql/pq_sequenceresultset.hxx
new file mode 100644
index 0000000000..64ac212b6b
--- /dev/null
+++ b/connectivity/source/drivers/postgresql/pq_sequenceresultset.hxx
@@ -0,0 +1,92 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * Effective License of whole file:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011:
+ *
+ * The Contents of this file are made available subject to the terms of
+ * the GNU Lesser General Public License Version 2.1
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * Contributor(s): Joerg Budischewski
+ *
+ * All parts contributed on or after August 2011:
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ ************************************************************************/
+
+#pragma once
+
+#include <cppuhelper/propshlp.hxx>
+#include <cppuhelper/component.hxx>
+
+#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XCloseable.hpp>
+#include <com/sun/star/sdbc/XColumnLocate.hpp>
+#include "pq_connection.hxx"
+#include "pq_baseresultset.hxx"
+#include "pq_statics.hxx"
+
+namespace pq_sdbc_driver
+{
+
+class SequenceResultSet : public BaseResultSet
+{
+protected:
+ std::vector< std::vector< css::uno::Any > > m_data;
+
+ std::vector< OUString > m_columnNames;
+ css::uno::Reference< css::sdbc::XResultSetMetaData > m_meta;
+
+protected:
+ /** mutex should be locked before called
+ */
+ virtual void checkClosed() override;
+
+ /** unchecked, acquire mutex before calling
+ */
+ virtual css::uno::Any getValue( sal_Int32 columnIndex ) override;
+
+public:
+ SequenceResultSet(
+ const ::rtl::Reference< comphelper::RefCountedMutex > & mutex,
+ const css::uno::Reference< css::uno::XInterface > &owner,
+ std::vector< OUString >&& colNames,
+ std::vector< std::vector< css::uno::Any > >&& data,
+ const css::uno::Reference< css::script::XTypeConverter > &tc,
+ const ColumnMetaDataVector *pVec = nullptr);
+ virtual ~SequenceResultSet() override;
+
+public: // XCloseable
+ virtual void SAL_CALL close( ) override;
+
+public: // XResultSetMetaDataSupplier
+ virtual css::uno::Reference< css::sdbc::XResultSetMetaData > SAL_CALL getMetaData( ) override;
+
+public: // XColumnLocate
+ virtual sal_Int32 SAL_CALL findColumn( const OUString& columnName ) override;
+};
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/postgresql/pq_sequenceresultsetmetadata.cxx b/connectivity/source/drivers/postgresql/pq_sequenceresultsetmetadata.cxx
new file mode 100644
index 0000000000..568e6bb9f4
--- /dev/null
+++ b/connectivity/source/drivers/postgresql/pq_sequenceresultsetmetadata.cxx
@@ -0,0 +1,191 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * Effective License of whole file:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011:
+ *
+ * The Contents of this file are made available subject to the terms of
+ * the GNU Lesser General Public License Version 2.1
+ *
+ * Copyright: 200? by Sun Microsystems, Inc.
+ *
+ * Contributor(s): Joerg Budischewski
+ *
+ * All parts contributed on or after August 2011:
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ ************************************************************************/
+
+#include "pq_sequenceresultsetmetadata.hxx"
+
+#include <com/sun/star/sdbc/SQLException.hpp>
+
+using com::sun::star::uno::Any;
+
+using com::sun::star::sdbc::SQLException;
+
+namespace pq_sdbc_driver
+{
+
+SequenceResultSetMetaData::SequenceResultSetMetaData(
+ ColumnMetaDataVector&& metaDataVector,
+ int colCount ) :
+ m_columnData( std::move(metaDataVector) ),
+ m_colCount( colCount )
+{
+}
+
+
+// Methods
+sal_Int32 SequenceResultSetMetaData::getColumnCount( )
+{
+ return m_colCount;
+}
+
+sal_Bool SequenceResultSetMetaData::isAutoIncrement( sal_Int32 column )
+{
+ checkColumnIndex( column );
+ return m_columnData[column-1].isAutoIncrement;
+}
+
+sal_Bool SequenceResultSetMetaData::isCaseSensitive( sal_Int32 /* column */ )
+{
+
+ return true; // ??? hmm, numeric types or
+}
+
+sal_Bool SequenceResultSetMetaData::isSearchable( sal_Int32 /* column */ )
+{
+ return true; // mmm, what types are not searchable ?
+}
+
+sal_Bool SequenceResultSetMetaData::isCurrency( sal_Int32 column )
+{
+ checkColumnIndex( column );
+ return m_columnData[column-1].isCurrency;
+}
+
+sal_Int32 SequenceResultSetMetaData::isNullable( sal_Int32 column )
+{
+ checkColumnIndex( column );
+ return m_columnData[column-1].isNullable ? 1 : 0;
+}
+
+sal_Bool SequenceResultSetMetaData::isSigned( sal_Int32 /* column */ )
+{
+ return true;
+}
+
+sal_Int32 SequenceResultSetMetaData::getColumnDisplaySize( sal_Int32 /* column */ )
+{
+ return 50;
+}
+
+OUString SequenceResultSetMetaData::getColumnLabel( sal_Int32 column )
+{
+ checkColumnIndex( column );
+ return m_columnData[column-1].columnName;
+}
+
+OUString SequenceResultSetMetaData::getColumnName( sal_Int32 column )
+{
+ checkColumnIndex( column );
+ return m_columnData[column-1].columnName;
+}
+
+OUString SequenceResultSetMetaData::getSchemaName( sal_Int32 column )
+{
+ checkColumnIndex( column );
+ return m_columnData[column-1].schemaTableName;
+}
+
+
+sal_Int32 SequenceResultSetMetaData::getPrecision( sal_Int32 column )
+{
+ checkColumnIndex( column );
+ return m_columnData[column-1].precision;
+}
+
+sal_Int32 SequenceResultSetMetaData::getScale( sal_Int32 column )
+{
+ checkColumnIndex( column );
+ return m_columnData[column-1].scale;
+}
+
+OUString SequenceResultSetMetaData::getTableName( sal_Int32 column )
+{
+ checkColumnIndex( column );
+ return m_columnData[column-1].tableName;
+}
+
+OUString SequenceResultSetMetaData::getCatalogName( sal_Int32 /* column */ )
+{
+ // can do this through XConnection.getCatalog() !
+ return OUString();
+}
+sal_Int32 SequenceResultSetMetaData::getColumnType( sal_Int32 column )
+{
+ checkColumnIndex( column );
+ return m_columnData[column-1].type;
+}
+
+OUString SequenceResultSetMetaData::getColumnTypeName( sal_Int32 column )
+{
+ checkColumnIndex( column );
+ return m_columnData[column-1].typeName;
+}
+
+
+sal_Bool SequenceResultSetMetaData::isReadOnly( sal_Int32 /* column */ )
+{
+ return false;
+}
+
+sal_Bool SequenceResultSetMetaData::isWritable( sal_Int32 column )
+{
+ return ! isReadOnly( column ); // what's the sense if this method ?
+}
+
+sal_Bool SequenceResultSetMetaData::isDefinitelyWritable( sal_Int32 column )
+{
+ return isWritable(column); // uhh, now it becomes really esoteric...
+}
+OUString SequenceResultSetMetaData::getColumnServiceName( sal_Int32 /* column */ )
+{
+ return OUString();
+}
+
+void SequenceResultSetMetaData::checkColumnIndex(sal_Int32 columnIndex)
+{
+ if( columnIndex < 1 || columnIndex > m_colCount )
+ {
+ throw SQLException(
+ "pq_sequenceresultsetmetadata: index out of range (expected 1 to "
+ + OUString::number( m_colCount )
+ + ", got " + OUString::number( columnIndex ),
+ *this, OUString(), 1, Any() );
+ }
+}
+
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/postgresql/pq_sequenceresultsetmetadata.hxx b/connectivity/source/drivers/postgresql/pq_sequenceresultsetmetadata.hxx
new file mode 100644
index 0000000000..3cd32ff66d
--- /dev/null
+++ b/connectivity/source/drivers/postgresql/pq_sequenceresultsetmetadata.hxx
@@ -0,0 +1,89 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * Effective License of whole file:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011:
+ *
+ * The Contents of this file are made available subject to the terms of
+ * the GNU Lesser General Public License Version 2.1
+ *
+ * Copyright: 200? by Sun Microsystems, Inc.
+ *
+ * Contributor(s): Joerg Budischewski
+ *
+ * All parts contributed on or after August 2011:
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ ************************************************************************/
+
+#pragma once
+
+#include <cppuhelper/implbase.hxx>
+#include <com/sun/star/sdbc/XResultSetMetaData.hpp>
+
+#include "pq_connection.hxx"
+#include "pq_statics.hxx"
+
+namespace pq_sdbc_driver
+{
+ class SequenceResultSetMetaData :
+ public ::cppu::WeakImplHelper< css::sdbc::XResultSetMetaData >
+ {
+ ColumnMetaDataVector m_columnData;
+ sal_Int32 m_colCount;
+
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void checkColumnIndex( sal_Int32 columnIndex );
+
+ public:
+ SequenceResultSetMetaData(
+ ColumnMetaDataVector&& vec,
+ int colCount );
+
+ public:
+ // Methods
+ virtual sal_Int32 SAL_CALL getColumnCount( ) override;
+ virtual sal_Bool SAL_CALL isAutoIncrement( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isCaseSensitive( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isSearchable( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isCurrency( sal_Int32 column ) override;
+ virtual sal_Int32 SAL_CALL isNullable( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isSigned( sal_Int32 column ) override;
+ virtual sal_Int32 SAL_CALL getColumnDisplaySize( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getColumnLabel( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getColumnName( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getSchemaName( sal_Int32 column ) override;
+ virtual sal_Int32 SAL_CALL getPrecision( sal_Int32 column ) override;
+ virtual sal_Int32 SAL_CALL getScale( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getTableName( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getCatalogName( sal_Int32 column ) override;
+ virtual sal_Int32 SAL_CALL getColumnType( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getColumnTypeName( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isReadOnly( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isWritable( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isDefinitelyWritable( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getColumnServiceName( sal_Int32 column ) override;
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/postgresql/pq_statement.cxx b/connectivity/source/drivers/postgresql/pq_statement.cxx
new file mode 100644
index 0000000000..648faa6981
--- /dev/null
+++ b/connectivity/source/drivers/postgresql/pq_statement.cxx
@@ -0,0 +1,887 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * Effective License of whole file:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011:
+ *
+ * The Contents of this file are made available subject to the terms of
+ * the GNU Lesser General Public License Version 2.1
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * Contributor(s): Joerg Budischewski
+ *
+ * All parts contributed on or after August 2011:
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ ************************************************************************/
+
+#include <sal/log.hxx>
+#include "pq_statement.hxx"
+#include "pq_fakedupdateableresultset.hxx"
+#include "pq_updateableresultset.hxx"
+#include "pq_tools.hxx"
+#include "pq_statics.hxx"
+
+#include <osl/time.h>
+
+#include <rtl/ustrbuf.hxx>
+
+#include <comphelper/sequence.hxx>
+
+#include <com/sun/star/sdbc/ResultSetConcurrency.hpp>
+#include <com/sun/star/sdbc/ResultSetType.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <com/sun/star/sdbc/XParameters.hpp>
+
+#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
+#include <com/sun/star/sdbcx/KeyType.hpp>
+#include <com/sun/star/sdbcx/XKeysSupplier.hpp>
+
+#include <com/sun/star/container/XIndexAccess.hpp>
+#include <com/sun/star/container/XEnumerationAccess.hpp>
+
+#include <cstddef>
+#include <string.h>
+#include <string_view>
+
+using osl::MutexGuard;
+
+
+using com::sun::star::uno::Any;
+using com::sun::star::uno::Type;
+using com::sun::star::uno::Sequence;
+using com::sun::star::uno::Reference;
+using com::sun::star::uno::XInterface;
+using com::sun::star::uno::UNO_QUERY;
+
+using com::sun::star::lang::IllegalArgumentException;
+
+using com::sun::star::sdbc::XCloseable;
+using com::sun::star::sdbc::XStatement;
+using com::sun::star::sdbc::XPreparedStatement;
+using com::sun::star::sdbc::XParameters;
+using com::sun::star::sdbc::XRow;
+using com::sun::star::sdbc::XResultSet;
+using com::sun::star::sdbc::XConnection;
+using com::sun::star::sdbc::SQLException;
+
+using com::sun::star::sdbcx::XColumnsSupplier;
+using com::sun::star::sdbcx::XKeysSupplier;
+
+using com::sun::star::beans::Property;
+using com::sun::star::beans::XPropertySetInfo;
+using com::sun::star::beans::XPropertySet;
+
+using com::sun::star::container::XNameAccess;
+using com::sun::star::container::XEnumerationAccess;
+using com::sun::star::container::XEnumeration;
+using com::sun::star::container::XIndexAccess;
+
+namespace pq_sdbc_driver
+{
+static ::cppu::IPropertyArrayHelper & getStatementPropertyArrayHelper()
+{
+ static ::cppu::OPropertyArrayHelper arrayHelper(
+ Sequence<Property>{
+ Property(
+ "CursorName", 0,
+ ::cppu::UnoType<OUString>::get() , 0 ),
+ Property(
+ "EscapeProcessing", 1,
+ cppu::UnoType<bool>::get() , 0 ),
+ Property(
+ "FetchDirection", 2,
+ ::cppu::UnoType<sal_Int32>::get() , 0 ),
+ Property(
+ "FetchSize", 3,
+ ::cppu::UnoType<sal_Int32>::get() , 0 ),
+ Property(
+ "MaxFieldSize", 4,
+ ::cppu::UnoType<sal_Int32>::get() , 0 ),
+ Property(
+ "MaxRows", 5,
+ ::cppu::UnoType<sal_Int32>::get() , 0 ),
+ Property(
+ "QueryTimeOut", 6,
+ ::cppu::UnoType<sal_Int32>::get() , 0 ),
+ Property(
+ "ResultSetConcurrency", 7,
+ ::cppu::UnoType<sal_Int32>::get() , 0 ),
+ Property(
+ "ResultSetType", 8,
+ ::cppu::UnoType<sal_Int32>::get() , 0 )},
+ true );
+
+ return arrayHelper;
+}
+
+Statement::Statement( const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex,
+ const Reference< XConnection > & conn,
+ struct ConnectionSettings *pSettings )
+ : Statement_BASE( refMutex->GetMutex() )
+ , OPropertySetHelper( Statement_BASE::rBHelper )
+ , m_connection( conn )
+ , m_pSettings( pSettings )
+ , m_xMutex( refMutex )
+ , m_multipleResultAvailable(false)
+ , m_multipleResultUpdateCount(0)
+ , m_lastOidInserted(InvalidOid)
+{
+ m_props[STATEMENT_QUERY_TIME_OUT] <<= sal_Int32(0);
+ m_props[STATEMENT_MAX_ROWS] <<= sal_Int32(0);
+ m_props[STATEMENT_RESULT_SET_CONCURRENCY] <<=
+ css::sdbc::ResultSetConcurrency::READ_ONLY;
+ m_props[STATEMENT_RESULT_SET_TYPE] <<=
+ css::sdbc::ResultSetType::SCROLL_INSENSITIVE;
+}
+
+Statement::~Statement()
+{
+}
+
+void Statement::checkClosed()
+{
+ if( ! m_pSettings || ! m_pSettings->pConnection )
+ throw SQLException(
+ "pq_driver: Statement or connection has already been closed !",
+ *this, OUString(),1,Any());
+}
+
+Any Statement::queryInterface( const Type & rType )
+{
+ Any aRet = Statement_BASE::queryInterface(rType);
+ return aRet.hasValue() ? aRet : OPropertySetHelper::queryInterface(rType);
+}
+
+
+Sequence< Type > Statement::getTypes()
+{
+ static Sequence< Type > collection(
+ ::comphelper::concatSequences(
+ OPropertySetHelper::getTypes(),
+ Statement_BASE::getTypes()));
+
+ return collection;
+}
+
+Sequence< sal_Int8> Statement::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+void Statement::close( )
+{
+ // let the connection die without acquired mutex !
+ Reference< XConnection > r;
+ Reference< XCloseable > resultSet;
+ {
+ MutexGuard guard( m_xMutex->GetMutex() );
+ m_pSettings = nullptr;
+ r = m_connection;
+ m_connection.clear();
+
+ resultSet = m_lastResultset;
+ m_lastResultset.clear();
+ }
+ if( resultSet.is() )
+ {
+ resultSet->close();
+ }
+
+}
+
+void Statement::raiseSQLException(
+ std::u16string_view sql, const char * errorMsg )
+{
+ OUString error = "pq_driver: "
+ + OUString( errorMsg, strlen(errorMsg), ConnectionSettings::encoding )
+ + " (caused by statement '" + sql + "')";
+ SAL_WARN("connectivity.postgresql", error);
+ throw SQLException( error, *this, OUString(), 1, Any() );
+}
+
+Reference< XResultSet > Statement::executeQuery(const OUString& sql )
+{
+ if( ! execute( sql ) )
+ {
+ raiseSQLException( sql, "not a query" );
+ }
+ return Reference< XResultSet > ( m_lastResultset, css::uno::UNO_QUERY );
+}
+
+sal_Int32 Statement::executeUpdate( const OUString& sql )
+{
+ if( execute( sql ) )
+ {
+ raiseSQLException( sql, "not a command" );
+ }
+ return m_multipleResultUpdateCount;
+}
+
+/// @throws SQLException
+static void raiseSQLException(
+ const Reference< XInterface> & owner,
+ std::string_view sql,
+ const char * errorMsg,
+ const char *errorType = nullptr )
+{
+ OUStringBuffer buf(128);
+ buf.append( "pq_driver: ");
+ if( errorType )
+ {
+ buf.append( "[" );
+ buf.appendAscii( errorType );
+ buf.append( "]" );
+ }
+ buf.append(
+ OUString( errorMsg, strlen(errorMsg) , ConnectionSettings::encoding )
+ + " (caused by statement '"
+ + OStringToOUString( sql, ConnectionSettings::encoding )
+ + "')" );
+ OUString error = buf.makeStringAndClear();
+ SAL_WARN("connectivity.postgresql", error);
+ throw SQLException( error, owner, OUString(), 1, Any() );
+}
+
+
+// returns the elements of the primary key of the given table
+// static Sequence< Reference< css::beans::XPropertySet > > lookupKeys(
+static std::vector< OUString > lookupKeys(
+ const Reference< css::container::XNameAccess > &tables,
+ const OUString & table,
+ OUString *pSchema,
+ OUString *pTable)
+{
+ std::vector< OUString > ret;
+ Reference< XKeysSupplier > keySupplier;
+ Statics & st = getStatics();
+
+ if( tables->hasByName( table ) )
+ tables->getByName( table ) >>= keySupplier;
+ else if( -1 == table.indexOf( '.' ) )
+ {
+ // it wasn't a fully qualified name. Now need to skip through all tables.
+ Reference< XEnumerationAccess > enumerationAccess( tables, UNO_QUERY );
+
+ Reference< css::container::XEnumeration > enumeration =
+ enumerationAccess->createEnumeration();
+ while( enumeration->hasMoreElements() )
+ {
+ Reference< XPropertySet > set;
+ enumeration->nextElement() >>= set;
+ OUString name;
+// OUString schema;
+
+ if( set->getPropertyValue( st.NAME ) >>= name )
+ {
+// printf( "searching %s %s\n",
+// OUStringToOString( schema, RTL_TEXTENCODING_ASCII_US ).getStr(),
+// OUStringToOString( name, RTL_TEXTENCODING_ASCII_US ).getStr() );
+ if( name == table )
+ {
+
+ if( keySupplier.is() )
+ {
+ // is ambiguous, as I don't know postgresql searchpath,
+ // I can't continue here, as I may write to a different table
+ keySupplier.clear();
+ SAL_INFO("connectivity.postgresql", "Can't offer updateable result set because table " << name << " is duplicated, add schema to resolve ambiguity");
+ break;
+ }
+ keySupplier.set( set, UNO_QUERY );
+ }
+ }
+ }
+ }
+ else
+ {
+ SAL_INFO("connectivity.postgresql", "Can't offer updateable result set ( table " << table << " is unknown)");
+ }
+
+ if( keySupplier.is() )
+ {
+ Reference< XPropertySet > set( keySupplier, UNO_QUERY );
+ set->getPropertyValue( getStatics().NAME ) >>= *pTable;
+ set->getPropertyValue( getStatics().SCHEMA_NAME ) >>= *pSchema;
+ set.clear();
+
+ Reference< XEnumerationAccess > keys ( keySupplier->getKeys(), UNO_QUERY );
+ Reference< XEnumeration > enumeration = keys->createEnumeration();
+ while( enumeration->hasMoreElements() )
+ {
+ enumeration->nextElement() >>= set;
+ sal_Int32 keyType = 0;
+ if( (set->getPropertyValue( st.TYPE ) >>= keyType ) &&
+ keyType == css::sdbcx::KeyType::PRIMARY )
+ {
+ Reference< XColumnsSupplier > columns( set, UNO_QUERY );
+ Reference< XIndexAccess > indexAccess( columns->getColumns(), UNO_QUERY );
+
+ int length = indexAccess->getCount();
+ ret.resize( length );
+// printf( "primary key for Table %s is ",
+// OUStringToOString( table, RTL_TEXTENCODING_ASCII_US ).getStr() );
+ for( int i = 0 ; i < length ; i ++ )
+ {
+ indexAccess->getByIndex( i ) >>= set;
+ OUString name;
+ set->getPropertyValue( st.NAME ) >>= name;
+ ret[i] = name;
+// printf( "%s," , OUStringToOString( name, RTL_TEXTENCODING_ASCII_US ).getStr() );
+ }
+// printf( "\n" );
+ }
+ }
+ if( ret.empty() )
+ {
+ SAL_INFO("connectivity.postgresql", "Can't offer updateable result set ( table " << table << " does not have a primary key)");
+ }
+ }
+ return ret;
+}
+
+bool executePostgresCommand( const OString & cmd, struct CommandData *data )
+{
+ ConnectionSettings *pSettings = *(data->ppSettings);
+
+ sal_Int32 duration = osl_getGlobalTimer();
+ PGresult *result = PQexec( pSettings->pConnection, cmd.getStr() );
+ duration = osl_getGlobalTimer() - duration;
+ if( ! result )
+ raiseSQLException(
+ data->owner, cmd, PQerrorMessage( pSettings->pConnection ) );
+
+ ExecStatusType state = PQresultStatus( result );
+ *(data->pLastOidInserted) = 0;
+ data->pLastTableInserted->clear();
+ *(data->pLastQuery) = cmd;
+
+ bool ret = false;
+ switch( state )
+ {
+ case PGRES_COMMAND_OK:
+ {
+ *(data->pMultipleResultUpdateCount) = atoi( PQcmdTuples( result ) );
+ *(data->pMultipleResultAvailable) = false;
+
+ // in case an oid value is available, we retrieve it
+ *(data->pLastOidInserted) = PQoidValue( result );
+
+ // in case it was a single insert, extract the name of the table,
+ // otherwise the table name is empty
+ *(data->pLastTableInserted) =
+ extractTableFromInsert( OStringToOUString( cmd, ConnectionSettings::encoding ) );
+
+ OString strMain = "executed command '" + cmd + "' successfully ('" + OString::number(*( data->pMultipleResultUpdateCount ))
+ + "), duration=" + OString::number(duration) + "ms";
+
+ OString strOption;
+ if( *(data->pLastOidInserted) )
+ {
+ strOption += ", usedOid=" + OString::number( *(data->pLastOidInserted) ) + ", diagnosedTable="
+ + OUStringToOString(*data->pLastTableInserted, ConnectionSettings::encoding);
+ }
+ SAL_INFO("connectivity.postgresql", strMain + strOption);
+ PQclear( result );
+ break;
+ }
+ case PGRES_TUPLES_OK: // success
+ {
+ // In case it is a single table, it has a primary key and all columns
+ // belonging to the primary key are in the result set, allow updateable result sets
+ // otherwise, don't
+ OUString table, schema;
+ std::vector< OString > vec;
+ tokenizeSQL( cmd, vec );
+ OUString sourceTable =
+ OStringToOUString(
+ extractSingleTableFromSelect( vec ), ConnectionSettings::encoding );
+
+ if( data->concurrency ==
+ css::sdbc::ResultSetConcurrency::UPDATABLE )
+ {
+ OString aReason;
+ if( sourceTable.getLength() )
+ {
+ std::vector< OUString > sourceTableKeys = lookupKeys(
+ pSettings->tables.is() ?
+ pSettings->tables : data->tableSupplier->getTables() ,
+ sourceTable,
+ &schema,
+ &table);
+
+ // check, whether the columns are in the result set (required !)
+ std::size_t i;
+ for( i = 0 ; i < sourceTableKeys.size() ; i ++ )
+ {
+ if( -1 == PQfnumber(
+ result,
+ OUStringToOString( sourceTableKeys[i] ,
+ ConnectionSettings::encoding ).getStr()) )
+ {
+ break;
+ }
+ }
+
+ if( !sourceTableKeys.empty() && i == sourceTableKeys.size() )
+ {
+ *(data->pLastResultset) =
+ UpdateableResultSet::createFromPGResultSet(
+ data->refMutex, data->owner, data->ppSettings, result,
+ schema, table, std::move(sourceTableKeys) );
+ }
+ else if( ! table.getLength() )
+ {
+ aReason = "can't support updateable resultset, because a single table in the "
+ "WHERE part of the statement could not be identified (" + cmd + ".";
+ }
+ else if( !sourceTableKeys.empty() )
+ {
+ aReason = "can't support updateable resultset for table "
+ + OUStringToOString( schema, ConnectionSettings::encoding ) + "."
+ + OUStringToOString( table, ConnectionSettings::encoding )
+ + ", because resultset does not contain a part of the primary key ( column "
+ + OUStringToOString( sourceTableKeys[i], ConnectionSettings::encoding )
+ + " is missing )";
+ }
+ else
+ {
+
+ aReason = "can't support updateable resultset for table "
+ + OUStringToOString( schema, ConnectionSettings::encoding ) + "."
+ + OUStringToOString( table, ConnectionSettings::encoding )
+ + ", because resultset table does not have a primary key ";
+ }
+ }
+ else
+ {
+ SAL_WARN("connectivity.postgresql", "can't support updateable result for selects with multiple tables (" << cmd << ")");
+ }
+ if( ! (*(data->pLastResultset)).is() )
+ {
+ SAL_WARN("connectivity.postgresql", aReason);
+
+ // TODO: How to react here correctly ?
+ // remove this piece of code
+ *(data->pLastResultset) =
+ new FakedUpdateableResultSet(
+ data->refMutex, data->owner,
+ data->ppSettings,result, schema, table,
+ OStringToOUString( aReason, ConnectionSettings::encoding) );
+ }
+
+ }
+ else if( sourceTable.getLength() > 0)
+ {
+ splitConcatenatedIdentifier( sourceTable, &schema, &table );
+ }
+
+ sal_Int32 returnedRows = PQntuples( result );
+ if( ! data->pLastResultset->is() )
+ *(data->pLastResultset) =
+ Reference< XCloseable > (
+ new ResultSet(
+ data->refMutex, data->owner,
+ data->ppSettings,result, schema, table ) );
+ *(data->pMultipleResultAvailable) = true;
+ ret = true;
+ SAL_INFO("connectivity.postgresql", "executed query '" << cmd << "' successfully, duration=" << duration << "ms, returnedRows=" << returnedRows << ".");
+ break;
+ }
+ case PGRES_EMPTY_QUERY:
+ case PGRES_COPY_OUT:
+ case PGRES_COPY_IN:
+ case PGRES_BAD_RESPONSE:
+ case PGRES_NONFATAL_ERROR:
+ case PGRES_FATAL_ERROR:
+ default:
+ raiseSQLException(
+ data->owner, cmd, PQresultErrorMessage( result ) , PQresStatus( state ) );
+ }
+ return ret;
+
+}
+
+static Sequence< OUString > getPrimaryKeyColumnNames(
+ const Reference< XConnection > & connection, const OUString &schemaName, const OUString &tableName )
+{
+ Sequence< OUString > ret;
+
+ Int2StringMap mapIndex2Name;
+ fillAttnum2attnameMap( mapIndex2Name, connection, schemaName, tableName );
+
+ // retrieve the primary key ...
+ Reference< XPreparedStatement > stmt = connection->prepareStatement(
+ "SELECT conkey " // 7
+ "FROM pg_constraint INNER JOIN pg_class ON conrelid = pg_class.oid "
+ "INNER JOIN pg_namespace ON pg_class.relnamespace = pg_namespace.oid "
+ "LEFT JOIN pg_class AS class2 ON confrelid = class2.oid "
+ "LEFT JOIN pg_namespace AS nmsp2 ON class2.relnamespace=nmsp2.oid "
+ "WHERE pg_class.relname = ? AND pg_namespace.nspname = ? AND pg_constraint.contype='p'" );
+ DisposeGuard guard( stmt );
+ Reference< XParameters > paras( stmt, UNO_QUERY );
+ paras->setString( 1 , tableName );
+ paras->setString( 2 , schemaName );
+ Reference< XResultSet > rs = stmt->executeQuery();
+ Reference< XRow > xRow( rs , UNO_QUERY );
+
+ if( rs->next() )
+ {
+ ret = convertMappedIntArray2StringArray( mapIndex2Name, string2intarray(xRow->getString( 1 ) ) );
+ }
+ return ret;
+}
+
+static void getAutoValues(
+ String2StringMap & result,
+ const Reference< XConnection > & connection,
+ const OUString &schemaName,
+ const OUString & tableName,
+ const ConnectionSettings *pConnectionSettings )
+{
+ OUString strDefaultValue = getColExprForDefaultSettingVal(pConnectionSettings);
+ Reference< XPreparedStatement > stmt = connection->prepareStatement(
+ "SELECT pg_attribute.attname, " + strDefaultValue +
+ "FROM pg_class, pg_namespace, pg_attribute "
+ "LEFT JOIN pg_attrdef ON pg_attribute.attrelid = pg_attrdef.adrelid AND "
+ "pg_attribute.attnum = pg_attrdef.adnum "
+ "WHERE pg_attribute.attrelid = pg_class.oid AND "
+ "pg_class.relnamespace = pg_namespace.oid AND "
+ "pg_namespace.nspname = ? AND "
+ // LEM TODO: this is weird; why "LIKE" and not "="?
+ // Most probably gives problems if tableName contains '%'
+ "pg_class.relname LIKE ? AND "
+ + strDefaultValue + " != ''"
+ );
+ DisposeGuard guard( stmt );
+ Reference< XParameters > paras( stmt, UNO_QUERY );
+ paras->setString( 1 , schemaName );
+ paras->setString( 2 , tableName );
+ Reference< XResultSet > rs = stmt->executeQuery();
+ Reference< XRow > xRow( rs , UNO_QUERY );
+
+ while( rs->next() )
+ {
+ result[ OUStringToOString( xRow->getString( 1 ), RTL_TEXTENCODING_ASCII_US) ] =
+ OUStringToOString( xRow->getString(2), RTL_TEXTENCODING_ASCII_US );
+ }
+}
+
+Reference< XResultSet > getGeneratedValuesFromLastInsert(
+ ConnectionSettings *pConnectionSettings,
+ const Reference< XConnection > &connection,
+ sal_Int32 nLastOid,
+ std::u16string_view lastTableInserted,
+ const OString & lastQuery )
+{
+ Reference< XResultSet > ret;
+ OUString query;
+ OUString schemaName, tableName;
+ splitConcatenatedIdentifier(
+ lastTableInserted, &schemaName, &tableName );
+
+ if( nLastOid && lastTableInserted.size() )
+ {
+ OUStringBuffer buf( 128 );
+ buf.append( "SELECT * FROM " );
+ if( schemaName.getLength() )
+ bufferQuoteQualifiedIdentifier(buf, schemaName, tableName, pConnectionSettings );
+ else
+ bufferQuoteIdentifier( buf, lastTableInserted, pConnectionSettings );
+ buf.append( " WHERE oid = " + OUString::number(nLastOid) );
+ query = buf.makeStringAndClear();
+ }
+ else if ( lastTableInserted.size() && lastQuery.getLength() )
+ {
+ // extract nameValue Pairs
+ String2StringMap namedValues;
+ extractNameValuePairsFromInsert( namedValues, lastQuery );
+
+ // debug ...
+// OStringBuffer buf( 128);
+// buf.append( "extracting name/value from '" );
+// buf.append( lastQuery.getStr() );
+// buf.append( "' to [" );
+// for( String2StringMap::iterator ii = namedValues.begin() ; ii != namedValues.end() ; ++ii )
+// {
+// buf.append( ii->first.getStr() );
+// buf.append( "=" );
+// buf.append( ii->second.getStr() );
+// buf.append( "," );
+// }
+// buf.append( "]\n" );
+// printf( "%s", buf.makeStringAndClear() );
+
+ // TODO: make also unqualified tables names work here. Have a look at 2.8.3. The Schema Search Path
+ // in postgresql doc
+
+ const Sequence< OUString > keyColumnNames = getPrimaryKeyColumnNames( connection, schemaName, tableName );
+ if( keyColumnNames.hasElements() )
+ {
+ OUStringBuffer buf( 128 );
+ buf.append( "SELECT * FROM " );
+ bufferQuoteQualifiedIdentifier(buf, schemaName, tableName, pConnectionSettings );
+ buf.append( " WHERE " );
+ bool bAdditionalCondition = false;
+ String2StringMap autoValues;
+ for( OUString const & columnNameUnicode : keyColumnNames )
+ {
+ OUString value;
+ OString columnName = OUStringToOString( columnNameUnicode, ConnectionSettings::encoding );
+ bool bColumnMatchNamedValue = false;
+ for (auto const& namedValue : namedValues)
+ {
+ if( columnName.equalsIgnoreAsciiCase( namedValue.first ) )
+ {
+ value = OStringToOUString( namedValue.second , ConnectionSettings::encoding );
+ bColumnMatchNamedValue = true;
+ break;
+ }
+ }
+
+ // check, if a column of the primary key was not inserted explicitly,
+ if( !bColumnMatchNamedValue )
+ {
+ if( autoValues.empty() )
+ {
+ getAutoValues( autoValues, connection, schemaName, tableName, pConnectionSettings );
+ }
+ // this could mean, that the column is a default or auto value, check this ...
+ bool bColumnMatchAutoValue = false;
+ for (auto const& autoValue : autoValues)
+ {
+ if( columnName.equalsIgnoreAsciiCase( autoValue.first ) )
+ {
+ // it is indeed an auto value.
+ value = OStringToOUString(autoValue.second, RTL_TEXTENCODING_ASCII_US );
+ // check, whether it is a sequence
+
+ if( autoValue.second.startsWith("nextval(") )
+ {
+ // retrieve current sequence value:
+ OUStringBuffer myBuf(128 );
+ myBuf.append( "SELECT currval(" );
+ myBuf.appendAscii( &(autoValue.second.getStr()[8]));
+ value = querySingleValue( connection, myBuf.makeStringAndClear() );
+ }
+ bColumnMatchAutoValue = true;
+ break;
+ }
+ }
+ if( !bColumnMatchAutoValue )
+ {
+ // it even was no autovalue, no sense to continue as we can't query the
+ // inserted row
+ buf.truncate();
+ break;
+ }
+ }
+
+ if( bAdditionalCondition )
+ buf.append( " AND " );
+ bufferQuoteIdentifier( buf, columnNameUnicode, pConnectionSettings );
+ buf.append( " = " + value );
+ bAdditionalCondition = true;
+ }
+ query = buf.makeStringAndClear();
+ }
+ }
+
+ if( query.getLength() )
+ {
+ Reference< css::sdbc::XStatement > stmt = connection->createStatement();
+ ret = stmt->executeQuery( query );
+ }
+
+ return ret;
+
+}
+
+sal_Bool Statement::execute( const OUString& sql )
+{
+ osl::MutexGuard guard( m_xMutex->GetMutex() );
+ checkClosed();
+ OString cmd = OUStringToOString( sql, m_pSettings );
+
+ Reference< XCloseable > lastResultSetHolder = m_lastResultset;
+ if( lastResultSetHolder.is() )
+ lastResultSetHolder->close();
+
+ m_lastResultset.clear();
+ m_lastTableInserted.clear();
+
+ struct CommandData data;
+ data.refMutex = m_xMutex;
+ data.ppSettings = &m_pSettings;
+ data.pLastOidInserted = &m_lastOidInserted;
+ data.pLastQuery = &m_lastQuery;
+ data.pMultipleResultUpdateCount = &m_multipleResultUpdateCount;
+ data.pMultipleResultAvailable = &m_multipleResultAvailable;
+ data.pLastTableInserted = &m_lastTableInserted;
+ data.pLastResultset = &m_lastResultset;
+ data.owner = *this;
+ data.tableSupplier.set( m_connection, UNO_QUERY );
+ data.concurrency =
+ extractIntProperty( this, getStatics().RESULT_SET_CONCURRENCY );
+ return executePostgresCommand( cmd , &data );
+}
+
+Reference< XConnection > Statement::getConnection( )
+{
+ Reference< XConnection > ret;
+ {
+ MutexGuard guard( m_xMutex->GetMutex() );
+ checkClosed();
+ ret = m_connection;
+ }
+ return ret;
+}
+
+
+Any Statement::getWarnings( )
+{
+ return Any();
+}
+
+void Statement::clearWarnings( )
+{
+}
+
+Reference< css::sdbc::XResultSetMetaData > Statement::getMetaData()
+{
+ Reference< css::sdbc::XResultSetMetaData > ret;
+ Reference< css::sdbc::XResultSetMetaDataSupplier > supplier( m_lastResultset, UNO_QUERY );
+ if( supplier.is() )
+ ret = supplier->getMetaData();
+ return ret;
+}
+
+
+::cppu::IPropertyArrayHelper & Statement::getInfoHelper()
+{
+ return getStatementPropertyArrayHelper();
+}
+
+
+sal_Bool Statement::convertFastPropertyValue(
+ Any & rConvertedValue, Any & rOldValue, sal_Int32 nHandle, const Any& rValue )
+{
+ rOldValue = m_props[nHandle];
+ bool bRet;
+ switch( nHandle )
+ {
+ case STATEMENT_CURSOR_NAME:
+ {
+ OUString val;
+ bRet = ( rValue >>= val );
+ rConvertedValue <<= val;
+ break;
+ }
+ case STATEMENT_ESCAPE_PROCESSING:
+ {
+ bool val(false);
+ bRet = ( rValue >>= val );
+ rConvertedValue <<= val;
+ break;
+ }
+ case STATEMENT_FETCH_DIRECTION:
+ case STATEMENT_FETCH_SIZE:
+ case STATEMENT_MAX_FIELD_SIZE:
+ case STATEMENT_MAX_ROWS:
+ case STATEMENT_QUERY_TIME_OUT:
+ case STATEMENT_RESULT_SET_CONCURRENCY:
+ case STATEMENT_RESULT_SET_TYPE:
+ {
+ sal_Int32 val;
+ bRet = ( rValue >>= val );
+ rConvertedValue <<= val;
+ break;
+ }
+ default:
+ {
+ throw IllegalArgumentException(
+ "pq_statement: Invalid property handle ("
+ + OUString::number( nHandle ) + ")",
+ *this, 2 );
+ }
+ }
+ return bRet;
+}
+
+
+void Statement::setFastPropertyValue_NoBroadcast(
+ sal_Int32 nHandle,const Any& rValue )
+{
+ m_props[nHandle] = rValue;
+}
+
+void Statement::getFastPropertyValue( Any& rValue, sal_Int32 nHandle ) const
+{
+ rValue = m_props[nHandle];
+}
+
+Reference < XPropertySetInfo > Statement::getPropertySetInfo()
+{
+ return OPropertySetHelper::createPropertySetInfo( getStatementPropertyArrayHelper() );
+}
+
+
+Reference< XResultSet > Statement::getResultSet( )
+{
+ return Reference< XResultSet > ( m_lastResultset, css::uno::UNO_QUERY );
+}
+
+sal_Int32 Statement::getUpdateCount( )
+{
+ return m_multipleResultUpdateCount;
+}
+
+sal_Bool Statement::getMoreResults( )
+{
+ // The PostgreSQL C interface always returns a single result,
+ // so we will never have multiple ones.
+ // Implicitly close the open resultset (if any) as per spec,
+ // and setup to signal "no more result, neither as resultset,
+ // nor as update count".
+ Reference< XCloseable > lastResultSetHolder = m_lastResultset;
+ if( lastResultSetHolder.is() )
+ lastResultSetHolder->close();
+ m_multipleResultUpdateCount = -1;
+ return false;
+}
+
+
+void Statement::disposing()
+{
+ close();
+}
+
+Reference< XResultSet > Statement::getGeneratedValues( )
+{
+ osl::MutexGuard guard( m_xMutex->GetMutex() );
+ return getGeneratedValuesFromLastInsert(
+ m_pSettings, m_connection, m_lastOidInserted, m_lastTableInserted, m_lastQuery );
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/postgresql/pq_statement.hxx b/connectivity/source/drivers/postgresql/pq_statement.hxx
new file mode 100644
index 0000000000..816d2a55af
--- /dev/null
+++ b/connectivity/source/drivers/postgresql/pq_statement.hxx
@@ -0,0 +1,198 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * Effective License of whole file:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011:
+ *
+ * The Contents of this file are made available subject to the terms of
+ * the GNU Lesser General Public License Version 2.1
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * Contributor(s): Joerg Budischewski
+ *
+ * All parts contributed on or after August 2011:
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ ************************************************************************/
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <string_view>
+
+#include <cppuhelper/propshlp.hxx>
+#include <cppuhelper/compbase.hxx>
+#include <cppuhelper/component.hxx>
+
+#include <libpq-fe.h>
+
+#include "pq_connection.hxx"
+#include <com/sun/star/sdbc/XMultipleResults.hpp>
+#include <com/sun/star/sdbc/XGeneratedResultSet.hpp>
+#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
+
+namespace pq_sdbc_driver
+{
+
+const sal_Int32 STATEMENT_CURSOR_NAME = 0;
+const sal_Int32 STATEMENT_ESCAPE_PROCESSING = 1;
+const sal_Int32 STATEMENT_FETCH_DIRECTION = 2;
+const sal_Int32 STATEMENT_FETCH_SIZE = 3;
+const sal_Int32 STATEMENT_MAX_FIELD_SIZE = 4;
+const sal_Int32 STATEMENT_MAX_ROWS = 5;
+const sal_Int32 STATEMENT_QUERY_TIME_OUT = 6;
+const sal_Int32 STATEMENT_RESULT_SET_CONCURRENCY = 7;
+const sal_Int32 STATEMENT_RESULT_SET_TYPE = 8;
+
+#define STATEMENT_SIZE 9
+
+typedef ::cppu::WeakComponentImplHelper< css::sdbc::XStatement,
+ css::sdbc::XCloseable,
+ css::sdbc::XWarningsSupplier,
+ css::sdbc::XMultipleResults,
+ css::sdbc::XGeneratedResultSet,
+ css::sdbc::XResultSetMetaDataSupplier
+ > Statement_BASE;
+
+class Statement : public Statement_BASE,
+ public cppu::OPropertySetHelper
+{
+private:
+ css::uno::Any m_props[STATEMENT_SIZE];
+ css::uno::Reference< css::sdbc::XConnection > m_connection;
+ ConnectionSettings *m_pSettings;
+ css::uno::Reference< css::sdbc::XCloseable > m_lastResultset;
+ ::rtl::Reference< comphelper::RefCountedMutex > m_xMutex;
+ bool m_multipleResultAvailable;
+ sal_Int32 m_multipleResultUpdateCount;
+ sal_Int32 m_lastOidInserted;
+ OUString m_lastTableInserted;
+ OString m_lastQuery;
+
+public:
+ /**
+ * @param ppConnection The piece of memory, pConnection points to, is accessible
+ * as long as a reference to parameter con is held.
+ */
+ Statement( const rtl::Reference< comphelper::RefCountedMutex > & refMutex,
+ const css::uno::Reference< css::sdbc::XConnection> & con,
+ struct ConnectionSettings *pSettings );
+
+ virtual ~Statement() override;
+public: // XInterface
+ virtual void SAL_CALL acquire() noexcept override { Statement_BASE::acquire(); }
+ virtual void SAL_CALL release() noexcept override { Statement_BASE::release(); }
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & reqType ) override;
+
+public: // XCloseable
+ virtual void SAL_CALL close( ) override;
+
+public: // XStatement
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL executeQuery(
+ const OUString& sql ) override;
+ virtual sal_Int32 SAL_CALL executeUpdate( const OUString& sql ) override;
+ virtual sal_Bool SAL_CALL execute( const OUString& sql ) override;
+ virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL getConnection( ) override;
+
+public: // XWarningsSupplier
+ virtual css::uno::Any SAL_CALL getWarnings( ) override;
+ virtual void SAL_CALL clearWarnings( ) override;
+
+public: // XTypeProvider, first implemented by OPropertySetHelper
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override;
+ virtual css::uno::Sequence< sal_Int8> SAL_CALL getImplementationId() override;
+
+public: // OPropertySetHelper
+ virtual cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override;
+
+ virtual sal_Bool SAL_CALL convertFastPropertyValue(
+ css::uno::Any & rConvertedValue,
+ css::uno::Any & rOldValue,
+ sal_Int32 nHandle,
+ const css::uno::Any& rValue ) override;
+
+ virtual void SAL_CALL setFastPropertyValue_NoBroadcast(
+ sal_Int32 nHandle,
+ const css::uno::Any& rValue ) override;
+
+ using ::cppu::OPropertySetHelper::getFastPropertyValue;
+
+ void SAL_CALL getFastPropertyValue(
+ css::uno::Any& rValue,
+ sal_Int32 nHandle ) const override;
+
+ // XPropertySet
+ css::uno::Reference < css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo() override;
+
+public: // XGeneratedResultSet
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL
+ getGeneratedValues( ) override;
+
+public: // XMultipleResults
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getResultSet( ) override;
+ virtual sal_Int32 SAL_CALL getUpdateCount( ) override;
+ virtual sal_Bool SAL_CALL getMoreResults( ) override;
+
+public: // OComponentHelper
+ virtual void SAL_CALL disposing() override;
+
+public: // XResultSetMetaDataSupplier (is required by framework (see
+ // dbaccess/source/core/api/preparedstatement.cxx::getMetaData() )
+ virtual css::uno::Reference< css::sdbc::XResultSetMetaData > SAL_CALL getMetaData( ) override;
+
+private:
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void checkClosed();
+ /// @throws css::sdbc::SQLException
+ void raiseSQLException( std::u16string_view sql, const char * errorMsg );
+};
+
+
+struct CommandData
+{
+ ConnectionSettings **ppSettings;
+ sal_Int32 *pLastOidInserted;
+ sal_Int32 *pMultipleResultUpdateCount;
+ bool *pMultipleResultAvailable;
+ OUString *pLastTableInserted;
+ css::uno::Reference< css::sdbc::XCloseable > *pLastResultset;
+ OString *pLastQuery;
+ ::rtl::Reference< comphelper::RefCountedMutex > refMutex;
+ css::uno::Reference< css::uno::XInterface > owner;
+ css::uno::Reference< css::sdbcx::XTablesSupplier > tableSupplier;
+ sal_Int32 concurrency;
+};
+
+bool executePostgresCommand( const OString & cmd, struct CommandData *data );
+css::uno::Reference< css::sdbc::XResultSet > getGeneratedValuesFromLastInsert(
+ ConnectionSettings *pConnectionSettings,
+ const css::uno::Reference< css::sdbc::XConnection > &connection,
+ sal_Int32 nLastOid,
+ std::u16string_view lastTableInserted,
+ const OString & lastQuery );
+
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/postgresql/pq_statics.cxx b/connectivity/source/drivers/postgresql/pq_statics.cxx
new file mode 100644
index 0000000000..f695562022
--- /dev/null
+++ b/connectivity/source/drivers/postgresql/pq_statics.cxx
@@ -0,0 +1,627 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * Effective License of whole file:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011:
+ *
+ * The Contents of this file are made available subject to the terms of
+ * the GNU Lesser General Public License Version 2.1
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * Contributor(s): Joerg Budischewski
+ *
+ * All parts contributed on or after August 2011:
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ ************************************************************************/
+
+#include "pq_statics.hxx"
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <utility>
+
+using com::sun::star::uno::Sequence;
+using com::sun::star::uno::Any;
+using com::sun::star::uno::Type;
+
+using com::sun::star::beans::PropertyAttribute::READONLY;
+using com::sun::star::beans::Property;
+
+namespace pq_sdbc_driver
+{
+
+namespace {
+
+struct DefColumnMetaData
+{
+ const char * columnName;
+ const char * tableName;
+ const char * schemaTableName;
+ const char * typeName;
+ sal_Int32 type;
+ sal_Int32 precision;
+ sal_Int32 scale;
+ bool isCurrency;
+ bool isNullable;
+ bool isAutoIncrement;
+};
+
+struct BaseTypeDef { const char * typeName; sal_Int32 value; };
+
+struct PropertyDef
+{
+ PropertyDef( OUString str, const Type &t )
+ : name(std::move( str )) , type( t ) {}
+ OUString name;
+ css::uno::Type type;
+};
+
+struct PropertyDefEx : public PropertyDef
+{
+ PropertyDefEx( const OUString & str, const Type &t , sal_Int32 a )
+ : PropertyDef( str, t ) , attribute( a )
+ {}
+ sal_Int32 attribute;
+};
+
+}
+
+static cppu::IPropertyArrayHelper * createPropertyArrayHelper(
+ PropertyDef const *props, int count , sal_Int16 attr )
+{
+ Sequence< Property > seq( count );
+ auto seqRange = asNonConstRange(seq);
+ for( int i = 0 ; i < count ; i ++ )
+ {
+ seqRange[i] = Property( props[i].name, i, props[i].type, attr );
+ }
+ return new cppu::OPropertyArrayHelper( seq, true );
+}
+
+static cppu::IPropertyArrayHelper * createPropertyArrayHelper(
+ PropertyDefEx const *props, int count )
+{
+ Sequence< Property > seq( count );
+ auto seqRange = asNonConstRange(seq);
+ for( int i = 0 ; i < count ; i ++ )
+ {
+ seqRange[i] = Property( props[i].name, i, props[i].type, props[i].attribute );
+ }
+ return new cppu::OPropertyArrayHelper( seq, true );
+}
+
+Statics & getStatics()
+{
+ static Statics* p = []() {
+ static Statics statics ;
+ statics.SYSTEM_TABLE = "SYSTEM TABLE";
+ statics.TABLE = "TABLE";
+ statics.VIEW = "VIEW";
+ statics.UNKNOWN = "UNKNOWN";
+ statics.YES = "YES";
+ statics.NO = "NO";
+ statics.NO_NULLS = "NO_NULLS";
+ statics.NULABLE = "NULABLE";
+ statics.NULLABLE_UNKNOWN = "NULLABLE_UNKNOWN";
+
+ statics.TYPE = "Type";
+ statics.TYPE_NAME = "TypeName";
+ statics.NAME = "Name";
+ statics.SCHEMA_NAME = "SchemaName";
+ statics.CATALOG_NAME = "CatalogName";
+ statics.DESCRIPTION = "Description";
+ statics.PRIVILEGES = "Privileges";
+
+ statics.DEFAULT_VALUE = "DefaultValue";
+ statics.IS_AUTO_INCREMENT = "IsAutoIncrement";
+ statics.IS_CURRENCY = "IsCurrency";
+ statics.IS_NULLABLE = "IsNullable";
+ statics.IS_ROW_VERSISON = "IsRowVersion";
+ statics.PRECISION = "Precision";
+ statics.SCALE = "Scale";
+
+ statics.cPERCENT = "%";
+ statics.BEGIN = "BEGIN";
+ statics.COMMIT = "COMMIT";
+ statics.ROLLBACK = "ROLLBACK";
+
+ statics.KEY = "Key";
+ statics.REFERENCED_TABLE = "ReferencedTable";
+ statics.UPDATE_RULE = "UpdateRule";
+ statics.DELETE_RULE = "DeleteRule";
+ statics.PRIVATE_COLUMNS = "PrivateColumns";
+ statics.PRIVATE_FOREIGN_COLUMNS = "PrivateForeignColumns";
+
+ statics.KEY_COLUMN = "KeyColumn";
+ statics.RELATED_COLUMN = "RelatedColumn";
+ statics.PASSWORD = "Password";
+ statics.USER = "User";
+
+ statics.CURSOR_NAME = "CursorName";
+ statics.ESCAPE_PROCESSING = "EscapeProcessing";
+ statics.FETCH_DIRECTION = "FetchDirection";
+ statics.FETCH_SIZE = "FetchSize";
+ statics.IS_BOOKMARKABLE = "IsBookmarkable";
+ statics.RESULT_SET_CONCURRENCY = "ResultSetConcurrency";
+ statics.RESULT_SET_TYPE = "ResultSetType";
+
+ statics.COMMAND = "Command";
+ statics.CHECK_OPTION = "CheckOption";
+
+ statics.TRUE = "t";
+ statics.FALSE = "f";
+ statics.IS_PRIMARY_KEY_INDEX = "IsPrimaryKeyIndex";
+ statics.IS_CLUSTERED = "IsClustered";
+ statics.IS_UNIQUE = "IsUnique";
+ statics.IS_ASCENDING = "IsAscending";
+ statics.PRIVATE_COLUMN_INDEXES = "PrivateColumnIndexes";
+ statics.HELP_TEXT = "HelpText";
+
+ statics.CATALOG = "Catalog";
+
+ Type tString = cppu::UnoType<OUString>::get();
+ Type tInt = cppu::UnoType<sal_Int32>::get();
+ Type tBool = cppu::UnoType<bool>::get();
+ Type tStringSequence = cppu::UnoType<css::uno::Sequence< OUString >>::get();
+
+ // Table props set
+ ImplementationStatics &ist = statics.refl.table;
+ ist.implName = "org.openoffice.comp.pq.sdbcx.Table";
+ ist.serviceNames = { "com.sun.star.sdbcx.Table" };
+ PropertyDef tableDef[] =
+ {
+ PropertyDef( statics.CATALOG_NAME , tString ),
+ PropertyDef( statics.DESCRIPTION , tString ),
+ PropertyDef( statics.NAME , tString ),
+ PropertyDef( statics.PRIVILEGES , tInt ),
+ PropertyDef( statics.SCHEMA_NAME , tString ),
+ PropertyDef( statics.TYPE , tString )
+ };
+ ist.pProps = createPropertyArrayHelper(
+ tableDef, std::size(tableDef), READONLY );
+
+ statics.refl.tableDescriptor.implName =
+ "org.openoffice.comp.pq.sdbcx.TableDescriptor";
+ statics.refl.tableDescriptor.serviceNames = { "com.sun.star.sdbcx.TableDescriptor" };
+ PropertyDef tableDescDef[] =
+ {
+ PropertyDef( statics.CATALOG_NAME , tString ),
+ PropertyDef( statics.DESCRIPTION , tString ),
+ PropertyDef( statics.NAME , tString ),
+ PropertyDef( statics.PRIVILEGES , tInt ),
+ PropertyDef( statics.SCHEMA_NAME , tString )
+ };
+ statics.refl.tableDescriptor.pProps = createPropertyArrayHelper(
+ tableDescDef, std::size(tableDescDef), 0 );
+
+ // Column props set
+ statics.refl.column.implName = "org.openoffice.comp.pq.sdbcx.Column";
+ statics.refl.column.serviceNames = { "com.sun.star.sdbcx.Column" };
+ PropertyDefEx columnDef[] =
+ {
+ PropertyDefEx( statics.CATALOG_NAME , tString, READONLY ),
+ PropertyDefEx( statics.DEFAULT_VALUE, tString, READONLY ),
+ PropertyDefEx( statics.DESCRIPTION , tString, READONLY ),
+// PropertyDefEx( statics.HELP_TEXT , tString, BOUND ),
+ PropertyDefEx( statics.IS_AUTO_INCREMENT, tBool, READONLY ),
+ PropertyDefEx( statics.IS_CURRENCY, tBool, READONLY ),
+ PropertyDefEx( statics.IS_NULLABLE, tInt, READONLY ),
+ PropertyDefEx( statics.IS_ROW_VERSISON, tBool,READONLY ),
+ PropertyDefEx( statics.NAME , tString,READONLY ),
+ PropertyDefEx( statics.PRECISION , tInt, READONLY ),
+ PropertyDefEx( statics.SCALE , tInt ,READONLY),
+ PropertyDefEx( statics.TYPE , tInt ,READONLY),
+ PropertyDefEx( statics.TYPE_NAME , tString ,READONLY)
+ };
+ statics.refl.column.pProps = createPropertyArrayHelper(
+ columnDef, std::size(columnDef) );
+
+ statics.refl.columnDescriptor.implName =
+ "org.openoffice.comp.pq.sdbcx.ColumnDescriptor";
+ statics.refl.columnDescriptor.serviceNames = { "com.sun.star.sdbcx.ColumnDescriptor" };
+ PropertyDef columnDescDef[] =
+ {
+ PropertyDef( statics.CATALOG_NAME , tString ),
+ PropertyDef( statics.DEFAULT_VALUE, tString ),
+ PropertyDef( statics.DESCRIPTION , tString ),
+// PropertyDef( statics.HELP_TEXT , tString ),
+ PropertyDef( statics.IS_AUTO_INCREMENT, tBool ),
+ PropertyDef( statics.IS_CURRENCY, tBool ),
+ PropertyDef( statics.IS_NULLABLE, tInt ),
+ PropertyDef( statics.IS_ROW_VERSISON, tBool ),
+ PropertyDef( statics.NAME , tString ),
+ PropertyDef( statics.PRECISION , tInt ),
+ PropertyDef( statics.SCALE , tInt ),
+ PropertyDef( statics.TYPE , tInt ),
+ PropertyDef( statics.TYPE_NAME , tString )
+ };
+
+ statics.refl.columnDescriptor.pProps = createPropertyArrayHelper(
+ columnDescDef, std::size(columnDescDef), 0 );
+
+ // Key properties
+ statics.refl.key.implName = "org.openoffice.comp.pq.sdbcx.Key";
+ statics.refl.key.serviceNames = { "com.sun.star.sdbcx.Key" };
+ PropertyDef keyDef[] =
+ {
+ PropertyDef( statics.DELETE_RULE, tInt ),
+ PropertyDef( statics.NAME, tString ),
+ PropertyDef( statics.PRIVATE_COLUMNS, tStringSequence ),
+ PropertyDef( statics.PRIVATE_FOREIGN_COLUMNS, tStringSequence ),
+ PropertyDef( statics.REFERENCED_TABLE, tString ),
+ PropertyDef( statics.TYPE, tInt ),
+ PropertyDef( statics.UPDATE_RULE, tInt )
+ };
+ statics.refl.key.pProps = createPropertyArrayHelper(
+ keyDef, std::size(keyDef), READONLY );
+
+
+ // Key properties
+ statics.refl.keyDescriptor.implName =
+ "org.openoffice.comp.pq.sdbcx.KeyDescriptor";
+ statics.refl.keyDescriptor.serviceNames = { "com.sun.star.sdbcx.KeyDescriptor" };
+ PropertyDef keyDescDef[] =
+ {
+ PropertyDef( statics.DELETE_RULE, tInt ),
+ PropertyDef( statics.NAME, tString ),
+ PropertyDef( statics.REFERENCED_TABLE, tString ),
+ PropertyDef( statics.TYPE, tInt ),
+ PropertyDef( statics.UPDATE_RULE, tInt )
+ };
+ statics.refl.keyDescriptor.pProps = createPropertyArrayHelper(
+ keyDescDef, std::size(keyDescDef), 0 );
+
+
+ // KeyColumn props set
+ statics.refl.keycolumn.implName = "org.openoffice.comp.pq.sdbcx.KeyColumn";
+ statics.refl.keycolumn.serviceNames = { "com.sun.star.sdbcx.KeyColumn" };
+ PropertyDef keycolumnDef[] =
+ {
+ PropertyDef( statics.CATALOG_NAME , tString ),
+ PropertyDef( statics.DEFAULT_VALUE, tString ),
+ PropertyDef( statics.DESCRIPTION , tString ),
+ PropertyDef( statics.IS_AUTO_INCREMENT, tBool ),
+ PropertyDef( statics.IS_CURRENCY, tBool ),
+ PropertyDef( statics.IS_NULLABLE, tInt ),
+ PropertyDef( statics.IS_ROW_VERSISON, tBool ),
+ PropertyDef( statics.NAME , tString ),
+ PropertyDef( statics.PRECISION , tInt ),
+ PropertyDef( statics.RELATED_COLUMN, tString ),
+ PropertyDef( statics.SCALE , tInt ),
+ PropertyDef( statics.TYPE , tInt ),
+ PropertyDef( statics.TYPE_NAME , tString )
+ };
+ statics.refl.keycolumn.pProps = createPropertyArrayHelper(
+ keycolumnDef, std::size(keycolumnDef), READONLY );
+
+ // KeyColumn props set
+ statics.refl.keycolumnDescriptor.implName =
+ "org.openoffice.comp.pq.sdbcx.KeyColumnDescriptor";
+ statics.refl.keycolumnDescriptor.serviceNames =
+ { "com.sun.star.sdbcx.KeyColumnDescriptor" };
+ PropertyDef keycolumnDescDef[] =
+ {
+ PropertyDef( statics.NAME , tString ),
+ PropertyDef( statics.RELATED_COLUMN, tString )
+ };
+ statics.refl.keycolumnDescriptor.pProps = createPropertyArrayHelper(
+ keycolumnDescDef, std::size(keycolumnDescDef), 0 );
+
+ // view props set
+ statics.refl.view.implName = "org.openoffice.comp.pq.sdbcx.View";
+ statics.refl.view.serviceNames = { "com.sun.star.sdbcx.View" };
+ PropertyDef viewDef[] =
+ {
+ PropertyDef( statics.CATALOG_NAME , tString ),
+ PropertyDef( statics.CHECK_OPTION , tInt ),
+ PropertyDef( statics.COMMAND , tString ),
+ PropertyDef( statics.NAME , tString ),
+ PropertyDef( statics.SCHEMA_NAME , tString )
+ };
+ statics.refl.view.pProps = createPropertyArrayHelper(
+ viewDef, std::size(viewDef), READONLY );
+
+ // view props set
+ statics.refl.viewDescriptor.implName = "org.openoffice.comp.pq.sdbcx.ViewDescriptor";
+ statics.refl.viewDescriptor.serviceNames = { "com.sun.star.sdbcx.ViewDescriptor" };
+ statics.refl.viewDescriptor.pProps = createPropertyArrayHelper(
+ viewDef, std::size(viewDef), 0 ); // reuse view, as it is identical
+ // user props set
+ statics.refl.user.implName = "org.openoffice.comp.pq.sdbcx.User";
+ statics.refl.user.serviceNames = { "com.sun.star.sdbcx.User" };
+ PropertyDef userDefRO[] =
+ {
+ PropertyDef( statics.NAME , tString )
+ };
+ statics.refl.user.pProps = createPropertyArrayHelper(
+ userDefRO, std::size(userDefRO), READONLY );
+
+ // user props set
+ statics.refl.userDescriptor.implName =
+ "org.openoffice.comp.pq.sdbcx.UserDescriptor";
+ statics.refl.userDescriptor.serviceNames = { "com.sun.star.sdbcx.UserDescriptor" };
+ PropertyDef userDefWR[] =
+ {
+ PropertyDef( statics.NAME , tString ),
+ PropertyDef( statics.PASSWORD , tString )
+ };
+ statics.refl.userDescriptor.pProps = createPropertyArrayHelper(
+ userDefWR, std::size(userDefWR), 0 );
+
+ // index props set
+ statics.refl.index.implName = "org.openoffice.comp.pq.sdbcx.Index";
+ statics.refl.index.serviceNames = { "com.sun.star.sdbcx.Index" };
+ PropertyDef indexDef[] =
+ {
+ PropertyDef( statics.CATALOG , tString ),
+ PropertyDef( statics.IS_CLUSTERED, tBool ),
+ PropertyDef( statics.IS_PRIMARY_KEY_INDEX, tBool ),
+ PropertyDef( statics.IS_UNIQUE, tBool ),
+ PropertyDef( statics.NAME , tString ),
+ PropertyDef( statics.PRIVATE_COLUMN_INDEXES, tStringSequence )
+ };
+ statics.refl.index.pProps = createPropertyArrayHelper(
+ indexDef, std::size(indexDef), READONLY );
+
+ // index props set
+ statics.refl.indexDescriptor.implName =
+ "org.openoffice.comp.pq.sdbcx.IndexDescriptor";
+ statics.refl.indexDescriptor.serviceNames = { "com.sun.star.sdbcx.IndexDescriptor" };
+ statics.refl.indexDescriptor.pProps = createPropertyArrayHelper(
+ indexDef, std::size(indexDef), 0 );
+
+ // indexColumn props set
+ statics.refl.indexColumn.implName = "org.openoffice.comp.pq.sdbcx.IndexColumn";
+ statics.refl.indexColumn.serviceNames = { "com.sun.star.sdbcx.IndexColumn" };
+ PropertyDef indexColumnDef[] =
+ {
+ PropertyDef( statics.CATALOG_NAME , tString ),
+ PropertyDef( statics.DEFAULT_VALUE, tString ),
+ PropertyDef( statics.DESCRIPTION , tString ),
+ PropertyDef( statics.IS_ASCENDING, tBool ),
+ PropertyDef( statics.IS_AUTO_INCREMENT, tBool ),
+ PropertyDef( statics.IS_CURRENCY, tBool ),
+ PropertyDef( statics.IS_NULLABLE, tInt ),
+ PropertyDef( statics.IS_ROW_VERSISON, tBool ),
+ PropertyDef( statics.NAME , tString ),
+ PropertyDef( statics.PRECISION , tInt ),
+ PropertyDef( statics.SCALE , tInt ),
+ PropertyDef( statics.TYPE , tInt ),
+ PropertyDef( statics.TYPE_NAME , tString )
+ };
+ statics.refl.indexColumn.pProps = createPropertyArrayHelper(
+ indexColumnDef, std::size(indexColumnDef), READONLY );
+
+ // indexColumn props set
+ statics.refl.indexColumnDescriptor.implName =
+ "org.openoffice.comp.pq.sdbcx.IndexColumnDescriptor";
+ statics.refl.indexColumnDescriptor.serviceNames =
+ { "com.sun.star.sdbcx.IndexColumnDescriptor" };
+ PropertyDef indexColumnDescDef[] =
+ {
+ PropertyDef( statics.IS_ASCENDING, tBool ),
+ PropertyDef( statics.NAME , tString )
+ };
+ statics.refl.indexColumnDescriptor.pProps = createPropertyArrayHelper(
+ indexColumnDescDef, std::size(indexColumnDescDef), 0 );
+
+ // databasemetadata
+ statics.tablesRowNames = std::vector< OUString > ( 5 );
+ statics.tablesRowNames[TABLE_INDEX_CATALOG] = "TABLE_CAT";
+ statics.tablesRowNames[TABLE_INDEX_SCHEMA] = "TABLE_SCHEM";
+ statics.tablesRowNames[TABLE_INDEX_NAME] = "TABLE_NAME";
+ statics.tablesRowNames[TABLE_INDEX_TYPE] = "TABLE_TYPE";
+ statics.tablesRowNames[TABLE_INDEX_REMARKS] = "REMARKS";
+
+ statics.primaryKeyNames = std::vector< OUString > ( 6 );
+ statics.primaryKeyNames[0] = "TABLE_CAT";
+ statics.primaryKeyNames[1] = "TABLE_SCHEM";
+ statics.primaryKeyNames[2] = "TABLE_NAME";
+ statics.primaryKeyNames[3] = "COLUMN_NAME";
+ statics.primaryKeyNames[4] = "KEY_SEQ";
+ statics.primaryKeyNames[5] = "PK_NAME";
+
+ statics.SELECT = "SELECT";
+ statics.UPDATE = "UPDATE";
+ statics.INSERT = "INSERT";
+ statics.DELETE = "DELETE";
+ statics.RULE = "RULE";
+ statics.REFERENCES = "REFERENCES";
+ statics.TRIGGER = "TRIGGER";
+ statics.EXECUTE = "EXECUTE";
+ statics.USAGE = "USAGE";
+ statics.CREATE = "CREATE";
+ statics.TEMPORARY = "TEMPORARY";
+ statics.INDEX = "Index";
+ statics.INDEX_COLUMN = "IndexColumn";
+
+ statics.schemaNames = std::vector< OUString > ( 1 );
+ statics.schemaNames[0] = "TABLE_SCHEM";
+
+ statics.tableTypeData = std::vector< std::vector< Any > >( 2 );
+
+ statics.tableTypeData[0] = std::vector< Any > ( 1 );
+ statics.tableTypeData[0][0] <<= statics.TABLE;
+
+// statics.tableTypeData[2] = Sequence< Any > ( 1 );
+// statics.tableTypeData[2][0] <<= statics.VIEW;
+
+ statics.tableTypeData[1] = std::vector< Any > ( 1 );
+ statics.tableTypeData[1][0] <<= statics.SYSTEM_TABLE;
+
+ statics.tableTypeNames = std::vector< OUString > ( 1 );
+ statics.tableTypeNames[0] = "TABLE_TYPE";
+
+ statics.columnRowNames =
+ {
+ "TABLE_CAT", "TABLE_SCHEM", "TABLE_NAME", "COLUMN_NAME",
+ "DATA_TYPE", "TYPE_NAME", "COLUMN_SIZE", "BUFFER_LENGTH",
+ "DECIMAL_DIGITS", "NUM_PREC_RADIX", "NULLABLE", "REMARKS",
+ "COLUMN_DEF", "SQL_DATA_TYPE", "SQL_DATETIME_SUB", "CHAR_OCTET_LENGTH",
+ "ORDINAL_POSITION", "IS_NULLABLE"
+ };
+
+ statics.typeinfoColumnNames =
+ {
+ "TYPE_NAME", "DATA_TYPE", "PRECISION", "LITERAL_PREFIX",
+ "LITERAL_SUFFIX", "CREATE_PARAMS", "NULLABLE", "CASE_SENSITIVE",
+ "SEARCHABLE", "UNSIGNED_ATTRIBUTE", "FIXED_PREC_SCALE",
+ "AUTO_INCREMENT", "LOCAL_TYPE_NAME", "MINIMUM_SCALE",
+ "MAXIMUM_SCALE", "SQL_DATA_TYPE", "SQL_DATETIME_SUB",
+ "NUM_PREC_RADIX"
+ };
+
+ statics.indexinfoColumnNames =
+ {
+ "TABLE_CAT", "TABLE_SCHEM", "TABLE_NAME",
+ "NON_UNIQUE", "INDEX_QUALIFIER", "INDEX_NAME",
+ "TYPE", "ORDINAL_POSITION", "COLUMN_NAME",
+ "ASC_OR_DESC", "CARDINALITY", "PAGES", "FILTER_CONDITION"
+ };
+
+ statics.resultSetArrayColumnNames = { "INDEX" , "VALUE" };
+
+ // LEM TODO see if a refresh is needed; obtain automatically from pg_catalog.pg_type?
+ BaseTypeDef baseTypeDefs[] =
+ {
+ { "bool" , css::sdbc::DataType::BOOLEAN },
+ { "bytea", css::sdbc::DataType::VARBINARY },
+ { "char" , css::sdbc::DataType::CHAR },
+
+ { "int8" , css::sdbc::DataType::BIGINT },
+ { "serial8" , css::sdbc::DataType::BIGINT },
+
+
+ { "int2" , css::sdbc::DataType::SMALLINT },
+
+ { "int4" , css::sdbc::DataType::INTEGER },
+// { "regproc" , css::sdbc::DataType::INTEGER },
+// { "oid" , css::sdbc::DataType::INTEGER },
+// { "xid" , css::sdbc::DataType::INTEGER },
+// { "cid" , css::sdbc::DataType::INTEGER },
+// { "serial", css::sdbc::DataType::INTEGER },
+// { "serial4", css::sdbc::DataType::INTEGER },
+
+ { "text", css::sdbc::DataType::LONGVARCHAR },
+ { "bpchar", css::sdbc::DataType::CHAR },
+ { "varchar", css::sdbc::DataType::VARCHAR },
+
+ { "float4", css::sdbc::DataType::REAL },
+ { "float8", css::sdbc::DataType::DOUBLE },
+
+ { "numeric", css::sdbc::DataType::NUMERIC },
+ { "decimal", css::sdbc::DataType::DECIMAL },
+
+ { "date", css::sdbc::DataType::DATE },
+ { "time", css::sdbc::DataType::TIME },
+ { "timestamp", css::sdbc::DataType::TIMESTAMP },
+
+// { "_bool" , css::sdbc::DataType::ARRAY },
+// { "_bytea", css::sdbc::DataType::ARRAY },
+// { "_char" , css::sdbc::DataType::ARRAY },
+
+// { "_int8" , css::sdbc::DataType::ARRAY },
+// { "_serial8" , css::sdbc::DataType::ARRAY },
+
+
+// { "_int2" , css::sdbc::DataType::ARRAY },
+
+// { "_int4" , css::sdbc::DataType::ARRAY },
+// { "_regproc" , css::sdbc::DataType::ARRAY },
+// { "_oid" , css::sdbc::DataType::ARRAY },
+// { "_xid" , css::sdbc::DataType::ARRAY },
+// { "_cid" , css::sdbc::DataType::ARRAY },
+
+// { "_text", css::sdbc::DataType::ARRAY },
+// { "_bpchar", css::sdbc::DataType::ARRAY },
+// { "_varchar", css::sdbc::DataType::ARRAY },
+
+// { "_float4", css::sdbc::DataType::ARRAY },
+// { "_float8", css::sdbc::DataType::ARRAY },
+
+// { "_numeric", css::sdbc::DataType::ARRAY },
+// { "_decimal", css::sdbc::DataType::ARRAY },
+
+// { "_date", css::sdbc::DataType::ARRAY }, // switch to date later
+// { "_time", css::sdbc::DataType::ARRAY }, // switch to time later
+
+ { nullptr, 0 }
+ };
+ int i;
+ for( i = 0 ; baseTypeDefs[i].typeName ; i ++ )
+ {
+ statics.baseTypeMap[
+ OUString::createFromAscii( baseTypeDefs[i].typeName) ] =
+ baseTypeDefs[i].value;
+ }
+
+ // This is the metadata for the columns of the recordset returned
+ // by css::sdbc::XDatabaseMetaData::getTypeInfo(),
+ // that is what is returned by getTypeInfo().getMetaData()
+ DefColumnMetaData defTypeInfoMetaData[] =
+ {
+ { "TYPE_NAME", "TYPEINFO", "pg_catalog", "", css::sdbc::DataType::VARCHAR, 0,50,false,false,false }, // 0
+ { "DATA_TYPE", "TYPEINFO", "pg_catalog", "", css::sdbc::DataType::SMALLINT, 0,50,false,false,false }, // 1
+ { "PRECISION", "TYPEINFO", "pg_catalog", "", css::sdbc::DataType::INTEGER, 0,50,false,false,false }, // 2
+ { "LITERAL_PREFIX", "TYPEINFO", "pg_catalog", "", css::sdbc::DataType::VARCHAR, 0,50,false,false,false }, // 3
+ { "LITERAL_SUFFIX", "TYPEINFO", "pg_catalog", "", css::sdbc::DataType::VARCHAR, 0,50,false,false,false }, // 4
+ { "CREATE_PARAMS", "TYPEINFO", "pg_catalog", "", css::sdbc::DataType::VARCHAR, 0,50,false,false,false }, // 5
+ { "NULLABLE", "TYPEINFO", "pg_catalog", "", css::sdbc::DataType::INTEGER, 0,50,false,false,false }, // 6
+ { "CASE_SENSITIVE", "TYPEINFO", "pg_catalog", "", css::sdbc::DataType::BOOLEAN, 0,50,false,false,false }, // 7
+ { "SEARCHABLE", "TYPEINFO", "pg_catalog", "", css::sdbc::DataType::SMALLINT, 0,50,false,false,false }, // 8
+ { "UNSIGNED_ATTRIBUTE", "TYPEINFO", "pg_catalog", "", css::sdbc::DataType::BOOLEAN, 0,50,false,false,false }, // 9
+ { "FIXED_PREC_SCALE", "TYPEINFO", "pg_catalog", "", css::sdbc::DataType::BOOLEAN, 0,50,false,false,false }, // 10
+ { "AUTO_INCREMENT", "TYPEINFO", "pg_catalog", "", css::sdbc::DataType::BOOLEAN, 0,50,false,false,false }, // 11
+ { "LOCAL_TYPE_NAME", "TYPEINFO", "pg_catalog", "", css::sdbc::DataType::VARCHAR, 0,50,false,false,false }, // 12
+ { "MINIMUM_SCALE", "TYPEINFO", "pg_catalog", "", css::sdbc::DataType::SMALLINT, 0,50,false,false,false}, // 13
+ { "MAXIMUM_SCALE", "TYPEINFO", "pg_catalog", "", css::sdbc::DataType::SMALLINT, 0,50,false,false,false }, // 14
+ { "SQL_DATA_TYPE", "TYPEINFO", "pg_catalog", "", css::sdbc::DataType::INTEGER, 0,50,false,false,false }, // 15
+ { "SQL_DATETIME_SUB", "TYPEINFO", "pg_catalog", "", css::sdbc::DataType::INTEGER, 0,50,false,false,false}, // 16
+ { "NUM_PREC_RADIX", "TYPEINFO", "pg_catalog", "", css::sdbc::DataType::INTEGER, 0,50,false,false,false }, // 17
+ {nullptr,nullptr,nullptr,nullptr,0,0,0,false,false,false}
+ };
+
+ for( i = 0 ; defTypeInfoMetaData[i].columnName ; i++ )
+ {
+ statics.typeInfoMetaData.push_back(
+ ColumnMetaData(
+ OUString::createFromAscii( defTypeInfoMetaData[i].columnName ),
+ OUString::createFromAscii( defTypeInfoMetaData[i].tableName ),
+ OUString::createFromAscii( defTypeInfoMetaData[i].schemaTableName ),
+ OUString::createFromAscii( defTypeInfoMetaData[i].typeName ),
+ defTypeInfoMetaData[i].type,
+ defTypeInfoMetaData[i].precision,
+ defTypeInfoMetaData[i].scale,
+ defTypeInfoMetaData[i].isCurrency,
+ defTypeInfoMetaData[i].isNullable,
+ defTypeInfoMetaData[i].isAutoIncrement ) );
+ }
+
+ return &statics;
+ }();
+ return *p;
+}
+
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/postgresql/pq_statics.hxx b/connectivity/source/drivers/postgresql/pq_statics.hxx
new file mode 100644
index 0000000000..4e745e4086
--- /dev/null
+++ b/connectivity/source/drivers/postgresql/pq_statics.hxx
@@ -0,0 +1,240 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * Effective License of whole file:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011:
+ *
+ * The Contents of this file are made available subject to the terms of
+ * the GNU Lesser General Public License Version 2.1
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * Contributor(s): Joerg Budischewski
+ *
+ * All parts contributed on or after August 2011:
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ ************************************************************************/
+
+#pragma once
+
+#include <unordered_map>
+#include <utility>
+#include <vector>
+
+#include <com/sun/star/uno/Any.hxx>
+#include <com/sun/star/uno/Sequence.hxx>
+
+#include <cppuhelper/propshlp.hxx>
+
+namespace pq_sdbc_driver
+{
+
+struct ColumnMetaData
+{
+ ColumnMetaData(
+ OUString _columnName,
+ OUString _tableName,
+ OUString _schemaTableName,
+ OUString _typeName,
+ sal_Int32 _type,
+ sal_Int32 _precision,
+ sal_Int32 _scale,
+ bool _isCurrency,
+ bool _isNullable,
+ bool _isAutoIncrement ) :
+ columnName(std::move( _columnName )),
+ tableName(std::move( _tableName )),
+ schemaTableName(std::move( _schemaTableName )),
+ typeName(std::move( _typeName )),
+ type( _type ),
+ precision( _precision ),
+ scale( _scale ),
+ isCurrency( _isCurrency ),
+ isNullable( _isNullable ),
+ isAutoIncrement( _isAutoIncrement )
+ {}
+
+ OUString columnName;
+ OUString tableName;
+ OUString schemaTableName;
+ OUString typeName;
+ sal_Int32 type;
+ sal_Int32 precision;
+ sal_Int32 scale;
+ bool isCurrency;
+ bool isNullable;
+ bool isAutoIncrement;
+};
+
+typedef std::vector< ColumnMetaData > ColumnMetaDataVector;
+
+typedef std::unordered_map
+<
+ OUString,
+ sal_Int32
+> BaseTypeMap;
+
+struct ImplementationStatics
+{
+ ImplementationStatics() :
+ pProps(nullptr)
+ {}
+
+ OUString implName;
+ css::uno::Sequence< OUString > serviceNames;
+ cppu::IPropertyArrayHelper *pProps;
+ css::uno::Sequence< css::uno::Type > types;
+};
+
+struct ReflectionImplementations
+{
+ struct ImplementationStatics table;
+ struct ImplementationStatics tableDescriptor;
+ struct ImplementationStatics column;
+ struct ImplementationStatics columnDescriptor;
+ struct ImplementationStatics key;
+ struct ImplementationStatics keyDescriptor;
+ struct ImplementationStatics keycolumn;
+ struct ImplementationStatics keycolumnDescriptor;
+ struct ImplementationStatics user;
+ struct ImplementationStatics userDescriptor;
+ struct ImplementationStatics view;
+ struct ImplementationStatics viewDescriptor;
+ struct ImplementationStatics index;
+ struct ImplementationStatics indexDescriptor;
+ struct ImplementationStatics indexColumn;
+ struct ImplementationStatics indexColumnDescriptor;
+};
+
+const sal_Int32 TABLE_INDEX_CATALOG = 0;
+const sal_Int32 TABLE_INDEX_SCHEMA = 1;
+const sal_Int32 TABLE_INDEX_NAME = 2;
+const sal_Int32 TABLE_INDEX_TYPE = 3;
+const sal_Int32 TABLE_INDEX_REMARKS = 4;
+
+struct Statics
+{
+ OUString SYSTEM_TABLE;
+ OUString TABLE;
+ OUString VIEW;
+ OUString UNKNOWN;
+ OUString YES;
+ OUString NO;
+ OUString NO_NULLS;
+ OUString NULABLE;
+ OUString NULLABLE_UNKNOWN;
+ OUString SELECT;
+ OUString UPDATE;
+ OUString INSERT;
+ OUString DELETE;
+ OUString RULE;
+ OUString REFERENCES;
+ OUString TRIGGER;
+ OUString EXECUTE;
+ OUString USAGE;
+ OUString CREATE;
+ OUString TEMPORARY;
+ OUString INDEX;
+ OUString INDEX_COLUMN;
+
+ OUString NAME;
+ OUString SCHEMA_NAME;
+ OUString CATALOG_NAME;
+ OUString DESCRIPTION;
+ OUString TYPE;
+ OUString TYPE_NAME;
+ OUString PRIVILEGES;
+
+ OUString DEFAULT_VALUE;
+ OUString IS_AUTO_INCREMENT;
+ OUString IS_CURRENCY;
+ OUString IS_NULLABLE;
+ OUString IS_ROW_VERSISON;
+ OUString PRECISION;
+ OUString SCALE;
+
+ OUString cPERCENT;
+
+ OUString BEGIN;
+ OUString ROLLBACK;
+ OUString COMMIT;
+
+ OUString KEY;
+ OUString REFERENCED_TABLE;
+ OUString UPDATE_RULE;
+ OUString DELETE_RULE;
+ OUString PRIVATE_COLUMNS;
+ OUString PRIVATE_FOREIGN_COLUMNS;
+
+ OUString KEY_COLUMN;
+ OUString RELATED_COLUMN;
+
+ OUString PASSWORD;
+ OUString USER;
+
+ OUString CURSOR_NAME;
+ OUString ESCAPE_PROCESSING;
+ OUString FETCH_DIRECTION;
+ OUString FETCH_SIZE;
+ OUString IS_BOOKMARKABLE;
+ OUString RESULT_SET_CONCURRENCY;
+ OUString RESULT_SET_TYPE;
+
+ OUString COMMAND;
+ OUString CHECK_OPTION;
+
+ OUString TRUE;
+ OUString FALSE;
+
+ OUString IS_PRIMARY_KEY_INDEX;
+ OUString IS_CLUSTERED;
+ OUString IS_UNIQUE;
+ OUString PRIVATE_COLUMN_INDEXES;
+ OUString HELP_TEXT;
+
+ OUString CATALOG;
+ OUString IS_ASCENDING;
+ ReflectionImplementations refl;
+
+ std::vector< OUString > tablesRowNames;
+ std::vector< OUString > columnRowNames;
+ std::vector< OUString > primaryKeyNames;
+ std::vector< OUString > schemaNames;
+ std::vector< OUString > tableTypeNames;
+ std::vector< OUString > typeinfoColumnNames;
+ std::vector< OUString > indexinfoColumnNames;
+ std::vector< OUString > resultSetArrayColumnNames;
+ std::vector< std::vector< css::uno::Any > > tableTypeData;
+
+ ColumnMetaDataVector typeInfoMetaData;
+ BaseTypeMap baseTypeMap;
+ Statics(){}
+private:
+ Statics( const Statics & ) = delete;
+ Statics & operator = ( const Statics & ) = delete;
+};
+
+Statics & getStatics();
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/postgresql/pq_tools.cxx b/connectivity/source/drivers/postgresql/pq_tools.cxx
new file mode 100644
index 0000000000..c7b94fee12
--- /dev/null
+++ b/connectivity/source/drivers/postgresql/pq_tools.cxx
@@ -0,0 +1,1247 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * Effective License of whole file:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011:
+ *
+ * The Contents of this file are made available subject to the terms of
+ * the GNU Lesser General Public License Version 2.1
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * Contributor(s): Joerg Budischewski
+ *
+ * All parts contributed on or after August 2011:
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ ************************************************************************/
+
+#include <sal/config.h>
+
+#include <o3tl/any.hxx>
+#include <o3tl/string_view.hxx>
+#include <rtl/strbuf.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <sal/log.hxx>
+
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/container/XEnumerationAccess.hpp>
+#include <com/sun/star/lang/XComponent.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XParameters.hpp>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <com/sun/star/sdbc/KeyRule.hpp>
+#include <com/sun/star/sdbcx/KeyType.hpp>
+#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
+
+#include "pq_tools.hxx"
+#include "pq_statics.hxx"
+
+#include <libpq-fe.h>
+#include <string.h>
+#include <string_view>
+
+using com::sun::star::beans::XPropertySet;
+
+using com::sun::star::lang::XComponent;
+
+using com::sun::star::sdbc::SQLException;
+using com::sun::star::sdbc::XStatement;
+using com::sun::star::sdbc::XConnection;
+using com::sun::star::sdbc::XPreparedStatement;
+using com::sun::star::sdbc::XParameters;
+using com::sun::star::sdbc::XResultSet;
+using com::sun::star::sdbc::XRow;
+
+using com::sun::star::sdbcx::XColumnsSupplier;
+
+using com::sun::star::uno::UNO_QUERY;
+using com::sun::star::uno::UNO_QUERY_THROW;
+using com::sun::star::uno::Reference;
+using com::sun::star::uno::Sequence;
+using com::sun::star::uno::XInterface;
+using com::sun::star::uno::Any;
+
+using com::sun::star::container::XEnumeration;
+using com::sun::star::container::XEnumerationAccess;
+
+namespace pq_sdbc_driver
+{
+
+OUString concatQualified( std::u16string_view a, std::u16string_view b)
+{
+ return OUString::Concat(a) + "." + b;
+}
+
+static OString iOUStringToOString( std::u16string_view str, ConnectionSettings const *settings) {
+ OSL_ENSURE(settings, "pgsql-sdbc: OUStringToOString got NULL settings");
+ return rtl::OUStringToOString( str, ConnectionSettings::encoding );
+}
+
+OString OUStringToOString( std::u16string_view str, ConnectionSettings const *settings) {
+ return iOUStringToOString( str, settings );
+}
+
+void bufferEscapeConstant( OUStringBuffer & buf, std::u16string_view value, ConnectionSettings *settings )
+{
+
+ OString y = iOUStringToOString( value, settings );
+ OStringBuffer strbuf( y.getLength() * 2 + 2 );
+ int error;
+ int len = PQescapeStringConn(settings->pConnection, const_cast<char*>(strbuf.getStr()), y.getStr() , y.getLength(), &error );
+ if ( error )
+ {
+ char *errstr = PQerrorMessage(settings->pConnection);
+ // As of PostgreSQL 9.1, the only possible errors "involve invalid multibyte encoding"
+ // According to https://www2.opengroup.org/ogsys/jsp/publications/PublicationDetails.jsp?publicationid=11216
+ // (X/Open SQL CLI, March 1995, ISBN: 1-85912-081-4, X/Open Document Number: C451)
+ // 22018 is for "Invalid character value" and seems to be the best match.
+ // We have no good XInterface Reference to pass here, so just give NULL
+ throw SQLException(OUString(errstr, strlen(errstr), ConnectionSettings::encoding),
+ nullptr,
+ "22018",
+ -1,
+ Any());
+ }
+ strbuf.setLength( len );
+ // Previously here RTL_TEXTENCODING_ASCII_US; as we set the PostgreSQL client_encoding to UTF8,
+ // we get UTF8 here, too. I'm not sure why it worked well before...
+ buf.append( OStringToOUString( strbuf, RTL_TEXTENCODING_UTF8 ) );
+}
+
+static void ibufferQuoteConstant( OUStringBuffer & buf, std::u16string_view value, ConnectionSettings *settings )
+{
+ buf.append( "'" );
+ bufferEscapeConstant( buf, value, settings );
+ buf.append( "'" );
+}
+
+void bufferQuoteConstant( OUStringBuffer & buf, std::u16string_view value, ConnectionSettings *settings )
+{
+ return ibufferQuoteConstant( buf, value, settings );
+}
+
+void bufferQuoteAnyConstant( OUStringBuffer & buf, const Any &val, ConnectionSettings *settings )
+{
+ if( val.hasValue() )
+ {
+ OUString str;
+ val >>= str;
+ bufferQuoteConstant( buf, str, settings );
+ }
+ else
+ buf.append( "NULL" );
+}
+
+static void ibufferQuoteIdentifier( OUStringBuffer & buf, std::u16string_view toQuote, ConnectionSettings *settings )
+{
+ OSL_ENSURE(settings, "pgsql-sdbc: bufferQuoteIdentifier got NULL settings");
+
+ OString y = iOUStringToOString( toQuote, settings );
+ char *cstr = PQescapeIdentifier(settings->pConnection, y.getStr(), y.getLength());
+ if ( cstr == nullptr )
+ {
+ char *errstr = PQerrorMessage(settings->pConnection);
+ // Implementation-defined SQLACCESS error
+ throw SQLException(OUString(errstr, strlen(errstr), ConnectionSettings::encoding),
+ nullptr,
+ "22018",
+ -1,
+ Any());
+ }
+ buf.append( OStringToOUString( cstr, RTL_TEXTENCODING_UTF8 ) );
+ PQfreemem( cstr );
+}
+
+void bufferQuoteIdentifier( OUStringBuffer & buf, std::u16string_view toQuote, ConnectionSettings *settings )
+{
+ return ibufferQuoteIdentifier(buf, toQuote, settings);
+}
+
+
+void bufferQuoteQualifiedIdentifier(
+ OUStringBuffer & buf, std::u16string_view schema, std::u16string_view table, ConnectionSettings *settings )
+{
+ ibufferQuoteIdentifier(buf, schema, settings);
+ buf.append( "." );
+ ibufferQuoteIdentifier(buf, table, settings);
+}
+
+void bufferQuoteQualifiedIdentifier(
+ OUStringBuffer & buf,
+ std::u16string_view schema,
+ std::u16string_view table,
+ std::u16string_view col,
+ ConnectionSettings *settings)
+{
+ ibufferQuoteIdentifier(buf, schema, settings);
+ buf.append( "." );
+ ibufferQuoteIdentifier(buf, table, settings);
+ buf.append( "." );
+ ibufferQuoteIdentifier(buf, col, settings);
+}
+
+
+OUString extractStringProperty(
+ const Reference< XPropertySet > & descriptor, const OUString &name )
+{
+ OUString value;
+ descriptor->getPropertyValue( name ) >>= value;
+ return value;
+}
+
+bool extractBoolProperty(
+ const Reference< XPropertySet > & descriptor, const OUString &name )
+{
+ bool value = false;
+ descriptor->getPropertyValue( name ) >>= value;
+ return value;
+}
+
+sal_Int32 extractIntProperty(
+ const Reference< XPropertySet > & descriptor, const OUString &name )
+{
+ sal_Int32 ret = 0;
+ descriptor->getPropertyValue( name ) >>= ret;
+ return ret;
+}
+
+void disposeObject( const css::uno::Reference< css::uno::XInterface > & r )
+{
+ Reference< XComponent > comp( r, UNO_QUERY );
+ if( comp.is() )
+ comp->dispose();
+}
+
+void disposeNoThrow( const css::uno::Reference< css::uno::XInterface > & r )
+{
+ try
+ {
+ disposeObject( r );
+ }
+ catch( SQLException & )
+ {
+ // ignore this
+ }
+
+}
+
+Reference< XConnection > extractConnectionFromStatement( const Reference< XInterface > & stmt )
+{
+ Reference< XConnection > ret;
+
+ Reference< css::sdbc::XStatement > owner( stmt, UNO_QUERY );
+ if( owner.is() )
+ ret = owner->getConnection();
+ else
+ {
+ Reference< css::sdbc::XPreparedStatement > myowner( stmt, UNO_QUERY );
+ if( myowner.is() )
+ ret = myowner->getConnection();
+ if( ! ret.is() )
+ throw SQLException(
+ "PQSDBC: Couldn't retrieve connection from statement",
+ Reference< XInterface > () , OUString(), 0 , css::uno::Any() );
+ }
+
+ return ret;
+
+}
+
+DisposeGuard::DisposeGuard( const Reference< XInterface > & r )
+ : d( r )
+{}
+
+DisposeGuard::~DisposeGuard()
+{
+ disposeNoThrow( d );
+}
+
+TransactionGuard::TransactionGuard( const Reference< XStatement > &stmt )
+ : m_stmt( stmt ),
+ m_commited( false )
+{
+ m_stmt->executeUpdate( getStatics().BEGIN );
+}
+
+void TransactionGuard::commit()
+{
+ m_stmt->executeUpdate( getStatics().COMMIT );
+ m_commited = true;
+}
+
+void TransactionGuard::executeUpdate( const OUString & sql )
+{
+ m_stmt->executeUpdate( sql );
+}
+
+TransactionGuard::~TransactionGuard()
+{
+ try
+ {
+ if( ! m_commited )
+ m_stmt->executeUpdate( getStatics().ROLLBACK );
+ }
+ catch( css::uno::Exception & )
+ {
+ // ignore, we are within a dtor
+ }
+
+ disposeNoThrow( m_stmt );
+}
+
+
+bool isWhitespace( sal_Unicode c )
+{
+ return ' ' == c || 9 == c || 10 == c || 13 == c;
+}
+
+OUString extractTableFromInsert( std::u16string_view sql )
+{
+ OUString ret;
+ size_t i = 0;
+ while (i < sql.size() && isWhitespace(sql[i])) { i++; }
+
+ if( o3tl::matchIgnoreAsciiCase(sql, u"insert", i) )
+ {
+ i += 6;
+ while (i < sql.size() && isWhitespace(sql[i])) { i++; }
+ if( o3tl::matchIgnoreAsciiCase(sql, u"into", i) )
+ {
+ i +=4;
+ while (i < sql.size() && isWhitespace(sql[i])) { i++; }
+ int start = i;
+ bool quote = (sql[i] == '"');
+ for( i++ ; i < sql.size() ; i ++ )
+ {
+ if( quote && sql[i] == '"' )
+ {
+ while (i < sql.size() && isWhitespace(sql[i])) { i++; }
+ if( '.' == sql[i] )
+ {
+ while (i < sql.size() && isWhitespace(sql[i])) { i++; }
+ if( '"' == sql[i] )
+ {
+ // the second part of the table name does not use quotes
+ // parse on
+ quote = false;
+ }
+ }
+ else
+ {
+ // end quoted name, ok
+ break;
+ }
+ }
+ else
+ {
+ if( isWhitespace( sql[i] ) )
+ {
+ // found the end of an unquoted name
+ break;
+ }
+ }
+ }
+ ret = o3tl::trim(sql.substr(start, i - start ));
+// printf( "pq_statement: parsed table name %s from insert\n" ,
+// OUStringToOString( ret, RTL_TEXTENCODING_ASCII_US).getStr() );
+ }
+ }
+ return ret;
+}
+
+
+static bool isOperator( char c )
+{
+ bool ret;
+ switch(c)
+ {
+ case '+':
+ case '-':
+ case '*':
+ case '/':
+ case '<':
+ case '>':
+ case '=':
+ case '~':
+ case '!':
+ case '@':
+ case '#':
+ case '%':
+ case '^':
+ case '&':
+ case '|':
+ case '`':
+ case '?':
+ case '$':
+ ret = true;
+ break;
+ default:
+ ret = false;
+ }
+ return ret;
+}
+
+void splitSQL( const OString & sql, std::vector< OString > &vec )
+{
+ int length = sql.getLength();
+
+ int i = 0;
+ bool singleQuote = false;
+ bool doubleQuote = false;
+ int start = 0;
+ for( ; i < length ; i ++ )
+ {
+ char c = sql[i];
+ if( doubleQuote )
+ {
+ if( '"' == c )
+ {
+ vec.push_back( OString( &sql.getStr()[start], i-start+1 ) );
+ start = i + 1;
+ doubleQuote = false;
+ }
+ }
+ else if( singleQuote )
+ {
+ if( '\'' == c && (i+1) < length && '\'' == sql[i+1] )
+ {
+ // two subsequent single quotes within a quoted string
+ // mean a single quote within the string
+ i ++;
+ }
+ else if( '\'' == c )
+ {
+ vec.push_back( OString( &sql.getStr()[start], i - start +1 ) );
+ start = i + 1; // leave single quotes !
+ singleQuote = false;
+ }
+ }
+ else
+ {
+ if( '"' == c )
+ {
+ vec.push_back( OString( &sql.getStr()[start], i - start ) );
+ doubleQuote = true;
+ start = i;
+ }
+ else if( '\'' == c )
+ {
+ vec.push_back( OString( &sql.getStr()[start], i - start ) );
+ singleQuote = true;
+ start = i;
+ }
+ }
+ }
+ if( start < i )
+ vec.push_back( OString( &sql.getStr()[start] , i - start ) );
+
+// for( i = 0 ; i < vec.size() ; i ++ )
+// printf( "%s!" , vec[i].getStr() );
+// printf( "\n" );
+
+}
+
+void tokenizeSQL( const OString & sql, std::vector< OString > &vec )
+{
+ int length = sql.getLength();
+
+ int i = 0;
+ bool singleQuote = false;
+ bool doubleQuote = false;
+ int start = 0;
+ for( ; i < length ; i ++ )
+ {
+ char c = sql[i];
+ if( doubleQuote )
+ {
+ if( '"' == c )
+ {
+ vec.push_back( OString( &sql.getStr()[start], i-start ) );
+ start = i + 1;
+ doubleQuote = false;
+ }
+ }
+ else if( singleQuote )
+ {
+ if( '\'' == c )
+ {
+ vec.push_back( OString( &sql.getStr()[start], i - start +1 ) );
+ start = i + 1; // leave single quotes !
+ singleQuote = false;
+ }
+ }
+ else
+ {
+ if( '"' == c )
+ {
+ doubleQuote = true;
+ start = i +1; // skip double quotes !
+ }
+ else if( '\'' == c )
+ {
+ singleQuote = true;
+ start = i; // leave single quotes
+ }
+ else if( isWhitespace( c ) )
+ {
+ if( i == start )
+ start ++; // skip additional whitespace
+ else
+ {
+ vec.push_back( OString( &sql.getStr()[start], i - start ) );
+ start = i +1;
+ }
+ }
+ else if( ',' == c || isOperator( c ) || '(' == c || ')' == c )
+ {
+ if( i - start )
+ vec.push_back( OString( &sql.getStr()[start], i - start ) );
+ vec.push_back( OString( &sql.getStr()[i], 1 ) );
+ start = i + 1;
+ }
+ else if( '.' == c )
+ {
+ if( ( i > start && sql[start] >= '0' && sql[start] <= '9' ) ||
+ ( i == start && i > 1 && isWhitespace( sql[i-1] ) ) )
+ {
+ // ignore, is a literal
+ }
+ else
+ {
+ if( i - start )
+ vec.push_back( OString( &sql.getStr()[start], i - start ) );
+ vec.push_back( "."_ostr );
+ start = i + 1;
+ }
+ }
+ }
+ }
+ if( start < i )
+ vec.push_back( OString( &sql.getStr()[start] , i - start ) );
+
+// for( i = 0 ; i < vec.size() ; i ++ )
+// printf( "%s!" , vec[i].getStr() );
+// printf( "\n" );
+}
+
+
+void splitConcatenatedIdentifier( std::u16string_view source, OUString *first, OUString *second)
+{
+ std::vector< OString > vec;
+ tokenizeSQL( rtl::OUStringToOString( source, RTL_TEXTENCODING_UTF8 ), vec );
+ switch (vec.size())
+ {
+ case 1:
+ first->clear();
+ *second = OStringToOUString( vec[0], RTL_TEXTENCODING_UTF8 );
+ break;
+ case 3:
+ *first = OStringToOUString( vec[0], RTL_TEXTENCODING_UTF8 );
+ *second = OStringToOUString( vec[2], RTL_TEXTENCODING_UTF8 );
+ break;
+ default:
+ SAL_WARN("connectivity.postgresql",
+ "pq_tools::splitConcatenatedIdentifier unexpected number of tokens in identifier: "
+ << vec.size());
+ }
+}
+
+OUString array2String( const css::uno::Sequence< Any > &seq )
+{
+ OUStringBuffer buf(128);
+ int len = seq.getLength();
+ buf.append( "{" );
+ for( int i = 0 ; i < len ; i ++ )
+ {
+ OUString element;
+ seq[i] >>= element;
+
+ if( i > 0 )
+ buf.append( "," );
+ int strLength = element.getLength();
+ buf.append( "\"" );
+ for( int j = 0 ; j < strLength ; j ++ )
+ {
+ sal_Unicode c = element[j];
+ if( c == '\\' || c == '"' || c == '{' || c == '}' )
+ {
+ buf.append( "\\" );
+ }
+ buf.append( c );
+ }
+ buf.append( "\"" );
+ }
+ buf.append( "}" );
+ return buf.makeStringAndClear();
+}
+
+
+std::vector< Any > parseArray( std::u16string_view str )
+{
+ size_t len = str.size();
+ bool doubleQuote = false;
+ int brackets = 0;
+ size_t i = 0;
+
+ OUStringBuffer current;
+ std::vector<Any> elements;
+ bool doubleQuotedValue = false;
+ while( i < len )
+ {
+ sal_Unicode c = str[i];
+ sal_Unicode cnext = str[i+1];
+ if( doubleQuote )
+ {
+ if( '\\' == c )
+ {
+ i ++;
+ current.append( cnext );
+ }
+ else if( '"' == c )
+ {
+ doubleQuote = false;
+ doubleQuotedValue = true; // signal, that there was an empty element
+ }
+ else
+ {
+ current.append( c );
+ }
+ }
+ else if ( '{' == c )
+ {
+ brackets ++;
+ }
+ else if( '}' == c )
+ {
+ brackets --;
+ if( brackets < 0 )
+ {
+ throw SQLException(
+ "error during array parsing, didn't expect a } at position "
+ + OUString::number(i) + " ('" + str + "')",
+ Reference< XInterface > (), OUString(), 1, Any() );
+ }
+ if( brackets == 0 )
+ {
+ if( !current.isEmpty() || doubleQuotedValue )
+ elements.push_back( Any( current.makeStringAndClear() ) );
+ }
+ else
+ {
+ current.append( c );
+ }
+ }
+ else if( '"' == c )
+ {
+// if( current.getLength() != 0 )
+// {
+// OUStringBuffer buf;
+// buf.appendAscii( "error during array parsing, didn't expect a \" at position " );
+// buf.append( i );
+// buf.append( " ('" );
+// buf.append( str );
+// buf.append( "')" );
+// throw SDBCException(
+// buf.makeStringAndClear(),
+// Reference< XInterface > (), 1, Any() );
+// }
+// else
+// {
+ doubleQuote = true;
+// }
+ }
+ else if( ',' == c && brackets == 1)
+ {
+ doubleQuotedValue = false;
+ elements.push_back( Any( current.makeStringAndClear() ) );
+ }
+ else if( isWhitespace( c ) )
+ {
+ // ignore whitespace without quotes
+ }
+ else
+ {
+ current.append( c );
+ }
+ i++;
+ }
+ return elements;
+}
+
+std::vector< sal_Int32 > parseIntArray( const OUString & str )
+{
+ sal_Int32 start = 0;
+ std::vector<sal_Int32> vec;
+// printf( ">%s<\n" , OUStringToOString( str, RTL_TEXTENCODING_UTF8 ).getStr() );
+ for( sal_Int32 i = str.indexOf( ' ' ) ; i != -1 ; i = str.indexOf( ' ', start) )
+ {
+ vec.push_back( rtl_ustr_toInt32( &str.pData->buffer[start], 10 ) );
+// printf( "found %d\n" , rtl_ustr_toInt32( &str.pData->buffer[start], 10 ));
+ start = i + 1;
+ }
+ vec.push_back( rtl_ustr_toInt32( &str.pData->buffer[start], 10 ) );
+// printf( "found %d\n" , rtl_ustr_toInt32( &str.pData->buffer[start], 10 ));
+ return vec;
+}
+
+void fillAttnum2attnameMap(
+ Int2StringMap &map,
+ const Reference< css::sdbc::XConnection > &conn,
+ const OUString &schema,
+ const OUString &table )
+{
+ Reference< XPreparedStatement > prep = conn->prepareStatement(
+ "SELECT attname,attnum "
+ "FROM pg_attribute "
+ "INNER JOIN pg_class ON attrelid = pg_class.oid "
+ "INNER JOIN pg_namespace ON pg_class.relnamespace = pg_namespace.oid "
+ "WHERE relname=? AND nspname=?" );
+
+ Reference< XParameters > paras( prep, UNO_QUERY_THROW );
+ paras->setString( 1 , table );
+ paras->setString( 2 , schema );
+ Reference< XResultSet > rs = prep->executeQuery();
+
+ Reference< XRow > xRow( rs , UNO_QUERY_THROW );
+ while( rs->next() )
+ {
+ map[ xRow->getInt(2) ] = xRow->getString(1);
+ }
+}
+
+OString extractSingleTableFromSelect( const std::vector< OString > &vec )
+{
+ OString ret;
+
+ if( 0 == rtl_str_shortenedCompareIgnoreAsciiCase_WithLength(
+ vec[0].pData->buffer, vec[0].pData->length, "select" , 6 , 6 ) )
+ {
+ size_t token = 0;
+
+ for( token = 1; token < vec.size() ; token ++ )
+ {
+ if( 0 == rtl_str_shortenedCompareIgnoreAsciiCase_WithLength(
+ vec[token].getStr(), vec[token].getLength(), "from" , 4 , 4 ) )
+ {
+ // found from
+ break;
+ }
+ }
+ token ++;
+
+ if( token < vec.size() && 0 == rtl_str_shortenedCompareIgnoreAsciiCase_WithLength(
+ vec[token].pData->buffer, vec[token].pData->length, "only " , 4 , 4 ) )
+ {
+ token ++;
+ }
+
+ if( token < vec.size() && vec[token] != "(" )
+ {
+ // it is a table or a function name
+ OStringBuffer buf(128);
+ if( '"' == vec[token][0] )
+ buf.append( &(vec[token].getStr()[1]) , vec[token].getLength() -2 );
+ else
+ buf.append( vec[token] );
+ token ++;
+
+ if( token < vec.size() )
+ {
+ if( vec[token] == "." )
+ {
+ buf.append( vec[token] );
+ token ++;
+ if( token < vec.size() )
+ {
+ if( '"' == vec[token][0] )
+ buf.append( &(vec[token].getStr()[1]) , vec[token].getLength() -2 );
+ else
+ buf.append( vec[token] );
+ token ++;
+ }
+ }
+ }
+
+ ret = buf.makeStringAndClear();
+ // now got my table candidate
+
+ if( token < vec.size() && vec[token] == "(" )
+ {
+ // whoops, it is a function
+ ret.clear();
+ }
+ else
+ {
+ if( token < vec.size() )
+ {
+ if( 0 == rtl_str_shortenedCompareIgnoreAsciiCase_WithLength(
+ vec[token].pData->buffer, vec[token].pData->length, "as" , 2, 2 ) )
+ {
+ token += 2; // skip alias
+ }
+ }
+
+ if( token < vec.size() )
+ {
+ if( vec[token] == "," )
+ {
+ // whoops, multiple tables are used
+ ret.clear();
+ }
+ else
+ {
+ static const char * forbiddenKeywords[] =
+ { "join", "natural", "outer", "inner", "left", "right", "full" , nullptr };
+ for( int i = 0 ; forbiddenKeywords[i] ; i ++ )
+ {
+ size_t nKeywordLen = strlen(forbiddenKeywords[i]);
+ if( 0 == rtl_str_shortenedCompareIgnoreAsciiCase_WithLength(
+ vec[token].pData->buffer, vec[token].pData->length,
+ forbiddenKeywords[i], nKeywordLen,
+ nKeywordLen ) )
+ {
+ // whoops, it is a join
+ ret.clear();
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return ret;
+
+}
+
+OUString getColExprForDefaultSettingVal(ConnectionSettings const *settings)
+{
+ return (PQserverVersion( settings->pConnection ) < 80000)?
+ OUString("pg_attrdef.adsrc"):
+ OUString("pg_get_expr(pg_attrdef.adbin, pg_attrdef.adrelid, true)");
+}
+
+css::uno::Sequence< sal_Int32 > string2intarray( const OUString & str )
+{
+ css::uno::Sequence< sal_Int32 > ret;
+ const sal_Int32 strlen = str.getLength();
+ if( str.getLength() > 1 )
+ {
+ sal_Int32 start = 0;
+ sal_uInt32 c;
+ for (;;)
+ {
+ c = str.iterateCodePoints(&start);
+ if (!iswspace(c))
+ break;
+ if ( start == strlen)
+ return ret;
+ }
+ if ( c != L'{' )
+ return ret;
+ for (;;)
+ {
+ c = str.iterateCodePoints(&start);
+ if ( !iswspace(c) )
+ break;
+ if ( start == strlen)
+ return ret;
+ }
+ if ( c == L'}' )
+ return ret;
+
+ std::vector< sal_Int32 > vec;
+ do
+ {
+ OUStringBuffer digits;
+ do
+ {
+ if(!iswspace(c))
+ break;
+ if ( start == strlen)
+ return ret;
+ c=str.iterateCodePoints(&start);
+ } while ( c );
+ do
+ {
+ if (!iswdigit(c))
+ break;
+ if ( start == strlen)
+ return ret;
+ digits.append(OUString(&c, 1));
+ c = str.iterateCodePoints(&start);
+ } while ( c );
+ vec.push_back( o3tl::toInt32(digits) );
+ do
+ {
+ if(!iswspace(c))
+ break;
+ if ( start == strlen)
+ return ret;
+ c = str.iterateCodePoints(&start);
+ } while ( c );
+ if ( c == L'}' )
+ break;
+ if ( str.iterateCodePoints(&start) != L',' )
+ return ret;
+ if ( start == strlen)
+ return ret;
+ } while( true );
+ // vec is guaranteed non-empty
+ assert(vec.size() > 0);
+ ret = css::uno::Sequence< sal_Int32 > ( vec.data() , vec.size() );
+ }
+ return ret;
+}
+
+
+Sequence< OUString > convertMappedIntArray2StringArray(
+ const Int2StringMap &map, const Sequence< sal_Int32 > &intArray )
+{
+ Sequence< OUString > ret( intArray.getLength() );
+ auto retRange = asNonConstRange(ret);
+ for( int i = 0; i < intArray.getLength() ; i ++ )
+ {
+ Int2StringMap::const_iterator ii = map.find( intArray[i] );
+ if( ii != map.end() )
+ retRange[i] = ii->second;
+ }
+ return ret;
+}
+
+
+OUString sqltype2string( const Reference< XPropertySet > & desc )
+{
+ OUStringBuffer typeName;
+ typeName.append( extractStringProperty( desc, getStatics().TYPE_NAME ) );
+ sal_Int32 precision = extractIntProperty( desc, getStatics().PRECISION );
+
+ if( precision )
+ {
+ switch( extractIntProperty( desc, getStatics().TYPE ) )
+ {
+ case css::sdbc::DataType::VARBINARY:
+ case css::sdbc::DataType::VARCHAR:
+ case css::sdbc::DataType::CHAR:
+ {
+ typeName.append( "(" + OUString::number(precision) + ")" );
+ break;
+ }
+ case css::sdbc::DataType::DECIMAL:
+ case css::sdbc::DataType::NUMERIC:
+ {
+ typeName.append( "("
+ + OUString::number(precision)
+ + ","
+ + OUString::number(extractIntProperty( desc, getStatics().SCALE ))
+ + ")" );
+ break;
+ }
+ default:
+ ((void)0);
+ }
+ }
+ return typeName.makeStringAndClear();
+}
+
+
+static void keyType2String( OUStringBuffer & buf, sal_Int32 keyType )
+{
+ if( css::sdbc::KeyRule::CASCADE == keyType )
+ {
+ buf.append( "CASCADE " );
+ }
+ else if( css::sdbc::KeyRule::RESTRICT == keyType )
+ {
+ buf.append( "RESTRICT " );
+ }
+ else if( css::sdbc::KeyRule::SET_DEFAULT == keyType )
+ {
+ buf.append( "SET DEFAULT " );
+ }
+ else if( css::sdbc::KeyRule::SET_NULL == keyType )
+ {
+ buf.append( "SET NULL " );
+ }
+ else //if( css::sdbc::KeyRule::NO_ACTION == keyType )
+ {
+ buf.append( "NO ACTION " );
+ }
+}
+
+void bufferKey2TableConstraint(
+ OUStringBuffer &buf, const Reference< XPropertySet > &key, ConnectionSettings *settings )
+{
+ Statics &st = getStatics();
+ sal_Int32 type = extractIntProperty( key, st.TYPE );
+ OUString referencedTable = extractStringProperty( key, st.REFERENCED_TABLE );
+ sal_Int32 updateRule = extractIntProperty( key, st.UPDATE_RULE );
+ sal_Int32 deleteRule = extractIntProperty( key, st.DELETE_RULE );
+ bool foreign = false;
+ if( type == css::sdbcx::KeyType::UNIQUE )
+ {
+ buf.append( "UNIQUE( " );
+ }
+ else if( type == css::sdbcx::KeyType::PRIMARY )
+ {
+ buf.append( "PRIMARY KEY( " );
+ }
+ else if( type == css::sdbcx::KeyType::FOREIGN )
+ {
+ foreign = true;
+ buf.append( "FOREIGN KEY( " );
+ }
+
+ Reference< XColumnsSupplier > columns( key, UNO_QUERY );
+ if( columns.is() )
+ {
+ Reference< XEnumerationAccess > colEnumAccess( columns->getColumns(), UNO_QUERY );
+ if( colEnumAccess.is() )
+ {
+ Reference< XEnumeration > colEnum = colEnumAccess->createEnumeration();
+ bool first = true;
+ while(colEnum.is() && colEnum->hasMoreElements() )
+ {
+ if( first )
+ {
+ first = false;
+ }
+ else
+ {
+ buf.append( ", " );
+ }
+ Reference< XPropertySet > keyColumn( colEnum->nextElement(), UNO_QUERY_THROW );
+ bufferQuoteIdentifier(buf, extractStringProperty( keyColumn, st.NAME ), settings );
+ }
+ }
+ }
+ buf.append( ") " );
+
+ if( !foreign )
+ return;
+
+ buf.append( "REFERENCES " );
+ OUString schema;
+ OUString tableName;
+ splitConcatenatedIdentifier( referencedTable, &schema, &tableName );
+ bufferQuoteQualifiedIdentifier(buf , schema, tableName, settings );
+ if(columns.is() )
+ {
+ Reference< XEnumerationAccess > colEnumAccess( columns->getColumns(), UNO_QUERY);
+ if( colEnumAccess.is() )
+ {
+ buf.append( " (" );
+ Reference< XEnumeration > colEnum(colEnumAccess->createEnumeration());
+ bool first = true;
+ while(colEnum.is() && colEnum->hasMoreElements() )
+ {
+ if( first )
+ {
+ first = false;
+ }
+ else
+ {
+ buf.append( ", " );
+ }
+ Reference< XPropertySet > keyColumn( colEnum->nextElement(), UNO_QUERY_THROW );
+ bufferQuoteIdentifier(
+ buf, extractStringProperty( keyColumn, st.RELATED_COLUMN ), settings );
+ }
+ buf.append( ") " );
+ }
+ }
+
+ buf.append( "ON DELETE " );
+ keyType2String( buf, deleteRule );
+ buf.append( " ON UPDATE " );
+ keyType2String( buf, updateRule );
+
+}
+
+void extractNameValuePairsFromInsert( String2StringMap & map, const OString & lastQuery )
+{
+ std::vector< OString > vec;
+ tokenizeSQL( lastQuery, vec );
+
+ int nSize = vec.size();
+// printf( "1 %d\n", nSize );
+ if( !(nSize > 6 &&
+ vec[0].equalsIgnoreAsciiCase( "insert" ) &&
+ vec[1].equalsIgnoreAsciiCase( "into" )) )
+ return;
+
+ int n = 2;
+
+// printf( "1a\n" );
+ // skip table name
+ if( vec[n+1].equalsIgnoreAsciiCase( "." ) )
+ {
+ n +=2;
+ }
+
+ n ++;
+ if( !vec[n].equalsIgnoreAsciiCase( "(" ) )
+ return;
+
+ std::vector< OString> names;
+// printf( "2\n" );
+ // extract names
+ n++;
+ while( nSize > n && ! vec[n].equalsIgnoreAsciiCase( ")" ) )
+ {
+ names.push_back( vec[n] );
+ if( nSize > n+1 && vec[n+1].equalsIgnoreAsciiCase( "," ) )
+ {
+ n ++;
+ }
+ n++;
+ }
+ n++;
+
+ // now read the values
+ if( !(nSize > n +1 && vec[n].equalsIgnoreAsciiCase("VALUES") &&
+ vec[n+1].equalsIgnoreAsciiCase( "(" )) )
+ return;
+
+ n +=2;
+// printf( "3\n" );
+ for (auto& name : names)
+ {
+ if (n >= nSize)
+ break;
+
+ map[name] = vec[n];
+ if( nSize > n+1 && vec[n+1].equalsIgnoreAsciiCase(",") )
+ {
+ n ++;
+ }
+ n++;
+ }
+}
+
+OUString querySingleValue(
+ const css::uno::Reference< css::sdbc::XConnection > &connection,
+ const OUString &query )
+{
+ OUString ret;
+ Reference< XStatement > stmt = connection->createStatement();
+ DisposeGuard guard( stmt );
+ Reference< XResultSet > rs = stmt->executeQuery( query );
+ Reference< XRow > xRow( rs, UNO_QUERY );
+ if( rs->next() )
+ ret = xRow->getString( 1 );
+ return ret;
+}
+
+
+// copied from connectivity/source/dbtools, can't use the function directly
+bool implSetObject( const Reference< XParameters >& _rxParameters,
+ const sal_Int32 _nColumnIndex, const Any& _rValue)
+{
+ bool bSuccessfullyReRouted = true;
+ switch (_rValue.getValueTypeClass())
+ {
+ case css::uno::TypeClass_HYPER:
+ {
+ _rxParameters->setLong( _nColumnIndex, sal_Int64(0) );
+ }
+ break;
+
+ case css::uno::TypeClass_VOID:
+ _rxParameters->setNull(_nColumnIndex,css::sdbc::DataType::VARCHAR);
+ break;
+
+ case css::uno::TypeClass_STRING:
+ _rxParameters->setString(_nColumnIndex, *o3tl::forceAccess<OUString>(_rValue));
+ break;
+
+ case css::uno::TypeClass_BOOLEAN:
+ _rxParameters->setBoolean(_nColumnIndex, *o3tl::forceAccess<bool>(_rValue));
+ break;
+
+ case css::uno::TypeClass_BYTE:
+ _rxParameters->setByte(_nColumnIndex, *o3tl::forceAccess<sal_Int8>(_rValue));
+ break;
+
+ case css::uno::TypeClass_UNSIGNED_SHORT:
+ case css::uno::TypeClass_SHORT:
+ _rxParameters->setShort(_nColumnIndex, *o3tl::forceAccess<sal_Int16>(_rValue));
+ break;
+
+ case css::uno::TypeClass_CHAR:
+ _rxParameters->setString(_nColumnIndex, OUString(*o3tl::forceAccess<sal_Unicode>(_rValue)));
+ break;
+
+ case css::uno::TypeClass_UNSIGNED_LONG:
+ case css::uno::TypeClass_LONG:
+ _rxParameters->setInt(_nColumnIndex, *o3tl::forceAccess<sal_Int32>(_rValue));
+ break;
+
+ case css::uno::TypeClass_FLOAT:
+ _rxParameters->setFloat(_nColumnIndex, *o3tl::forceAccess<float>(_rValue));
+ break;
+
+ case css::uno::TypeClass_DOUBLE:
+ _rxParameters->setDouble(_nColumnIndex, *o3tl::forceAccess<double>(_rValue));
+ break;
+
+ case css::uno::TypeClass_SEQUENCE:
+ if (auto s = o3tl::tryAccess<Sequence< sal_Int8 >>(_rValue))
+ {
+ _rxParameters->setBytes(_nColumnIndex, *s);
+ }
+ else
+ bSuccessfullyReRouted = false;
+ break;
+ case css::uno::TypeClass_STRUCT:
+ if (auto s1 = o3tl::tryAccess<css::util::DateTime>(_rValue))
+ _rxParameters->setTimestamp(_nColumnIndex, *s1);
+ else if (auto s2 = o3tl::tryAccess<css::util::Date>(_rValue))
+ _rxParameters->setDate(_nColumnIndex, *s2);
+ else if (auto s3 = o3tl::tryAccess<css::util::Time>(_rValue))
+ _rxParameters->setTime(_nColumnIndex, *s3);
+ else
+ bSuccessfullyReRouted = false;
+ break;
+
+ case css::uno::TypeClass_INTERFACE:
+ {
+ Reference< css::io::XInputStream > xStream;
+ if (_rValue >>= xStream)
+ {
+ _rValue >>= xStream;
+ _rxParameters->setBinaryStream(_nColumnIndex, xStream, xStream->available());
+ break;
+ }
+ [[fallthrough]];
+ }
+ default:
+ bSuccessfullyReRouted = false;
+
+ }
+
+ return bSuccessfullyReRouted;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/postgresql/pq_tools.hxx b/connectivity/source/drivers/postgresql/pq_tools.hxx
new file mode 100644
index 0000000000..8a31e207cc
--- /dev/null
+++ b/connectivity/source/drivers/postgresql/pq_tools.hxx
@@ -0,0 +1,176 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * Effective License of whole file:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011:
+ *
+ * The Contents of this file are made available subject to the terms of
+ * the GNU Lesser General Public License Version 2.1
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * Contributor(s): Joerg Budischewski
+ *
+ * All parts contributed on or after August 2011:
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ ************************************************************************/
+
+#pragma once
+
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/sdbc/XParameters.hpp>
+#include <com/sun/star/util/Date.hpp>
+#include <com/sun/star/util/Time.hpp>
+#include <com/sun/star/util/DateTime.hpp>
+
+#include <rtl/ustrbuf.hxx>
+#include <rtl/string.hxx>
+
+#include "pq_connection.hxx"
+
+#include <string_view>
+#include <vector>
+
+namespace
+{
+// helper to create one-time deleters
+template <auto fn>
+using deleter_from_fn = std::integral_constant<decltype(fn), fn>;
+
+}
+
+namespace pq_sdbc_driver
+{
+bool isWhitespace( sal_Unicode c );
+
+OUString concatQualified( std::u16string_view a, std::u16string_view b);
+
+OString OUStringToOString( std::u16string_view str, ConnectionSettings const *settings);
+
+void bufferQuoteConstant( OUStringBuffer & buf, std::u16string_view str, ConnectionSettings *settings );
+void bufferQuoteAnyConstant( OUStringBuffer & buf, const css::uno::Any &val, ConnectionSettings *settings );
+
+void bufferEscapeConstant( OUStringBuffer & buf, std::u16string_view str, ConnectionSettings *settings );
+
+OUString sqltype2string(
+ const css::uno::Reference< css::beans::XPropertySet > & column );
+
+
+void bufferQuoteQualifiedIdentifier(
+ OUStringBuffer & buf, std::u16string_view schema, std::u16string_view name, ConnectionSettings *settings );
+
+void bufferQuoteQualifiedIdentifier(
+ OUStringBuffer & buf,
+ std::u16string_view schema,
+ std::u16string_view name,
+ std::u16string_view col,
+ ConnectionSettings *settings );
+
+void bufferQuoteIdentifier( OUStringBuffer & buf, std::u16string_view toQuote, ConnectionSettings *settings );
+void bufferKey2TableConstraint(
+ OUStringBuffer &buf,
+ const css::uno::Reference< css::beans::XPropertySet > &key,
+ ConnectionSettings *settings );
+
+OUString extractStringProperty(
+ const css::uno::Reference< css::beans::XPropertySet > & descriptor,
+ const OUString &name );
+
+sal_Int32 extractIntProperty(
+ const css::uno::Reference< css::beans::XPropertySet > & descriptor,
+ const OUString &name );
+
+bool extractBoolProperty(
+ const css::uno::Reference< css::beans::XPropertySet > & descriptor,
+ const OUString &name );
+
+void disposeNoThrow( const css::uno::Reference< css::uno::XInterface > & r );
+void disposeObject( const css::uno::Reference< css::uno::XInterface > & r );
+
+OUString extractTableFromInsert( std::u16string_view sql );
+OString extractSingleTableFromSelect( const std::vector< OString > &vec );
+
+OUString getColExprForDefaultSettingVal(ConnectionSettings const *settings);
+
+void tokenizeSQL( const OString & sql, std::vector< OString > &vec );
+void splitSQL( const OString & sql, std::vector< OString > &vec );
+std::vector< sal_Int32 > parseIntArray( const OUString & str );
+/// @throws css::sdbc::SQLException
+std::vector< css::uno::Any > parseArray( std::u16string_view str );
+
+OUString array2String( const css::uno::Sequence< css::uno::Any > &seq );
+
+css::uno::Reference< css::sdbc::XConnection > extractConnectionFromStatement(
+ const css::uno::Reference< css::uno::XInterface > & stmt );
+
+void splitConcatenatedIdentifier( std::u16string_view source, OUString *first, OUString *second);
+
+
+void fillAttnum2attnameMap(
+ Int2StringMap &map,
+ const css::uno::Reference< css::sdbc::XConnection > &conn,
+ const OUString &schema,
+ const OUString &table );
+
+css::uno::Sequence< sal_Int32 > string2intarray( const OUString & str );
+
+css::uno::Sequence< OUString > convertMappedIntArray2StringArray(
+ const Int2StringMap &map, const css::uno::Sequence< sal_Int32> &source );
+
+typedef std::unordered_map< OString, OString > String2StringMap;
+
+OUString querySingleValue(
+ const css::uno::Reference< css::sdbc::XConnection > &connection,
+ const OUString &query );
+
+void extractNameValuePairsFromInsert( String2StringMap & map, const OString & lastQuery );
+sal_Int32 typeNameToDataType( const OUString &typeName, std::u16string_view typtype );
+
+// copied from connectivity/source/dbtools, can't use the function directly
+bool implSetObject( const css::uno::Reference< css::sdbc::XParameters >& _rxParameters,
+ const sal_Int32 _nColumnIndex, const css::uno::Any& _rValue);
+
+class DisposeGuard
+{
+ css::uno::Reference< css::uno::XInterface > d;
+public:
+ explicit DisposeGuard(const css::uno::Reference< css::uno::XInterface > & r );
+ ~DisposeGuard();
+
+};
+
+class TransactionGuard
+{
+ css::uno::Reference< css::sdbc::XStatement > m_stmt;
+ bool m_commited;
+public:
+ /// takes over ownership of given statement
+ explicit TransactionGuard( const css::uno::Reference< css::sdbc::XStatement > &stmt );
+ ~TransactionGuard( );
+
+ void commit();
+ void executeUpdate( const OUString & sql );
+};
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/postgresql/pq_updateableresultset.cxx b/connectivity/source/drivers/postgresql/pq_updateableresultset.cxx
new file mode 100644
index 0000000000..49eb65cd9f
--- /dev/null
+++ b/connectivity/source/drivers/postgresql/pq_updateableresultset.cxx
@@ -0,0 +1,550 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * Effective License of whole file:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011:
+ *
+ * The Contents of this file are made available subject to the terms of
+ * the GNU Lesser General Public License Version 2.1
+ *
+ * Copyright: 200? by Sun Microsystems, Inc.
+ *
+ * Contributor(s): Joerg Budischewski
+ *
+ * All parts contributed on or after August 2011:
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ ************************************************************************/
+
+#include <sal/log.hxx>
+#include <rtl/ref.hxx>
+#include <rtl/ustrbuf.hxx>
+
+#include <cppuhelper/queryinterface.hxx>
+#include <cppuhelper/typeprovider.hxx>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <com/sun/star/sdbc/XGeneratedResultSet.hpp>
+
+#include "pq_updateableresultset.hxx"
+#include "pq_resultsetmetadata.hxx"
+#include "pq_tools.hxx"
+#include "pq_statics.hxx"
+
+#include <string.h>
+
+#include <connectivity/dbconversion.hxx>
+
+using osl::MutexGuard;
+
+
+using com::sun::star::uno::Reference;
+using com::sun::star::uno::Sequence;
+using com::sun::star::uno::UNO_QUERY;
+using com::sun::star::uno::Any;
+using com::sun::star::uno::Type;
+
+using com::sun::star::sdbc::XGeneratedResultSet;
+using com::sun::star::sdbc::XResultSetMetaDataSupplier;
+using com::sun::star::sdbc::SQLException;
+using com::sun::star::sdbc::XResultSet;
+using com::sun::star::sdbc::XCloseable;
+using com::sun::star::sdbc::XColumnLocate;
+using com::sun::star::sdbc::XResultSetUpdate;
+using com::sun::star::sdbc::XRowUpdate;
+using com::sun::star::sdbc::XRow;
+using com::sun::star::sdbc::XStatement;
+
+using com::sun::star::beans::XFastPropertySet;
+using com::sun::star::beans::XPropertySet;
+using com::sun::star::beans::XMultiPropertySet;
+
+using namespace dbtools;
+
+namespace pq_sdbc_driver
+{
+
+
+css::uno::Reference< css::sdbc::XCloseable > UpdateableResultSet::createFromPGResultSet(
+ const ::rtl::Reference< comphelper::RefCountedMutex > & mutex,
+ const css::uno::Reference< css::uno::XInterface > &owner,
+ ConnectionSettings **ppSettings,
+ PGresult *result,
+ const OUString &schema,
+ const OUString &table,
+ std::vector< OUString > && primaryKey )
+{
+ sal_Int32 columnCount = PQnfields( result );
+ sal_Int32 rowCount = PQntuples( result );
+ std::vector< OUString > columnNames( columnCount );
+ for( int i = 0 ; i < columnCount ; i ++ )
+ {
+ char * name = PQfname( result, i );
+ columnNames[i] = OUString( name, strlen(name), ConnectionSettings::encoding );
+ }
+ std::vector< std::vector< Any > > data( rowCount );
+
+ // copy all the data into unicode strings (also binaries, as we yet
+ // don't know, what a binary is and what not!)
+ for( int row = 0 ; row < rowCount ; row ++ )
+ {
+ std::vector< Any > aRow( columnCount );
+ for( int col = 0 ; col < columnCount ; col ++ )
+ {
+ if( ! PQgetisnull( result, row, col ) )
+ {
+ char * val = PQgetvalue( result, row, col );
+
+ aRow[col] <<=
+ OUString( val, strlen( val ), ConnectionSettings::encoding );
+ }
+ }
+ data[row] = aRow;
+ }
+
+ rtl::Reference<UpdateableResultSet> pRS = new UpdateableResultSet(
+ mutex, owner, std::move(columnNames), std::move(data), ppSettings, schema, table, std::move(primaryKey) );
+
+ pRS->m_meta = new ResultSetMetaData( mutex, pRS,nullptr, ppSettings, result, schema, table );
+
+ PQclear( result ); // we don't need it anymore
+
+ return pRS;
+}
+
+css::uno::Any UpdateableResultSet::queryInterface(
+ const css::uno::Type & reqType )
+{
+ Any ret = SequenceResultSet::queryInterface( reqType );
+ if( ! ret.hasValue() )
+ ret = ::cppu::queryInterface(
+ reqType,
+ static_cast< XResultSetUpdate * > ( this ),
+ static_cast< XRowUpdate * > ( this ) );
+ return ret;
+}
+
+
+css::uno::Sequence< css::uno::Type > UpdateableResultSet::getTypes()
+{
+ static cppu::OTypeCollection collection(
+ cppu::UnoType<XResultSetUpdate>::get(),
+ cppu::UnoType<XRowUpdate>::get(),
+ SequenceResultSet::getTypes());
+
+ return collection.getTypes();
+
+}
+
+css::uno::Sequence< sal_Int8> UpdateableResultSet::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+OUString UpdateableResultSet::buildWhereClause()
+{
+ OUString ret;
+ if( !m_primaryKey.empty() )
+ {
+ OUStringBuffer buf( 128 );
+ buf.append( " WHERE " );
+ for( size_t i = 0 ; i < m_primaryKey.size() ; i ++ )
+ {
+ if( i > 0 )
+ buf.append( " AND " );
+ sal_Int32 index = findColumn( m_primaryKey[i] );
+ bufferQuoteIdentifier( buf, m_primaryKey[i], *m_ppSettings );
+ buf.append( " = " );
+ bufferQuoteConstant( buf, getString( index ), *m_ppSettings );
+ }
+ ret = buf.makeStringAndClear();
+ }
+ return ret;
+}
+
+
+void UpdateableResultSet::insertRow( )
+{
+ MutexGuard guard( m_xMutex->GetMutex() );
+ SAL_INFO("connectivity.postgresql", "UpdateableResultSet::insertRow() got called");
+
+ if( ! m_insertRow )
+ throw SQLException(
+ "pq_resultset.insertRow: moveToInsertRow has not been called !",
+ *this, OUString(), 1, Any() );
+
+ OUStringBuffer buf( 128 );
+ buf.append( "INSERT INTO " );
+ bufferQuoteQualifiedIdentifier( buf, m_schema, m_table, *m_ppSettings );
+ buf.append( " ( " );
+
+ int columns = 0;
+ for( UpdateableFieldVector::size_type i = 0 ; i < m_updateableField.size() ; i++ )
+ {
+ if( m_updateableField[i].isTouched )
+ {
+ if( columns > 0 )
+ buf.append( ", " );
+ columns ++;
+ bufferQuoteIdentifier( buf, m_columnNames[i], *m_ppSettings);
+ }
+ }
+ buf.append( " ) VALUES ( " );
+
+ columns = 0;
+ for(const UpdateableField & i : m_updateableField)
+ {
+ if( i.isTouched )
+ {
+ if( columns > 0 )
+ buf.append( " , " );
+ columns ++;
+ bufferQuoteAnyConstant( buf, i.value, *m_ppSettings );
+
+// OUString val;
+// m_updateableField[i].value >>= val;
+// buf.append( val );
+// OStringToOUString(val, (*m_ppSettings)->encoding ) );
+ }
+ }
+
+ buf.append( " )" );
+
+ Reference< XStatement > stmt =
+ extractConnectionFromStatement(m_owner)->createStatement();
+ DisposeGuard dispGuard( stmt );
+ stmt->executeUpdate( buf.makeStringAndClear() );
+
+ // reflect the changes !
+ m_rowCount ++;
+ m_data.resize( m_rowCount );
+ m_data[m_rowCount-1] = std::vector< Any > ( m_fieldCount );
+ Reference< XGeneratedResultSet > result( stmt, UNO_QUERY );
+ if( result.is() )
+ {
+ Reference< XResultSet > rs = result->getGeneratedValues();
+ if( rs.is() && rs->next() )
+ {
+ Reference< XColumnLocate > columnLocate( rs, UNO_QUERY );
+ Reference< XRow> xRow ( rs, UNO_QUERY );
+ for( int i = 0 ; i < m_fieldCount ; i++ )
+ {
+ int field = columnLocate->findColumn( m_columnNames[i] );
+ if( field >= 1 )
+ {
+ m_data[m_rowCount-1][i] <<= xRow->getString( field );
+// printf( "adding %s %s\n" ,
+// OUStringToOString( m_columnNames[i], RTL_TEXTENCODING_ASCII_US).getStr(),
+// OUStringToOString( xRow->getString( field ), RTL_TEXTENCODING_ASCII_US).getStr() );
+
+ }
+ }
+ }
+ else
+ {
+ // do the best we can ( DEFAULT and AUTO increment values fail ! )
+ for( int i = 0 ; i < m_fieldCount ; i ++ )
+ {
+ if( m_updateableField[i].isTouched )
+ m_data[m_rowCount-1][i] = m_updateableField[i].value;
+ }
+ }
+ }
+
+ // cleanup
+ m_updateableField = UpdateableFieldVector();
+}
+
+void UpdateableResultSet::updateRow( )
+{
+ MutexGuard guard( m_xMutex->GetMutex() );
+ SAL_INFO("connectivity.postgresql", "UpdateableResultSet::updateRow() got called");
+
+ if( m_insertRow )
+ throw SQLException(
+ "pq_resultset.updateRow: moveToCurrentRow has not been called !",
+ *this, OUString(), 1, Any() );
+
+ OUStringBuffer buf( 128 );
+ buf.append( "UPDATE " );
+ bufferQuoteQualifiedIdentifier( buf, m_schema, m_table, *m_ppSettings );
+ buf.append( "SET " );
+
+ int columns = 0;
+ for( UpdateableFieldVector::size_type i = 0; i < m_updateableField.size() ; i ++ )
+ {
+ if( m_updateableField[i].isTouched )
+ {
+ if( columns > 0 )
+ buf.append( ", " );
+ columns ++;
+
+ buf.append( m_columnNames[i]
+ + " = " );
+ bufferQuoteAnyConstant( buf, m_updateableField[i].value, *m_ppSettings );
+// OUString val;
+// m_updateableField[i].value >>= val;
+// bufferQuoteConstant( buf, val ):
+// buf.append( val );
+ }
+ }
+ buf.append( buildWhereClause() );
+
+ Reference< XStatement > stmt = extractConnectionFromStatement(m_owner)->createStatement();
+ DisposeGuard dispGuard( stmt );
+ stmt->executeUpdate( buf.makeStringAndClear() );
+
+ // reflect the changes !
+ for( int i = 0 ; i < m_fieldCount ; i ++ )
+ {
+ if( m_updateableField[i].isTouched )
+ m_data[m_row][i] = m_updateableField[i].value;
+ }
+ m_updateableField = UpdateableFieldVector();
+}
+
+void UpdateableResultSet::deleteRow( )
+{
+ SAL_INFO("connectivity.postgresql", "UpdateableResultSet::deleteRow() got called");
+
+ if( m_insertRow )
+ throw SQLException(
+ "pq_resultset.deleteRow: deleteRow cannot be called when on insert row !",
+ *this, OUString(), 1, Any() );
+
+ if( m_row < 0 || m_row >= m_rowCount )
+ {
+ throw SQLException(
+ "deleteRow cannot be called on invalid row ("
+ + OUString::number(m_row) + ")",
+ *this, OUString(), 0, Any() );
+ }
+
+ Reference< XStatement > stmt = extractConnectionFromStatement(m_owner)->createStatement();
+ DisposeGuard dispGuard( stmt );
+ OUStringBuffer buf( 128 );
+ buf.append( "DELETE FROM " );
+ bufferQuoteQualifiedIdentifier( buf, m_schema, m_table, *m_ppSettings );
+ buf.append( " "
+ + buildWhereClause() );
+
+ stmt->executeUpdate( buf.makeStringAndClear() );
+
+ // reflect the changes !
+ for( int i = m_row + 1; i < m_row ; i ++ )
+ {
+ m_data[i-1] = m_data[i];
+ }
+ m_rowCount --;
+ m_data.resize( m_rowCount );
+ }
+
+void UpdateableResultSet::cancelRowUpdates( )
+{
+ MutexGuard guard( m_xMutex->GetMutex() );
+ m_updateableField = UpdateableFieldVector();
+}
+
+void UpdateableResultSet::moveToInsertRow( )
+{
+ m_insertRow = true;
+}
+
+void UpdateableResultSet::moveToCurrentRow( )
+{
+ m_insertRow = false;
+}
+
+void UpdateableResultSet::checkUpdate( sal_Int32 columnIndex)
+{
+ checkColumnIndex( columnIndex );
+ if( m_updateableField.empty() )
+ m_updateableField = UpdateableFieldVector( m_fieldCount );
+ m_updateableField[columnIndex-1].isTouched = true;
+}
+
+void UpdateableResultSet::updateNull( sal_Int32 columnIndex )
+{
+ MutexGuard guard( m_xMutex->GetMutex() );
+ checkClosed();
+ checkUpdate( columnIndex );
+ m_updateableField[columnIndex-1].value = Any();
+}
+
+void UpdateableResultSet::updateBoolean( sal_Int32 columnIndex, sal_Bool x )
+{
+ MutexGuard guard( m_xMutex->GetMutex() );
+ checkClosed();
+ checkUpdate( columnIndex );
+
+ Statics &st = getStatics();
+ m_updateableField[columnIndex-1].value <<= ( x ? st.TRUE : st.FALSE );
+
+}
+
+void UpdateableResultSet::updateByte( sal_Int32 columnIndex, sal_Int8 x )
+{
+ updateInt(columnIndex,x);
+}
+
+void UpdateableResultSet::updateShort( sal_Int32 columnIndex, sal_Int16 x )
+{
+ updateInt( columnIndex, x );
+}
+
+void UpdateableResultSet::updateInt( sal_Int32 columnIndex, sal_Int32 x )
+{
+ updateLong( columnIndex, x );
+// MutexGuard guard( m_xMutex->GetMutex() );
+// checkClosed();
+// checkUpdate( columnIndex );
+
+// m_updateableField[columnIndex-1].value <<= OUString::valueOf( x );
+
+}
+
+void UpdateableResultSet::updateLong( sal_Int32 columnIndex, sal_Int64 x )
+{
+ MutexGuard guard( m_xMutex->GetMutex() );
+ checkClosed();
+ checkUpdate( columnIndex );
+
+// OStringBuffer buf( 20 );
+// buf.append( "'" );
+// buf.append( (sal_Int64) x );
+// buf.append( "'" );
+ m_updateableField[columnIndex-1].value <<= OUString::number( x );
+}
+
+void UpdateableResultSet::updateFloat( sal_Int32 columnIndex, float x )
+{
+
+ MutexGuard guard( m_xMutex->GetMutex() );
+ checkClosed();
+ checkUpdate( columnIndex );
+
+ m_updateableField[columnIndex-1].value <<= OUString::number( x );
+}
+
+void UpdateableResultSet::updateDouble( sal_Int32 columnIndex, double x )
+{
+ MutexGuard guard( m_xMutex->GetMutex() );
+ checkClosed();
+ checkUpdate( columnIndex );
+
+ m_updateableField[columnIndex-1].value <<= OUString::number( x );
+}
+
+void UpdateableResultSet::updateString( sal_Int32 columnIndex, const OUString& x )
+{
+ MutexGuard guard( m_xMutex->GetMutex() );
+ checkClosed();
+ checkUpdate( columnIndex );
+
+ m_updateableField[columnIndex-1].value <<= x;
+}
+
+void UpdateableResultSet::updateBytes( sal_Int32 columnIndex, const css::uno::Sequence< sal_Int8 >& x )
+{
+ MutexGuard guard( m_xMutex->GetMutex() );
+ checkClosed();
+ checkUpdate( columnIndex );
+
+ size_t len;
+ unsigned char * escapedString =
+ PQescapeBytea( reinterpret_cast<unsigned char const *>(x.getConstArray()), x.getLength(), &len);
+ if( ! escapedString )
+ {
+ throw SQLException(
+ "pq_preparedstatement.setBytes: Error during converting bytesequence to an SQL conform string",
+ *this, OUString(), 1, Any() );
+ }
+// buf.append( (const char *)escapedString, len -1 );
+
+ m_updateableField[columnIndex-1].value <<=
+ OUString( reinterpret_cast<char*>(escapedString), len, RTL_TEXTENCODING_ASCII_US );
+ PQfreemem( escapedString );
+}
+
+void UpdateableResultSet::updateDate( sal_Int32 columnIndex, const css::util::Date& x )
+{
+ updateString( columnIndex, DBTypeConversion::toDateString( x ) );
+}
+
+void UpdateableResultSet::updateTime( sal_Int32 columnIndex, const css::util::Time& x )
+{
+ updateString( columnIndex, DBTypeConversion::toTimeString( x ) );
+}
+
+void UpdateableResultSet::updateTimestamp( sal_Int32 columnIndex, const css::util::DateTime& x )
+{
+ updateString( columnIndex, DBTypeConversion::toDateTimeString( x ) );
+}
+
+void UpdateableResultSet::updateBinaryStream( sal_Int32 /* columnIndex */, const css::uno::Reference< css::io::XInputStream >& /* x */, sal_Int32 /* length */ )
+{
+}
+
+void UpdateableResultSet::updateCharacterStream( sal_Int32 /* columnIndex */, const css::uno::Reference< css::io::XInputStream >& /* x */, sal_Int32 /* length */ )
+{
+}
+
+void UpdateableResultSet::updateObject( sal_Int32 /* columnIndex */, const css::uno::Any& /* x */ )
+{
+}
+
+void UpdateableResultSet::updateNumericObject( sal_Int32 /* columnIndex */, const css::uno::Any& /* x */, sal_Int32 /* scale */ )
+{
+}
+
+
+Sequence< Type > UpdateableResultSet::getStaticTypes( bool updateable )
+{
+ if( updateable )
+ {
+ cppu::OTypeCollection collection(
+ cppu::UnoType<XResultSetUpdate>::get(),
+ cppu::UnoType<XRowUpdate>::get(),
+// cppu::UnoType<css::sdbcx::XRowLocate>::get(),
+ getStaticTypes( false /* updateable */ ) );
+ return collection.getTypes();
+ }
+ else
+ {
+ cppu::OTypeCollection collection(
+ cppu::UnoType<XResultSet>::get(),
+ cppu::UnoType<XResultSetMetaDataSupplier>::get(),
+ cppu::UnoType<XRow>::get(),
+ cppu::UnoType<XColumnLocate>::get(),
+ cppu::UnoType<XCloseable>::get(),
+ cppu::UnoType<XPropertySet>::get(),
+ cppu::UnoType<XFastPropertySet>::get(),
+ cppu::UnoType<XMultiPropertySet>::get(),
+ cppu::UnoType<css::lang::XComponent>::get(), // OComponentHelper
+ cppu::UnoType<css::lang::XTypeProvider>::get(),
+ cppu::UnoType<css::uno::XAggregation>::get(),
+ cppu::UnoType<css::uno::XWeak>::get());
+ return collection.getTypes();
+ }
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/postgresql/pq_updateableresultset.hxx b/connectivity/source/drivers/postgresql/pq_updateableresultset.hxx
new file mode 100644
index 0000000000..52cb513a58
--- /dev/null
+++ b/connectivity/source/drivers/postgresql/pq_updateableresultset.hxx
@@ -0,0 +1,170 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * Effective License of whole file:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011:
+ *
+ * The Contents of this file are made available subject to the terms of
+ * the GNU Lesser General Public License Version 2.1
+ *
+ * Copyright: 200? by Sun Microsystems, Inc.
+ *
+ * Contributor(s): Joerg Budischewski
+ *
+ * All parts contributed on or after August 2011:
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ ************************************************************************/
+
+#pragma once
+
+#include "pq_sequenceresultset.hxx"
+#include "pq_resultsetmetadata.hxx"
+
+#include <com/sun/star/sdbc/FetchDirection.hpp>
+#include <com/sun/star/sdbc/ResultSetConcurrency.hpp>
+#include <com/sun/star/sdbc/ResultSetType.hpp>
+#include <com/sun/star/sdbc/XResultSetUpdate.hpp>
+#include <com/sun/star/sdbc/XRowUpdate.hpp>
+#include <utility>
+
+namespace pq_sdbc_driver
+{
+
+struct UpdateableField
+{
+ UpdateableField( )
+ : isTouched(false)
+ {}
+ css::uno::Any value;
+ bool isTouched;
+};
+
+typedef std::vector< UpdateableField > UpdateableFieldVector;
+
+class UpdateableResultSet final :
+ public SequenceResultSet,
+ public css::sdbc::XResultSetUpdate,
+ public css::sdbc::XRowUpdate
+{
+ ConnectionSettings **m_ppSettings;
+ OUString m_schema;
+ OUString m_table;
+ std::vector< OUString > m_primaryKey;
+ UpdateableFieldVector m_updateableField;
+ bool m_insertRow;
+
+private:
+ UpdateableResultSet(
+ const ::rtl::Reference< comphelper::RefCountedMutex > & mutex,
+ const css::uno::Reference< css::uno::XInterface > &owner,
+ std::vector< OUString >&& colNames,
+ std::vector< std::vector< css::uno::Any > >&& data,
+ ConnectionSettings **ppSettings,
+ OUString schema,
+ OUString table,
+ std::vector< OUString >&& primaryKey)
+ : SequenceResultSet( mutex, owner, std::move(colNames), std::move(data), (*ppSettings)->tc ),
+ m_ppSettings( ppSettings ),
+ m_schema(std::move( schema )),
+ m_table(std::move( table )),
+ m_primaryKey( std::move(primaryKey) ),
+ m_insertRow( false )
+ {
+ // LEM TODO: this duplicates code in pq_resultset.cxx, except for different value
+ // of ResultSetConcurrency. Baaad.
+ // Why is an updatable ResultSet a sequenceresultset in the first place?
+ // This seems to imply that the whole data is fetched once and kept in memory. BAAAAD.
+ // LEM TODO: shouldn't these things be inherited from the statement or something like that?
+ // Positioned update/delete not supported, so no cursor name
+ // Fetch direction and size are cursor-specific things, so not used now.
+ // Fetch size not set
+ m_props[ BASERESULTSET_FETCH_DIRECTION ] <<= css::sdbc::FetchDirection::UNKNOWN;
+ // No escape processing for now
+ m_props[ BASERESULTSET_ESCAPE_PROCESSING ] <<= false;
+ // Bookmarks not implemented for now
+ m_props[ BASERESULTSET_IS_BOOKMARKABLE ] <<= false;
+ m_props[ BASERESULTSET_RESULT_SET_CONCURRENCY ] <<=
+ css::sdbc::ResultSetConcurrency::UPDATABLE;
+ m_props[ BASERESULTSET_RESULT_SET_TYPE ] <<=
+ css::sdbc::ResultSetType::SCROLL_INSENSITIVE;
+ }
+
+ OUString buildWhereClause();
+ void checkUpdate( sal_Int32 column );
+
+public:
+ static css::uno::Reference< css::sdbc::XCloseable > createFromPGResultSet(
+ const ::rtl::Reference< comphelper::RefCountedMutex > & mutex,
+ const css::uno::Reference< css::uno::XInterface > &owner,
+ ConnectionSettings **ppSettings,
+ PGresult *result,
+ const OUString &schema,
+ const OUString &table,
+ std::vector< OUString > && primaryKey );
+
+public: // XInterface
+ virtual void SAL_CALL acquire() noexcept override { SequenceResultSet::acquire(); }
+ virtual void SAL_CALL release() noexcept override { SequenceResultSet::release(); }
+ virtual css::uno::Any SAL_CALL queryInterface(
+ const css::uno::Type & reqType ) override;
+
+public: // XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override;
+ virtual css::uno::Sequence< sal_Int8> SAL_CALL getImplementationId() override;
+
+public: // XResultSetUpdate
+ virtual void SAL_CALL insertRow( ) override;
+ virtual void SAL_CALL updateRow( ) override;
+ virtual void SAL_CALL deleteRow( ) override;
+ virtual void SAL_CALL cancelRowUpdates( ) override;
+ virtual void SAL_CALL moveToInsertRow( ) override;
+ virtual void SAL_CALL moveToCurrentRow( ) override;
+
+public: // XRowUpdate
+ virtual void SAL_CALL updateNull( sal_Int32 columnIndex ) override;
+ virtual void SAL_CALL updateBoolean( sal_Int32 columnIndex, sal_Bool x ) override;
+ virtual void SAL_CALL updateByte( sal_Int32 columnIndex, sal_Int8 x ) override;
+ virtual void SAL_CALL updateShort( sal_Int32 columnIndex, sal_Int16 x ) override;
+ virtual void SAL_CALL updateInt( sal_Int32 columnIndex, sal_Int32 x ) override;
+ virtual void SAL_CALL updateLong( sal_Int32 columnIndex, sal_Int64 x ) override;
+ virtual void SAL_CALL updateFloat( sal_Int32 columnIndex, float x ) override;
+ virtual void SAL_CALL updateDouble( sal_Int32 columnIndex, double x ) override;
+ virtual void SAL_CALL updateString( sal_Int32 columnIndex, const OUString& x ) override;
+ virtual void SAL_CALL updateBytes( sal_Int32 columnIndex, const css::uno::Sequence< sal_Int8 >& x ) override;
+ virtual void SAL_CALL updateDate( sal_Int32 columnIndex, const css::util::Date& x ) override;
+ virtual void SAL_CALL updateTime( sal_Int32 columnIndex, const css::util::Time& x ) override;
+ virtual void SAL_CALL updateTimestamp( sal_Int32 columnIndex, const css::util::DateTime& x ) override;
+ virtual void SAL_CALL updateBinaryStream( sal_Int32 columnIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override;
+ virtual void SAL_CALL updateCharacterStream( sal_Int32 columnIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override;
+ virtual void SAL_CALL updateObject( sal_Int32 columnIndex, const css::uno::Any& x ) override;
+ virtual void SAL_CALL updateNumericObject( sal_Int32 columnIndex, const css::uno::Any& x, sal_Int32 scale ) override;
+
+public:
+ /// @throws css::uno::RuntimeException
+ static css::uno::Sequence< css::uno::Type > getStaticTypes( bool updateable );
+
+};
+
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/postgresql/pq_xbase.cxx b/connectivity/source/drivers/postgresql/pq_xbase.cxx
new file mode 100644
index 0000000000..001046aa52
--- /dev/null
+++ b/connectivity/source/drivers/postgresql/pq_xbase.cxx
@@ -0,0 +1,216 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * Effective License of whole file:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011:
+ *
+ * The Contents of this file are made available subject to the terms of
+ * the GNU Lesser General Public License Version 2.1
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * Contributor(s): Joerg Budischewski
+ *
+ * All parts contributed on or after August 2011:
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ ************************************************************************/
+
+#include <cppuhelper/supportsservice.hxx>
+#include <comphelper/sequence.hxx>
+#include <utility>
+
+#include "pq_statics.hxx"
+#include "pq_tools.hxx"
+#include "pq_xbase.hxx"
+
+using osl::MutexGuard;
+
+using com::sun::star::uno::Any;
+using com::sun::star::uno::Sequence;
+using com::sun::star::uno::Reference;
+using com::sun::star::uno::RuntimeException;
+
+using com::sun::star::beans::Property;
+using com::sun::star::beans::XPropertySetInfo;
+using com::sun::star::beans::XPropertySet;
+
+namespace pq_sdbc_driver
+{
+
+ReflectionBase::ReflectionBase(
+ OUString implName,
+ const css::uno::Sequence< OUString > &supportedServices,
+ const ::rtl::Reference< comphelper::RefCountedMutex >& refMutex,
+ css::uno::Reference< css::sdbc::XConnection > conn,
+ ConnectionSettings *pSettings,
+ cppu::IPropertyArrayHelper & props /* must survive this object !*/ )
+ : ReflectionBase_BASE( refMutex->GetMutex() ),
+ OPropertySetHelper( ReflectionBase_BASE::rBHelper ),
+ m_implName(std::move( implName )),
+ m_supportedServices( supportedServices ),
+ m_xMutex( refMutex ),
+ m_conn(std::move( conn )),
+ m_pSettings( pSettings ),
+ m_propsDesc( props ),
+ m_values( props.getProperties().getLength() )
+{}
+
+cppu::IPropertyArrayHelper & ReflectionBase::getInfoHelper()
+{
+ return m_propsDesc;
+}
+
+sal_Bool ReflectionBase::convertFastPropertyValue(
+ css::uno::Any & rConvertedValue,
+ css::uno::Any & rOldValue,
+ sal_Int32 nHandle,
+ const css::uno::Any& rValue )
+{
+
+ rOldValue = m_values[nHandle];
+ rConvertedValue = rValue; // TODO !!! implement correct conversion !
+ m_values[nHandle] = rValue;
+ return true;
+}
+
+void ReflectionBase::setPropertyValue_NoBroadcast_public(
+ const OUString & name, const css::uno::Any & value )
+{
+ sal_Int32 nHandle = m_propsDesc.getHandleByName( name );
+ if( -1 == nHandle )
+ {
+ throw css::uno::RuntimeException(
+ "Unknown property '" + name + "' in " + m_implName,
+ *this );
+ }
+ setFastPropertyValue_NoBroadcast( nHandle , value );
+}
+
+void ReflectionBase::setFastPropertyValue_NoBroadcast(
+ sal_Int32 nHandle,
+ const css::uno::Any& rValue )
+{
+// OUString s;
+// rValue >>= s;
+// printf( "setting value (handle %d):%s\n" ,
+// nHandle, OUStringToOString(s, RTL_TEXTENCODING_ASCII_US).getStr() );
+ m_values[nHandle] = rValue;
+}
+
+void ReflectionBase::getFastPropertyValue(
+ css::uno::Any& rValue,
+ sal_Int32 nHandle ) const
+{
+ rValue = m_values[nHandle];
+// OUString s;
+// rValue >>= s;
+// printf( "getting value (handle %d):%s\n" ,
+// nHandle, OUStringToOString(s, RTL_TEXTENCODING_ASCII_US).getStr() );
+
+}
+
+Reference < css::beans::XPropertySetInfo > ReflectionBase::getPropertySetInfo()
+{
+ return OPropertySetHelper::createPropertySetInfo( m_propsDesc );
+}
+
+OUString ReflectionBase::getImplementationName()
+{
+ return m_implName;
+}
+
+sal_Bool ReflectionBase::supportsService(const OUString& ServiceName)
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+Sequence< OUString > ReflectionBase::getSupportedServiceNames()
+{
+ return m_supportedServices;
+}
+
+
+Sequence< css::uno::Type > ReflectionBase::getTypes()
+{
+ osl::MutexGuard guard( m_xMutex->GetMutex() );
+ static Sequence< css::uno::Type > collection(
+ ::comphelper::concatSequences(
+ ::cppu::OPropertySetHelper::getTypes(),
+ ReflectionBase_BASE::getTypes() ) );
+ return collection;
+}
+
+
+css::uno::Any ReflectionBase::queryInterface(
+ const css::uno::Type & reqType )
+{
+ Any ret = ReflectionBase_BASE::queryInterface( reqType );
+ return ret.hasValue() ? ret : OPropertySetHelper::queryInterface( reqType );
+
+}
+
+Sequence< sal_Int8> ReflectionBase::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+void ReflectionBase::copyValuesFrom( const Reference< XPropertySet > & set )
+{
+ Reference< XPropertySetInfo > info = set->getPropertySetInfo();
+ if( info.is () )
+ {
+ Reference< XPropertySetInfo > myPropInfo = getPropertySetInfo();
+
+ const Sequence< Property > props = info->getProperties();
+ for( Property const & prop : props )
+ {
+ if( myPropInfo->hasPropertyByName( prop.Name ) )
+ setPropertyValue_NoBroadcast_public(
+ prop.Name, set->getPropertyValue( prop.Name ) );
+ }
+ }
+}
+
+OUString ReflectionBase::getName( )
+{
+ Statics & st = getStatics();
+ if( getInfoHelper().hasPropertyByName( st.SCHEMA_NAME ) )
+ return concatQualified(
+ extractStringProperty( this, getStatics().SCHEMA_NAME ),
+ extractStringProperty( this, getStatics().NAME ) );
+ else
+ return extractStringProperty( this, getStatics().NAME );
+}
+
+
+void ReflectionBase::setName( const OUString& /* aName */ )
+{
+ throw RuntimeException(
+ "pq_sdbc::ReflectionBase::setName not implemented",
+ *this );
+ //setPropertyValue( getStatics().NAME , makeAny( aName ) );
+}
+
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/postgresql/pq_xbase.hxx b/connectivity/source/drivers/postgresql/pq_xbase.hxx
new file mode 100644
index 0000000000..e4ca16fd5e
--- /dev/null
+++ b/connectivity/source/drivers/postgresql/pq_xbase.hxx
@@ -0,0 +1,131 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * Effective License of whole file:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011:
+ *
+ * The Contents of this file are made available subject to the terms of
+ * the GNU Lesser General Public License Version 2.1
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * Contributor(s): Joerg Budischewski
+ *
+ * All parts contributed on or after August 2011:
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ ************************************************************************/
+
+#pragma once
+#include <cppuhelper/propshlp.hxx>
+#include <cppuhelper/compbase.hxx>
+
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/container/XNamed.hpp>
+
+#include "pq_xcontainer.hxx"
+
+namespace pq_sdbc_driver
+{
+
+typedef ::cppu::WeakComponentImplHelper< css::lang::XServiceInfo,
+ css::sdbcx::XDataDescriptorFactory,
+ css::container::XNamed
+ > ReflectionBase_BASE;
+
+class ReflectionBase :
+ public ReflectionBase_BASE,
+ public cppu::OPropertySetHelper
+{
+protected:
+ const OUString m_implName;
+ const css::uno::Sequence< OUString > m_supportedServices;
+ ::rtl::Reference< comphelper::RefCountedMutex > m_xMutex;
+ css::uno::Reference< css::sdbc::XConnection > m_conn;
+ ConnectionSettings *m_pSettings;
+ cppu::IPropertyArrayHelper & m_propsDesc;
+ std::vector< css::uno::Any > m_values;
+public:
+ ReflectionBase(
+ OUString implName,
+ const css::uno::Sequence< OUString > &supportedServices,
+ const ::rtl::Reference< comphelper::RefCountedMutex >& refMutex,
+ css::uno::Reference< css::sdbc::XConnection > conn,
+ ConnectionSettings *pSettings,
+ cppu::IPropertyArrayHelper & props /* must survive this object !*/ );
+
+public:
+ void copyValuesFrom( const css::uno::Reference< css::beans::XPropertySet > &set );
+
+public: // for initialization purposes only, not exported via an interface !
+ void setPropertyValue_NoBroadcast_public(
+ const OUString & name, const css::uno::Any & value );
+
+public: //XInterface
+ virtual void SAL_CALL acquire() noexcept override { ReflectionBase_BASE::acquire(); }
+ virtual void SAL_CALL release() noexcept override { ReflectionBase_BASE::release(); }
+ virtual css::uno::Any SAL_CALL queryInterface(
+ const css::uno::Type & reqType ) override;
+
+public: // OPropertySetHelper
+ virtual cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override;
+
+ virtual sal_Bool SAL_CALL convertFastPropertyValue(
+ css::uno::Any & rConvertedValue,
+ css::uno::Any & rOldValue,
+ sal_Int32 nHandle,
+ const css::uno::Any& rValue ) override;
+
+ virtual void SAL_CALL setFastPropertyValue_NoBroadcast(
+ sal_Int32 nHandle,
+ const css::uno::Any& rValue ) override;
+
+ using ::cppu::OPropertySetHelper::getFastPropertyValue;
+
+ void SAL_CALL getFastPropertyValue(
+ css::uno::Any& rValue,
+ sal_Int32 nHandle ) const override;
+
+ // XPropertySet
+ css::uno::Reference < css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo() override;
+
+public: // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+public: // XTypeProvider, first implemented by OPropertySetHelper
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override;
+ virtual css::uno::Sequence< sal_Int8> SAL_CALL getImplementationId() override;
+
+public: // XDataDescriptorFactory
+ virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL
+ createDataDescriptor( ) override = 0;
+
+public: // XNamed
+ virtual OUString SAL_CALL getName( ) override;
+ virtual void SAL_CALL setName( const OUString& aName ) override;
+
+};
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/postgresql/pq_xcolumn.cxx b/connectivity/source/drivers/postgresql/pq_xcolumn.cxx
new file mode 100644
index 0000000000..b19d95c3c9
--- /dev/null
+++ b/connectivity/source/drivers/postgresql/pq_xcolumn.cxx
@@ -0,0 +1,95 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * Effective License of whole file:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011:
+ *
+ * The Contents of this file are made available subject to the terms of
+ * the GNU Lesser General Public License Version 2.1
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * Contributor(s): Joerg Budischewski
+ *
+ * All parts contributed on or after August 2011:
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ ************************************************************************/
+
+#include <sal/config.h>
+
+#include <rtl/ref.hxx>
+
+#include "pq_statics.hxx"
+#include "pq_xcolumn.hxx"
+
+using com::sun::star::uno::Reference;
+
+using com::sun::star::beans::XPropertySet;
+
+namespace pq_sdbc_driver
+{
+Column::Column( const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex,
+ const Reference< css::sdbc::XConnection > & connection,
+ ConnectionSettings *pSettings)
+ : ReflectionBase(
+ getStatics().refl.column.implName,
+ getStatics().refl.column.serviceNames,
+ refMutex,
+ connection,
+ pSettings,
+ * getStatics().refl.column.pProps )
+{}
+
+Reference< XPropertySet > Column::createDataDescriptor( )
+{
+ rtl::Reference<ColumnDescriptor> pColumn = new ColumnDescriptor(
+ m_xMutex, m_conn, m_pSettings );
+ pColumn->copyValuesFrom( this );
+ return Reference< XPropertySet > ( pColumn );
+}
+
+ColumnDescriptor::ColumnDescriptor(
+ const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex,
+ const Reference< css::sdbc::XConnection > & connection,
+ ConnectionSettings *pSettings)
+ : ReflectionBase(
+ getStatics().refl.columnDescriptor.implName,
+ getStatics().refl.columnDescriptor.serviceNames,
+ refMutex,
+ connection,
+ pSettings,
+ *getStatics().refl.columnDescriptor.pProps )
+{}
+
+Reference< XPropertySet > ColumnDescriptor::createDataDescriptor( )
+{
+ rtl::Reference<ColumnDescriptor> pColumn = new ColumnDescriptor(
+ m_xMutex, m_conn, m_pSettings );
+ pColumn->copyValuesFrom( this );
+
+ return Reference< XPropertySet > ( pColumn );
+}
+
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/postgresql/pq_xcolumn.hxx b/connectivity/source/drivers/postgresql/pq_xcolumn.hxx
new file mode 100644
index 0000000000..794b5851d3
--- /dev/null
+++ b/connectivity/source/drivers/postgresql/pq_xcolumn.hxx
@@ -0,0 +1,82 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * Effective License of whole file:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011:
+ *
+ * The Contents of this file are made available subject to the terms of
+ * the GNU Lesser General Public License Version 2.1
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * Contributor(s): Joerg Budischewski
+ *
+ * All parts contributed on or after August 2011:
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ ************************************************************************/
+
+#pragma once
+
+#include <cppuhelper/component.hxx>
+#include <cppuhelper/propshlp.hxx>
+
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/sdbcx/XDataDescriptorFactory.hpp>
+
+#include "pq_connection.hxx"
+#include "pq_xbase.hxx"
+
+namespace pq_sdbc_driver
+{
+
+class Column : public ReflectionBase
+{
+public:
+ Column( const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex,
+ const css::uno::Reference< css::sdbc::XConnection > & connection,
+ ConnectionSettings *pSettings);
+
+public: // XDataDescriptorFactory
+ virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL
+ createDataDescriptor( ) override;
+
+};
+
+class ColumnDescriptor : public ReflectionBase
+{
+public:
+ ColumnDescriptor(
+ const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex,
+ const css::uno::Reference< css::sdbc::XConnection > & connection,
+ ConnectionSettings *pSettings );
+
+public: // XDataDescriptorFactory
+ virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL
+ createDataDescriptor( ) override;
+
+};
+
+
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/postgresql/pq_xcolumns.cxx b/connectivity/source/drivers/postgresql/pq_xcolumns.cxx
new file mode 100644
index 0000000000..b72d569d22
--- /dev/null
+++ b/connectivity/source/drivers/postgresql/pq_xcolumns.cxx
@@ -0,0 +1,560 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * Effective License of whole file:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011:
+ *
+ * The Contents of this file are made available subject to the terms of
+ * the GNU Lesser General Public License Version 2.1
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * Contributor(s): Joerg Budischewski
+ *
+ * All parts contributed on or after August 2011:
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ ************************************************************************/
+
+#include <sal/config.h>
+
+#include <string_view>
+
+#include <o3tl/safeint.hxx>
+#include <o3tl/string_view.hxx>
+#include <rtl/ref.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <sal/log.hxx>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/ColumnValue.hpp>
+
+#include <cppuhelper/exc_hlp.hxx>
+#include <utility>
+
+#include "pq_xcolumns.hxx"
+#include "pq_xcolumn.hxx"
+#include "pq_statics.hxx"
+#include "pq_tools.hxx"
+
+using osl::MutexGuard;
+
+
+using com::sun::star::beans::XPropertySet;
+
+using com::sun::star::uno::Any;
+using com::sun::star::uno::UNO_QUERY;
+using com::sun::star::uno::Reference;
+using com::sun::star::uno::RuntimeException;
+
+using com::sun::star::sdbc::XRow;
+using com::sun::star::sdbc::XStatement;
+using com::sun::star::sdbc::XResultSet;
+using com::sun::star::sdbc::XDatabaseMetaData;
+using com::sun::star::sdbc::SQLException;
+
+namespace pq_sdbc_driver
+{
+
+static Any isCurrency( std::u16string_view typeName )
+{
+ return Any( o3tl::equalsIgnoreAsciiCase(typeName, u"money") );
+}
+
+// static sal_Bool isAutoIncrement8( const OUString & typeName )
+// {
+// return typeName.equalsIgnoreAsciiCase("serial8") ||
+// typeName.equalsIgnoreAsciiCase("bigserial");
+// }
+
+static Any isAutoIncrement( std::u16string_view defaultValue )
+{
+ bool ret = o3tl::starts_with( defaultValue, u"nextval(" );
+// printf( "%s %d\n",
+// OUStringToOString(defaultValue, RTL_TEXTENCODING_ASCII_US).getStr(),
+// ret );
+// {
+// static const char * const serials[] =
+// {
+// "serial", "serial4", "serial8", "bigserial", 0
+// };
+// s sal_Bool b = sal_False;
+// for( int i = 0; !b && serials[i] ; i ++ )
+// {
+// b = b || typeName.equalsIgnoreAsciiCaseAscii( serials[i] );
+// }
+ return Any ( ret );
+}
+
+Columns::Columns(
+ const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex,
+ const css::uno::Reference< css::sdbc::XConnection > & origin,
+ ConnectionSettings *pSettings,
+ OUString schemaName,
+ OUString tableName)
+ : Container( refMutex, origin, pSettings, "COLUMN" ),
+ m_schemaName(std::move( schemaName )),
+ m_tableName(std::move( tableName ))
+{}
+
+Columns::~Columns()
+{}
+
+OUString columnMetaData2SDBCX(
+ ReflectionBase *pBase, const css::uno::Reference< css::sdbc::XRow > &xRow )
+{
+ Statics & st = getStatics();
+
+ // 1. TABLE_CAT string => table catalog (may be NULL)
+ // => not supported
+ // 2. TABLE_SCHEM string => table schema (may be NULL)
+ // => pg_namespace.nspname
+ // 3. TABLE_NAME string => table name
+ // => pg_class.relname
+ // 4. COLUMN_NAME string => column name
+ // => pg_attribute.attname
+ // 5. DATA_TYPE short => SQL type from java.sql.Types
+ // => pg_type.typname => sdbc.DataType
+ // 6. TYPE_NAME string => Data source dependent type name, for a UDT the
+ // type name is fully qualified
+ // => pg_type.typname
+ // 7. COLUMN_SIZE long => column size. For char or date types this is
+ // the maximum number of characters, for numeric
+ // or decimal types this is precision.
+ // => pg_type.typlen ( TODO: What is about variable size ? )
+ // 8. BUFFER_LENGTH is not used.
+ // => not used
+ // 9. DECIMAL_DIGITS long => the number of fractional digits
+ // => don't know ! TODO !
+ // 10. NUM_PREC_RADIX long => Radix (typically either 10 or 2)
+ // => TODO ??
+ // 11. NULLABLE long => is NULL allowed?
+ // NO_NULLS - might not allow NULL values
+ // NULABLE - definitely allows NULL values
+ // NULLABLE_UNKNOWN - nullability unknown
+ // => pg_attribute.attnotnull
+ // 12. REMARKS string => comment describing column (may be NULL )
+ // => Don't know, there does not seem to exist something like
+ // that in postgres
+ // 13. COLUMN_DEF string => default value (may be NULL)
+ // => pg_type.typdefault
+ // 14. SQL_DATA_TYPE long => unused
+ // => empty
+ // 15. SQL_DATETIME_SUB long => unused
+ // => empty
+ // 16. CHAR_OCTET_LENGTH long => for char types the maximum number of
+ // bytes in the column
+ // => pg_type.typlen
+ // 17. ORDINAL_POSITION int => index of column in table (starting at 1)
+ // pg_attribute.attnum
+ // 18. IS_NULLABLE string => "NO" means column definitely does not allow
+ // NULL values; "YES" means the column might
+ // allow NULL values. An empty string means
+ // nobody knows.
+ // => pg_attribute.attnotnull
+
+ static const int COLUMN_NAME = 4;
+ static const int DATA_TYPE = 5;
+ static const int TYPE_NAME = 6;
+ static const int COLUMN_SIZE = 7;
+ static const int DECIMAL_DIGITS = 9;
+ static const int IS_NULLABLE = 11;
+ static const int DESCRIPTION = 12;
+ static const int DEFAULT_VALUE = 13;
+
+ OUString name = xRow->getString( COLUMN_NAME );
+ OUString typeName = xRow->getString( TYPE_NAME );
+
+ pBase->setPropertyValue_NoBroadcast_public(
+ st.NAME, Any( name ) );
+
+ pBase->setPropertyValue_NoBroadcast_public(
+ st.TYPE, Any( xRow->getInt( DATA_TYPE ) ) );
+
+ pBase->setPropertyValue_NoBroadcast_public(
+ st.TYPE_NAME, Any( typeName ) );
+
+ pBase->setPropertyValue_NoBroadcast_public(
+ st.PRECISION, Any( xRow->getInt( COLUMN_SIZE ) ) );
+
+ pBase->setPropertyValue_NoBroadcast_public(
+ st.SCALE, Any( xRow->getInt( DECIMAL_DIGITS ) ) );
+
+ pBase->setPropertyValue_NoBroadcast_public(
+ st.IS_NULLABLE, Any( xRow->getInt( IS_NULLABLE ) ) );
+
+ pBase->setPropertyValue_NoBroadcast_public(
+ st.DEFAULT_VALUE, Any( xRow->getString( DEFAULT_VALUE ) ) );
+
+// pBase->setPropertyValue_NoBroadcast_public(
+// st.DESCRIPTION, makeAny( xRow->getString( DESCRIPTION ) ) );
+
+// if( pBase->getPropertySetInfo()->hasPropertyByName( st.HELP_TEXT ) )
+// pBase->setPropertyValue_NoBroadcast_public(
+// st.HELP_TEXT, makeAny( xRow->getString( DESCRIPTION ) ) );
+// else // for key columns, etc. ...
+ pBase->setPropertyValue_NoBroadcast_public(
+ st.DESCRIPTION, Any( xRow->getString( DESCRIPTION ) ) );
+
+
+ // maybe a better criterion than the type name can be found in future
+ pBase->setPropertyValue_NoBroadcast_public(
+ st.IS_AUTO_INCREMENT, isAutoIncrement(xRow->getString( DEFAULT_VALUE )) );
+
+ pBase->setPropertyValue_NoBroadcast_public(
+ st.IS_CURRENCY, isCurrency( typeName));
+ return name;
+}
+
+
+// class CommentChanger : public cppu::WeakImplHelper< XPropertyChangeListener >
+// {
+// ::rtl::Reference< comphelper::RefCountedMutex > m_xMutex;
+// css::uno::Reference< css::sdbc::XConnection > m_connection;
+// ConnectionSettings *m_pSettings;
+// OUString m_schema;
+// OUString m_table;
+// OUString m_column;
+
+// public:
+// CommentChanger(
+// const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex,
+// const css::uno::Reference< css::sdbc::XConnection > & connection,
+// ConnectionSettings *pSettings,
+// const OUString & schema,
+// const OUString & table,
+// const OUString & column ) :
+// m_xMutex( refMutex ),
+// m_connection( connection ),
+// m_pSettings( pSettings ),
+// m_schema ( schema ),
+// m_table ( table ),
+// m_column ( column )
+// {}
+
+
+// // Methods
+// virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) throw (css::uno::RuntimeException)
+// {
+// osl::MutexGuard guard( m_xMutex->GetMutex() );
+// m_connection.clear();
+// }
+// // Methods
+// virtual void SAL_CALL propertyChange( const css::beans::PropertyChangeEvent& evt ) throw (css::uno::RuntimeException)
+// {
+// osl::MutexGuard guard( m_xMutex->GetMutex() );
+// OUStringBuffer buf( 128 );
+// OUString comment;
+// evt.NewValue >>= comment;
+// buf.append( "COMMENT ON COLUMN" );
+// bufferQuoteQualifiedIdentifier( buf, m_schema, m_table , m_column );
+// buf.append( "IS " );
+// bufferQuoteConstant( buf, comment,m_pSettings->encoding);
+
+// printf( "changing comment of column %s to %s\n",
+// OUStringToOString( m_column, RTL_TEXTENCODING_ASCII_US ).getStr(),
+// OUStringToOString( comment, RTL_TEXTENCODING_ASCII_US ).getStr() );
+
+// m_connection->createStatement()->executeUpdate( buf.makeStringAndClear() );
+// }
+// };
+
+void Columns::refresh()
+{
+ try
+ {
+ SAL_INFO("connectivity.postgresql", "sdbcx.Columns get refreshed for table " << m_schemaName << "." << m_tableName);
+ osl::MutexGuard guard( m_xMutex->GetMutex() );
+
+ Statics &st = getStatics();
+ Reference< XDatabaseMetaData > meta = m_origin->getMetaData();
+
+ Reference< XResultSet > rs =
+ meta->getColumns( Any(), m_schemaName, m_tableName, st.cPERCENT );
+
+ DisposeGuard disposeIt( rs );
+ Reference< XRow > xRow( rs , UNO_QUERY );
+
+ String2IntMap map;
+
+ m_values.clear();
+ int columnIndex = 0;
+ while( rs->next() )
+ {
+ rtl::Reference<Column> pColumn =
+ new Column( m_xMutex, m_origin, m_pSettings );
+ Reference< css::beans::XPropertySet > prop = pColumn;
+
+ OUString name = columnMetaData2SDBCX( pColumn.get(), xRow );
+// pColumn->addPropertyChangeListener(
+// st.HELP_TEXT,
+// new CommentChanger(
+// m_xMutex,
+// m_origin,
+// m_pSettings,
+// m_schemaName,
+// m_tableName,
+// name ) );
+
+ {
+ m_values.push_back( Any( prop ) );
+ map[ name ] = columnIndex;
+ ++columnIndex;
+ }
+ }
+ m_name2index.swap( map );
+ }
+ catch ( css::sdbc::SQLException & e )
+ {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ throw css::lang::WrappedTargetRuntimeException( e.Message,
+ nullptr, anyEx );
+ }
+ fire( RefreshedBroadcaster( *this ) );
+}
+
+
+void alterColumnByDescriptor(
+ std::u16string_view schemaName,
+ std::u16string_view tableName,
+ ConnectionSettings *settings,
+ const Reference< XStatement > &stmt,
+ const css::uno::Reference< css::beans::XPropertySet > & past,
+ const css::uno::Reference< css::beans::XPropertySet > & future)
+{
+ Statics & st = getStatics();
+
+// if( past->getPropertyValue( st.TABLE_NAME ) != future->getPropertyValue( st.TABLE_NAME ) ||
+// past->getPropertyValue( st.SCHEMA_NAME ) != future->getPropertyValue( st.SCHEMA_NAME ))
+// {
+// OUStringBuffer buf(128);
+// buf.append( "Can't move column " );
+// buf.append( extractStringProperty( past, st.COLUMN_NAME ) );
+// buf.append( " from table " );
+// buf.append( extractStringProperty( past, st.TABLE_NAME ) );
+// buf.append( " to table " );
+// buf.append( extractStringProperty( past, st.TABLE_NAME ) );
+// throw SQLException( buf.makeStringAndClear() );
+// }
+
+// OUString tableName = extractStringProperty( past, st.TABLE_NAME );
+// OUString schemaName = extractStringProperty( past, st.SCHEMA_NAME );
+ OUString pastColumnName = extractStringProperty( past, st.NAME );
+ OUString futureColumnName = extractStringProperty( future, st.NAME );
+ OUString pastTypeName = sqltype2string( past );
+ OUString futureTypeName = sqltype2string( future );
+
+ TransactionGuard transaction( stmt );
+
+ OUStringBuffer buf( 128 );
+ if( ! pastColumnName.getLength())
+ {
+ // create a new column
+ buf.append( "ALTER TABLE" );
+ bufferQuoteQualifiedIdentifier( buf, schemaName, tableName, settings );
+ buf.append( "ADD COLUMN" );
+ bufferQuoteIdentifier( buf, futureColumnName, settings );
+ buf.append( futureTypeName );
+ transaction.executeUpdate( buf.makeStringAndClear() );
+ }
+ else
+ {
+ if( pastTypeName != futureTypeName )
+ {
+ throw RuntimeException(
+ "Can't modify column types, drop the column and create a new one" );
+ }
+
+ if( pastColumnName != futureColumnName )
+ {
+ buf.append( "ALTER TABLE" );
+ bufferQuoteQualifiedIdentifier( buf, schemaName, tableName, settings );
+ buf.append( "RENAME COLUMN" );
+ bufferQuoteIdentifier( buf, pastColumnName, settings );
+ buf.append( "TO" );
+ bufferQuoteIdentifier( buf, futureColumnName, settings );
+ transaction.executeUpdate( buf.makeStringAndClear() );
+ }
+ }
+
+ OUString futureDefaultValue = extractStringProperty( future, st.DEFAULT_VALUE );
+ OUString pastDefaultValue = extractStringProperty( past, st.DEFAULT_VALUE );
+ if( futureDefaultValue != pastDefaultValue )
+ {
+ buf.truncate();
+ buf.append( "ALTER TABLE" );
+ bufferQuoteQualifiedIdentifier( buf, schemaName, tableName, settings );
+ buf.append( "ALTER COLUMN" );
+ bufferQuoteIdentifier( buf, futureColumnName, settings );
+ // LEM TODO: check out
+ // default value is not quoted, caller needs to quote himself (otherwise
+ // how to pass e.g. nextval('something' ) ????
+ buf.append( "SET DEFAULT " + futureDefaultValue );
+// bufferQuoteConstant( buf, defaultValue, encoding );
+ transaction.executeUpdate( buf.makeStringAndClear() );
+ }
+
+ sal_Int32 futureNullable = extractIntProperty( future, st.IS_NULLABLE );
+ sal_Int32 pastNullable = extractIntProperty( past, st.IS_NULLABLE );
+ if( futureNullable != pastNullable )
+ {
+ buf.truncate();
+ buf.append( "ALTER TABLE" );
+ bufferQuoteQualifiedIdentifier( buf, schemaName, tableName, settings );
+ buf.append( "ALTER COLUMN" );
+ bufferQuoteIdentifier( buf, futureColumnName, settings );
+ if( futureNullable == css::sdbc::ColumnValue::NO_NULLS )
+ {
+ buf.append( "SET" );
+ }
+ else
+ {
+ buf.append( "DROP" );
+ }
+ buf.append( " NOT NULL" );
+ transaction.executeUpdate( buf.makeStringAndClear() );
+ }
+
+// OUString futureComment = extractStringProperty( future, st.HELP_TEXT );
+// OUString pastComment = extractStringProperty( past, st.HELP_TEXT );
+// printf( "past Comment %s, futureComment %s\n",
+// OUStringToOString( pastComment, RTL_TEXTENCODING_ASCII_US ).getStr(),
+// OUStringToOString( futureComment, RTL_TEXTENCODING_ASCII_US ).getStr() );
+ OUString futureComment = extractStringProperty( future, st.DESCRIPTION );
+ OUString pastComment = extractStringProperty( past, st.DESCRIPTION );
+
+ if( futureComment != pastComment )
+ {
+ buf.truncate();
+ buf.append( "COMMENT ON COLUMN" );
+ bufferQuoteQualifiedIdentifier( buf, schemaName, tableName , futureColumnName, settings );
+ buf.append( "IS " );
+ bufferQuoteConstant( buf, futureComment, settings );
+ transaction.executeUpdate( buf.makeStringAndClear() );
+ }
+ transaction.commit();
+}
+
+void Columns::appendByDescriptor(
+ const css::uno::Reference< css::beans::XPropertySet >& future )
+{
+ osl::MutexGuard guard( m_xMutex->GetMutex() );
+ Statics & st = getStatics();
+ Reference< XPropertySet > past = createDataDescriptor();
+ past->setPropertyValue( st.IS_NULLABLE, Any( css::sdbc::ColumnValue::NULLABLE ) );
+ alterColumnByDescriptor(
+ m_schemaName, m_tableName, m_pSettings, m_origin->createStatement() , past, future );
+
+ refresh();
+}
+
+// void Columns::dropByName( const OUString& elementName )
+// throw (css::sdbc::SQLException,
+// css::container::NoSuchElementException,
+// css::uno::RuntimeException)
+// {
+// String2IntMap::const_iterator ii = m_name2index.find( elementName );
+// if( ii == m_name2index.end() )
+// {
+// OUStringBuffer buf( 128 );
+// buf.appendAscii( "Column " );
+// buf.append( elementName );
+// buf.appendAscii( " is unknown in table " );
+// buf.append( m_schemaName );
+// buf.appendAscii( "." );
+// buf.append( m_tableName );
+// buf.appendAscii( ", so it can't be dropped" );
+// throw css::container::NoSuchElementException(
+// buf.makeStringAndClear(), *this );
+// }
+// dropByIndex( ii->second );
+// }
+
+void Columns::dropByIndex( sal_Int32 index )
+{
+ osl::MutexGuard guard( m_xMutex->GetMutex() );
+ if( index < 0 || o3tl::make_unsigned(index) >= m_values.size() )
+ {
+ throw css::lang::IndexOutOfBoundsException(
+ "COLUMNS: Index out of range (allowed 0 to "
+ + OUString::number(m_values.size() -1)
+ + ", got " + OUString::number( index ) + ")",
+ *this );
+ }
+
+ Reference< XPropertySet > set;
+ m_values[index] >>= set;
+ Statics &st = getStatics();
+ OUString name;
+ set->getPropertyValue( st.NAME ) >>= name;
+
+ OUStringBuffer update( 128 );
+ update.append( "ALTER TABLE ONLY");
+ bufferQuoteQualifiedIdentifier( update, m_schemaName, m_tableName, m_pSettings );
+ update.append( "DROP COLUMN" );
+ bufferQuoteIdentifier( update, name, m_pSettings );
+ Reference< XStatement > stmt = m_origin->createStatement( );
+ DisposeGuard disposeIt( stmt );
+ stmt->executeUpdate( update.makeStringAndClear() );
+
+ Container::dropByIndex( index );
+}
+
+
+css::uno::Reference< css::beans::XPropertySet > Columns::createDataDescriptor()
+{
+ return new ColumnDescriptor( m_xMutex, m_origin, m_pSettings );
+}
+
+Reference< css::container::XNameAccess > Columns::create(
+ const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex,
+ const css::uno::Reference< css::sdbc::XConnection > & origin,
+ ConnectionSettings *pSettings,
+ const OUString &schemaName,
+ const OUString &tableName,
+ rtl::Reference<Columns> *ppColumns)
+{
+ *ppColumns = new Columns(
+ refMutex, origin, pSettings, schemaName, tableName );
+ (*ppColumns)->refresh();
+
+ return *ppColumns;
+}
+
+
+ColumnDescriptors::ColumnDescriptors(
+ const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex,
+ const css::uno::Reference< css::sdbc::XConnection > & origin,
+ ConnectionSettings *pSettings )
+ : Container( refMutex, origin, pSettings, "COLUMN-DESCRIPTOR" )
+{}
+
+
+Reference< css::beans::XPropertySet > ColumnDescriptors::createDataDescriptor()
+{
+ return new ColumnDescriptor( m_xMutex, m_origin, m_pSettings );
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/postgresql/pq_xcolumns.hxx b/connectivity/source/drivers/postgresql/pq_xcolumns.hxx
new file mode 100644
index 0000000000..8ff8fcfbd9
--- /dev/null
+++ b/connectivity/source/drivers/postgresql/pq_xcolumns.hxx
@@ -0,0 +1,122 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * Effective License of whole file:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011:
+ *
+ * The Contents of this file are made available subject to the terms of
+ * the GNU Lesser General Public License Version 2.1
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * Contributor(s): Joerg Budischewski
+ *
+ * All parts contributed on or after August 2011:
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ ************************************************************************/
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <string_view>
+
+#include <rtl/ref.hxx>
+
+#include "pq_xcontainer.hxx"
+#include "pq_xbase.hxx"
+
+namespace com::sun::star::sdbc { class XRow; }
+
+namespace pq_sdbc_driver
+{
+
+void alterColumnByDescriptor(
+ std::u16string_view schemaName,
+ std::u16string_view tableName,
+ ConnectionSettings *settings,
+ const css::uno::Reference< css::sdbc::XStatement > &stmt,
+ const css::uno::Reference< css::beans::XPropertySet > & past,
+ const css::uno::Reference< css::beans::XPropertySet > & future);
+
+OUString columnMetaData2SDBCX(
+ ReflectionBase *pBase, const css::uno::Reference< css::sdbc::XRow > &xRow );
+
+class Columns final : public Container
+{
+ OUString m_schemaName;
+ OUString m_tableName;
+
+public: // instances Columns 'exception safe'
+ static css::uno::Reference< css::container::XNameAccess > create(
+ const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex,
+ const css::uno::Reference< css::sdbc::XConnection > & origin,
+ ConnectionSettings *pSettings,
+ const OUString &schemaName,
+ const OUString &tableName,
+ rtl::Reference<Columns> *pColumns);
+
+private:
+ Columns(
+ const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex,
+ const css::uno::Reference< css::sdbc::XConnection > & origin,
+ ConnectionSettings *pSettings,
+ OUString schemaName,
+ OUString tableName);
+
+
+ virtual ~Columns() override;
+
+public: // XAppend
+ virtual void SAL_CALL appendByDescriptor(
+ const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override;
+
+// public: // XDrop
+// virtual void SAL_CALL dropByName( const OUString& elementName )
+// throw (css::sdbc::SQLException,
+// css::container::NoSuchElementException,
+// css::uno::RuntimeException);
+ virtual void SAL_CALL dropByIndex( sal_Int32 index ) override;
+
+public: // XRefreshable
+ virtual void SAL_CALL refresh( ) override;
+
+public: // XDataDescriptorFactory
+ virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL createDataDescriptor( ) override;
+};
+
+
+class ColumnDescriptors : public Container
+{
+public:
+ ColumnDescriptors(
+ const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex,
+ const css::uno::Reference< css::sdbc::XConnection > & origin,
+ ConnectionSettings *pSettings );
+
+public: // XDataDescriptorFactory
+ virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL createDataDescriptor( ) override;
+};
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/postgresql/pq_xcontainer.cxx b/connectivity/source/drivers/postgresql/pq_xcontainer.cxx
new file mode 100644
index 0000000000..9d59428006
--- /dev/null
+++ b/connectivity/source/drivers/postgresql/pq_xcontainer.cxx
@@ -0,0 +1,411 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * Effective License of whole file:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011:
+ *
+ * The Contents of this file are made available subject to the terms of
+ * the GNU Lesser General Public License Version 2.1
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * Contributor(s): Joerg Budischewski
+ *
+ * All parts contributed on or after August 2011:
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ ************************************************************************/
+
+#include <com/sun/star/container/ElementExistException.hpp>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <comphelper/diagnose_ex.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <o3tl/safeint.hxx>
+#include <utility>
+
+#include "pq_xcontainer.hxx"
+#include "pq_statics.hxx"
+#include "pq_tools.hxx"
+
+using osl::MutexGuard;
+
+using com::sun::star::beans::XPropertySet;
+
+using com::sun::star::uno::Any;
+using com::sun::star::uno::Type;
+using com::sun::star::uno::XInterface;
+using com::sun::star::uno::Reference;
+using com::sun::star::uno::Sequence;
+using com::sun::star::uno::RuntimeException;
+
+using com::sun::star::container::NoSuchElementException;
+using com::sun::star::container::XEnumeration;
+using com::sun::star::container::XContainerListener;
+using com::sun::star::container::ContainerEvent;
+using com::sun::star::lang::IndexOutOfBoundsException;
+using com::sun::star::lang::XEventListener;
+
+
+namespace pq_sdbc_driver
+{
+
+namespace {
+
+class ReplacedBroadcaster : public EventBroadcastHelper
+{
+ ContainerEvent m_event;
+public:
+ ReplacedBroadcaster(
+ const Reference< XInterface > & source,
+ const OUString & name,
+ const Any & newElement,
+ const OUString & oldElement ) :
+ m_event( source, Any( name ), newElement, Any(oldElement) )
+ {}
+
+ virtual void fire( XEventListener * listener ) const override
+ {
+ static_cast<XContainerListener*>(listener)->elementReplaced( m_event );
+ }
+ virtual Type getType() const override
+ {
+ return cppu::UnoType<XContainerListener>::get();
+ }
+};
+
+class InsertedBroadcaster : public EventBroadcastHelper
+{
+public:
+ ContainerEvent m_event;
+ InsertedBroadcaster(
+ const Reference< XInterface > & source,
+ const OUString & name,
+ const Any & newElement ) :
+ m_event( source, Any( name ), newElement, Any() )
+ {}
+
+ virtual void fire( XEventListener * listener ) const override
+ {
+ static_cast<XContainerListener*>(listener)->elementInserted( m_event );
+ }
+
+ virtual Type getType() const override
+ {
+ return cppu::UnoType<XContainerListener>::get();
+ }
+};
+
+class RemovedBroadcaster : public EventBroadcastHelper
+{
+public:
+ ContainerEvent m_event;
+ RemovedBroadcaster(
+ const Reference< XInterface > & source,
+ const OUString & name) :
+ m_event( source, Any( name ), Any(), Any() )
+ {}
+
+ virtual void fire( XEventListener * listener ) const override
+ {
+ static_cast<XContainerListener*>(listener)->elementRemoved( m_event );
+ }
+
+ virtual Type getType() const override
+ {
+ return cppu::UnoType<XContainerListener>::get();
+ }
+};
+
+}
+
+Container::Container(
+ const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex,
+ css::uno::Reference< css::sdbc::XConnection > origin,
+ ConnectionSettings *pSettings,
+ OUString type)
+ : ContainerBase( refMutex->GetMutex() ),
+ m_xMutex( refMutex ),
+ m_pSettings( pSettings ),
+ m_origin(std::move( origin )),
+ m_type(std::move( type ))
+{
+}
+
+Any Container::getByName( const OUString& aName )
+{
+ String2IntMap::const_iterator ii = m_name2index.find( aName );
+ if( ii == m_name2index.end() )
+ {
+ throw NoSuchElementException(
+ "Element " + aName + " unknown in " + m_type + "-Container",
+ *this );
+ }
+ OSL_ASSERT( ii->second >= 0 && o3tl::make_unsigned(ii->second) < m_values.size() );
+ return m_values[ ii->second ];
+}
+
+Sequence< OUString > Container::getElementNames( )
+{
+ Sequence< OUString > ret( m_values.size() );
+ auto retRange = asNonConstRange(ret);
+ for( const auto& [rName, rIndex] : m_name2index )
+ {
+ // give element names in index order !
+ retRange[rIndex] = rName;
+ }
+ return ret;
+}
+
+sal_Bool Container::hasByName( const OUString& aName )
+{
+ return m_name2index.find( aName ) != m_name2index.end();
+}
+ // Methods
+Type Container::getElementType( )
+{
+ return Type();
+}
+
+sal_Bool Container::hasElements( )
+{
+ return ! m_name2index.empty();
+}
+
+Any Container::getByIndex( sal_Int32 Index )
+{
+ if( Index < 0 || o3tl::make_unsigned(Index) >= m_values.size() )
+ {
+ throw IndexOutOfBoundsException(
+ "Index " + OUString::number( Index )
+ + " out of range for " + m_type + "-Container, expected 0 <= x <= "
+ + OUString::number(m_values.size() -1),
+ *this );
+ }
+ return m_values[Index];
+}
+
+sal_Int32 Container::getCount()
+{
+ return m_values.size();
+}
+
+namespace {
+
+class ContainerEnumeration : public ::cppu::WeakImplHelper< XEnumeration >
+{
+ std::vector< css::uno::Any > m_vec;
+ sal_Int32 m_index;
+public:
+ explicit ContainerEnumeration( std::vector< css::uno::Any >&& vec )
+ : m_vec( std::move(vec) ),
+ m_index( -1 )
+ {}
+
+public:
+ // XEnumeration
+ virtual sal_Bool SAL_CALL hasMoreElements( ) override;
+ virtual css::uno::Any SAL_CALL nextElement( ) override;
+
+};
+
+}
+
+sal_Bool ContainerEnumeration::hasMoreElements()
+{
+ return static_cast<int>(m_vec.size()) > m_index +1;
+}
+
+css::uno::Any ContainerEnumeration::nextElement()
+{
+ if( ! hasMoreElements() )
+ {
+ throw NoSuchElementException(
+ "NoSuchElementException during enumeration", *this );
+ }
+ m_index ++;
+ return m_vec[m_index];
+}
+
+Reference< XEnumeration > Container::createEnumeration( )
+{
+ return new ContainerEnumeration( std::vector(m_values) );
+}
+
+void Container::addRefreshListener(
+ const css::uno::Reference< css::util::XRefreshListener >& l )
+{
+ rBHelper.addListener( cppu::UnoType<decltype(l)>::get() , l );
+}
+
+void Container::removeRefreshListener(
+ const css::uno::Reference< css::util::XRefreshListener >& l )
+{
+ rBHelper.removeListener( cppu::UnoType<decltype(l)>::get() , l );
+}
+
+void Container::disposing()
+{
+ m_origin.clear();
+}
+
+void Container::rename( const OUString &oldName, const OUString &newName )
+{
+ Any newValue;
+ {
+ osl::MutexGuard guard ( m_xMutex->GetMutex() );
+ String2IntMap::iterator ii = m_name2index.find( oldName );
+ if( ii != m_name2index.end() )
+ {
+ sal_Int32 nIndex = ii->second;
+ newValue = m_values[nIndex];
+ m_name2index.erase( ii );
+ m_name2index[ newName ] = nIndex;
+ }
+ }
+ fire( ReplacedBroadcaster( *this, newName, newValue, oldName ) );
+ fire( RefreshedBroadcaster( *this ) );
+}
+
+void Container::dropByName( const OUString& elementName )
+{
+ osl::MutexGuard guard( m_xMutex->GetMutex() );
+ String2IntMap::const_iterator ii = m_name2index.find( elementName );
+ if( ii == m_name2index.end() )
+ {
+ throw css::container::NoSuchElementException(
+ "Column " + elementName + " is unknown in "
+ + m_type + " container, so it can't be dropped",
+ *this );
+ }
+ dropByIndex( ii->second );
+}
+
+void Container::dropByIndex( sal_Int32 index )
+{
+ osl::MutexGuard guard( m_xMutex->GetMutex() );
+ if( index < 0 || o3tl::make_unsigned(index) >=m_values.size() )
+ {
+ throw css::lang::IndexOutOfBoundsException(
+ "Index out of range (allowed 0 to "
+ + OUString::number(m_values.size() -1)
+ + ", got " + OUString::number( index )
+ + ") in " + m_type,
+ *this );
+ }
+
+ OUString name;
+ String2IntMap::iterator ii = std::find_if(m_name2index.begin(), m_name2index.end(),
+ [&index](const String2IntMap::value_type& rEntry) { return rEntry.second == index; });
+ if (ii != m_name2index.end())
+ {
+ name = ii->first;
+ m_name2index.erase( ii );
+ }
+
+ for( int i = index +1 ; i < static_cast<int>(m_values.size()) ; i ++ )
+ {
+ m_values[i-1] = m_values[i];
+
+ // I know, this is expensive, but don't want to maintain another map ...
+ ii = std::find_if(m_name2index.begin(), m_name2index.end(),
+ [&i](const String2IntMap::value_type& rEntry) { return rEntry.second == i; });
+ if (ii != m_name2index.end())
+ {
+ ii->second = i-1;
+ }
+ }
+ m_values.resize( m_values.size() - 1 );
+
+ fire( RemovedBroadcaster( *this, name ) );
+}
+
+void Container::append(
+ const OUString & name,
+ const css::uno::Reference< css::beans::XPropertySet >& descriptor )
+
+{
+ osl::MutexGuard guard( m_xMutex->GetMutex() );
+
+ if( hasByName( name ) )
+ {
+ throw css::container::ElementExistException(
+ "a " + m_type + " with name " + name + " already exists in this container",
+ *this );
+ }
+
+ int index = m_values.size();
+ m_values.push_back( Any( descriptor ) );
+ m_name2index[name] = index;
+
+ fire( InsertedBroadcaster( *this, name, Any( descriptor ) ) );
+}
+
+void Container::appendByDescriptor(
+ const css::uno::Reference< css::beans::XPropertySet >& descriptor)
+{
+ append( extractStringProperty( descriptor, getStatics().NAME ), descriptor );
+}
+
+
+void Container::addContainerListener(
+ const css::uno::Reference< css::container::XContainerListener >& l )
+{
+ rBHelper.addListener( cppu::UnoType<decltype(l)>::get() , l );
+}
+
+void Container::removeContainerListener(
+ const css::uno::Reference< css::container::XContainerListener >& l )
+{
+ rBHelper.removeListener( cppu::UnoType<decltype(l)>::get() , l );
+}
+
+
+void Container::fire( const EventBroadcastHelper &helper )
+{
+ cppu::OInterfaceContainerHelper *container = rBHelper.getContainer( helper.getType() );
+ if( !container )
+ return;
+
+ cppu::OInterfaceIteratorHelper iterator( * container );
+ while( iterator.hasMoreElements() )
+ {
+ try
+ {
+ helper.fire( static_cast<XEventListener *>(iterator.next()) );
+ }
+ catch ( css::uno::RuntimeException & )
+ {
+ TOOLS_WARN_EXCEPTION( "connectivity.postgresql", "exception caught" );
+ // loose coupling, a runtime exception shall not break anything
+ // TODO: log away as warning !
+ }
+ catch( css::uno::Exception & )
+ {
+ TOOLS_WARN_EXCEPTION( "connectivity.postgresql", "exception from listener flying through" );
+ throw;
+ }
+ }
+
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/postgresql/pq_xcontainer.hxx b/connectivity/source/drivers/postgresql/pq_xcontainer.hxx
new file mode 100644
index 0000000000..4b6c190b0a
--- /dev/null
+++ b/connectivity/source/drivers/postgresql/pq_xcontainer.hxx
@@ -0,0 +1,188 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * Effective License of whole file:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011:
+ *
+ * The Contents of this file are made available subject to the terms of
+ * the GNU Lesser General Public License Version 2.1
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * Contributor(s): Joerg Budischewski
+ *
+ * All parts contributed on or after August 2011:
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ ************************************************************************/
+
+#pragma once
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <com/sun/star/container/XIndexAccess.hpp>
+#include <com/sun/star/container/XEnumerationAccess.hpp>
+#include <com/sun/star/container/XContainer.hpp>
+
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <com/sun/star/sdbcx/XAppend.hpp>
+#include <com/sun/star/sdbcx/XDrop.hpp>
+#include <com/sun/star/sdbcx/XDataDescriptorFactory.hpp>
+
+#include <com/sun/star/util/XRefreshable.hpp>
+
+#include <comphelper/refcountedmutex.hxx>
+#include <cppuhelper/compbase.hxx>
+#include <rtl/ref.hxx>
+
+#include <unordered_map>
+
+namespace pq_sdbc_driver
+{
+
+struct ConnectionSettings;
+
+class EventBroadcastHelper
+{
+public:
+ virtual void fire(css::lang::XEventListener * listener) const = 0;
+ virtual css::uno::Type getType() const = 0;
+ virtual ~EventBroadcastHelper(){};
+};
+
+class RefreshedBroadcaster : public EventBroadcastHelper
+{
+ css::lang::EventObject m_event;
+public:
+ explicit RefreshedBroadcaster(const css::uno::Reference< css::uno::XInterface > & source ) :
+ m_event( source )
+ {}
+
+ virtual void fire( css::lang::XEventListener * listener ) const override
+ {
+ static_cast<css::util::XRefreshListener*>(listener)->refreshed( m_event );
+ }
+
+ virtual css::uno::Type getType() const override
+ {
+ return cppu::UnoType<
+ css::util::XRefreshListener>::get();
+ }
+};
+
+typedef std::unordered_map
+<
+ OUString,
+ sal_Int32
+> String2IntMap;
+
+typedef ::cppu::WeakComponentImplHelper
+<
+ css::container::XNameAccess,
+ css::container::XIndexAccess,
+ css::container::XEnumerationAccess,
+ css::sdbcx::XAppend,
+ css::sdbcx::XDrop,
+ css::util::XRefreshable,
+ css::sdbcx::XDataDescriptorFactory,
+ css::container::XContainer
+> ContainerBase;
+
+class /* abstract */ Container : public ContainerBase
+{
+protected:
+ ::rtl::Reference< comphelper::RefCountedMutex > m_xMutex;
+ ConnectionSettings *m_pSettings;
+ css::uno::Reference< css::sdbc::XConnection > m_origin;
+ String2IntMap m_name2index; // maps the element name to an index
+ std::vector< css::uno::Any > m_values; // contains the real values
+ OUString m_type;
+
+public:
+ Container(
+ const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex,
+ css::uno::Reference< css::sdbc::XConnection > origin,
+ ConnectionSettings *pSettings,
+ OUString type // for exception messages
+ );
+
+public: // XIndexAccess
+ virtual sal_Int32 SAL_CALL getCount( ) override;
+ virtual css::uno::Any SAL_CALL getByIndex( sal_Int32 Index ) override;
+
+public: // XEnumerationAccess
+ virtual css::uno::Reference< css::container::XEnumeration >
+ SAL_CALL createEnumeration( ) override;
+
+public: // XNameAccess
+ virtual css::uno::Any SAL_CALL getByName( const OUString& aName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getElementNames( ) override;
+ virtual sal_Bool SAL_CALL hasByName( const OUString& aName ) override;
+ // Methods
+ virtual css::uno::Type SAL_CALL getElementType( ) override;
+ virtual sal_Bool SAL_CALL hasElements( ) override;
+
+
+public: // XAppend
+ // Must be overridden in Non-Descriptors. May be overridden in descriptors, when
+ // PropertySet.NAME != container name
+ virtual void SAL_CALL appendByDescriptor(
+ const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override;
+
+ // helper method !
+ /// @throws css::container::ElementExistException
+ void append(
+ const OUString & str,
+ const css::uno::Reference< css::beans::XPropertySet >& descriptor );
+
+
+public: // XDrop
+ virtual void SAL_CALL dropByName( const OUString& elementName ) override;
+ virtual void SAL_CALL dropByIndex( sal_Int32 index ) override;
+
+public: // XDataDescriptorFactory
+ virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL createDataDescriptor( ) override = 0;
+
+public: // XRefreshable
+ virtual void SAL_CALL refresh( ) override {}
+ virtual void SAL_CALL addRefreshListener(
+ const css::uno::Reference< css::util::XRefreshListener >& l ) override;
+ virtual void SAL_CALL removeRefreshListener(
+ const css::uno::Reference< css::util::XRefreshListener >& l ) override;
+
+public:
+ // Methods
+ virtual void SAL_CALL addContainerListener(
+ const css::uno::Reference< css::container::XContainerListener >& xListener ) override;
+ virtual void SAL_CALL removeContainerListener(
+ const css::uno::Reference< css::container::XContainerListener >& xListener ) override;
+
+public:
+ virtual void SAL_CALL disposing() override;
+
+public:
+ void rename( const OUString & oldName, const OUString &newName );
+
+protected:
+ void fire( const EventBroadcastHelper & helper );
+};
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/postgresql/pq_xindex.cxx b/connectivity/source/drivers/postgresql/pq_xindex.cxx
new file mode 100644
index 0000000000..4753b5fd4e
--- /dev/null
+++ b/connectivity/source/drivers/postgresql/pq_xindex.cxx
@@ -0,0 +1,187 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * Effective License of whole file:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011:
+ *
+ * The Contents of this file are made available subject to the terms of
+ * the GNU Lesser General Public License Version 2.1
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * Contributor(s): Joerg Budischewski
+ *
+ * All parts contributed on or after August 2011:
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ ************************************************************************/
+
+#include <cppuhelper/typeprovider.hxx>
+#include <cppuhelper/queryinterface.hxx>
+#include <rtl/ref.hxx>
+#include <utility>
+
+#include "pq_xindex.hxx"
+#include "pq_xindexcolumns.hxx"
+#include "pq_tools.hxx"
+#include "pq_statics.hxx"
+
+using com::sun::star::container::XNameAccess;
+
+using com::sun::star::uno::Reference;
+using com::sun::star::uno::Sequence;
+using com::sun::star::uno::Any;
+using com::sun::star::uno::Type;
+
+using com::sun::star::beans::XPropertySet;
+
+
+namespace pq_sdbc_driver
+{
+Index::Index( const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex,
+ const Reference< css::sdbc::XConnection > & connection,
+ ConnectionSettings *pSettings,
+ OUString schemaName,
+ OUString tableName )
+ : ReflectionBase(
+ getStatics().refl.index.implName,
+ getStatics().refl.index.serviceNames,
+ refMutex,
+ connection,
+ pSettings,
+ * getStatics().refl.index.pProps ),
+ m_schemaName(std::move( schemaName )),
+ m_tableName(std::move( tableName ))
+{}
+
+Reference< XPropertySet > Index::createDataDescriptor( )
+{
+ rtl::Reference<IndexDescriptor> pIndex = new IndexDescriptor(
+ m_xMutex, m_conn, m_pSettings );
+ pIndex->copyValuesFrom( this );
+
+ return Reference< XPropertySet > ( pIndex );
+}
+
+Reference< XNameAccess > Index::getColumns( )
+{
+ if( ! m_indexColumns.is() )
+ {
+ Sequence< OUString > columnNames;
+ getPropertyValue( getStatics().PRIVATE_COLUMN_INDEXES ) >>= columnNames;
+ OUString indexName = extractStringProperty( this, getStatics().NAME );
+ m_indexColumns = IndexColumns::create(
+ m_xMutex, m_conn, m_pSettings, m_schemaName,
+ m_tableName, indexName, columnNames );
+ }
+ return m_indexColumns;
+}
+
+Sequence<Type > Index::getTypes()
+{
+ static cppu::OTypeCollection collection(
+ cppu::UnoType<css::sdbcx::XColumnsSupplier>::get(),
+ ReflectionBase::getTypes());
+
+ return collection.getTypes();
+}
+
+Sequence< sal_Int8> Index::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+Any Index::queryInterface( const Type & reqType )
+{
+ Any ret = ReflectionBase::queryInterface( reqType );
+ if( ! ret.hasValue() )
+ ret = ::cppu::queryInterface(
+ reqType,
+ static_cast< css::sdbcx::XColumnsSupplier * > ( this ) );
+ return ret;
+}
+
+
+IndexDescriptor::IndexDescriptor(
+ const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex,
+ const Reference< css::sdbc::XConnection > & connection,
+ ConnectionSettings *pSettings )
+ : ReflectionBase(
+ getStatics().refl.indexDescriptor.implName,
+ getStatics().refl.indexDescriptor.serviceNames,
+ refMutex,
+ connection,
+ pSettings,
+ * getStatics().refl.indexDescriptor.pProps )
+{}
+
+Reference< XPropertySet > IndexDescriptor::createDataDescriptor( )
+{
+ rtl::Reference<IndexDescriptor> pIndex = new IndexDescriptor(
+ m_xMutex, m_conn, m_pSettings );
+ pIndex->copyValuesFrom( this );
+ return Reference< XPropertySet > ( pIndex );
+}
+
+Reference< XNameAccess > IndexDescriptor::getColumns( )
+{
+ if( ! m_indexColumns.is() )
+ {
+ m_indexColumns = IndexColumnDescriptors::create(
+ m_xMutex, m_conn, m_pSettings );
+// Sequence< OUString > columnNames;
+// getPropertyValue( getStatics().PRIVATE_COLUMN_INDEXES ) >>= columnNames;
+// OUString indexName = extractStringProperty( this, getStatics().NAME );
+// m_indexColumns = IndexColumns::create(
+// m_xMutex, m_conn, m_pSettings, m_schemaName,
+// m_tableName, indexName, columnNames );
+ }
+ return m_indexColumns;
+}
+
+Sequence<Type > IndexDescriptor::getTypes()
+{
+ static cppu::OTypeCollection collection(
+ cppu::UnoType<css::sdbcx::XColumnsSupplier>::get(),
+ ReflectionBase::getTypes());
+
+ return collection.getTypes();
+}
+
+Sequence< sal_Int8> IndexDescriptor::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+Any IndexDescriptor::queryInterface( const Type & reqType )
+{
+ Any ret = ReflectionBase::queryInterface( reqType );
+ if( ! ret.hasValue() )
+ ret = ::cppu::queryInterface(
+ reqType,
+ static_cast< css::sdbcx::XColumnsSupplier * > ( this ) );
+ return ret;
+}
+
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/postgresql/pq_xindex.hxx b/connectivity/source/drivers/postgresql/pq_xindex.hxx
new file mode 100644
index 0000000000..8ccf456604
--- /dev/null
+++ b/connectivity/source/drivers/postgresql/pq_xindex.hxx
@@ -0,0 +1,123 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * Effective License of whole file:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011:
+ *
+ * The Contents of this file are made available subject to the terms of
+ * the GNU Lesser General Public License Version 2.1
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * Contributor(s): Joerg Budischewski
+ *
+ * All parts contributed on or after August 2011:
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ ************************************************************************/
+
+#pragma once
+
+#include <cppuhelper/component.hxx>
+#include <cppuhelper/propshlp.hxx>
+
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/sdbcx/XDataDescriptorFactory.hpp>
+#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
+
+#include "pq_connection.hxx"
+#include "pq_xbase.hxx"
+
+namespace pq_sdbc_driver
+{
+
+class Index : public ReflectionBase,
+ public css::sdbcx::XColumnsSupplier
+{
+ css::uno::Reference< css::container::XNameAccess > m_indexColumns;
+
+ OUString m_schemaName;
+ OUString m_tableName;
+
+public:
+ Index( const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex,
+ const css::uno::Reference< css::sdbc::XConnection > & connection,
+ ConnectionSettings *pSettings,
+ OUString schemaName,
+ OUString tableName);
+
+public: // XInterface
+ virtual void SAL_CALL acquire() noexcept override { ReflectionBase::acquire(); }
+ virtual void SAL_CALL release() noexcept override { ReflectionBase::release(); }
+ virtual css::uno::Any SAL_CALL queryInterface(
+ const css::uno::Type & reqType ) override;
+
+public: // XColumnsSupplier
+ virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL
+ getColumns( ) override;
+
+public: // XTypeProvider, first implemented by OPropertySetHelper
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override;
+ virtual css::uno::Sequence< sal_Int8> SAL_CALL getImplementationId() override;
+
+public: // XDataDescriptorFactory
+ virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL
+ createDataDescriptor( ) override;
+
+};
+
+
+class IndexDescriptor : public ReflectionBase,
+ public css::sdbcx::XColumnsSupplier
+{
+ css::uno::Reference< css::container::XNameAccess > m_indexColumns;
+
+public:
+ IndexDescriptor(
+ const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex,
+ const css::uno::Reference< css::sdbc::XConnection > & connection,
+ ConnectionSettings *pSettings);
+
+public: // XInterface
+ virtual void SAL_CALL acquire() noexcept override { ReflectionBase::acquire(); }
+ virtual void SAL_CALL release() noexcept override { ReflectionBase::release(); }
+ virtual css::uno::Any SAL_CALL queryInterface(
+ const css::uno::Type & reqType ) override;
+
+public: // XColumnsSupplier
+ virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL
+ getColumns( ) override;
+
+public: // XTypeProvider, first implemented by OPropertySetHelper
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override;
+ virtual css::uno::Sequence< sal_Int8> SAL_CALL getImplementationId() override;
+
+public: // XDataDescriptorFactory
+ virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL
+ createDataDescriptor( ) override;
+
+};
+
+
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/postgresql/pq_xindexcolumn.cxx b/connectivity/source/drivers/postgresql/pq_xindexcolumn.cxx
new file mode 100644
index 0000000000..fe72059bc1
--- /dev/null
+++ b/connectivity/source/drivers/postgresql/pq_xindexcolumn.cxx
@@ -0,0 +1,96 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * Effective License of whole file:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011:
+ *
+ * The Contents of this file are made available subject to the terms of
+ * the GNU Lesser General Public License Version 2.1
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * Contributor(s): Joerg Budischewski
+ *
+ * All parts contributed on or after August 2011:
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ ************************************************************************/
+
+#include <sal/config.h>
+
+#include <rtl/ref.hxx>
+
+#include "pq_statics.hxx"
+#include "pq_xindexcolumn.hxx"
+
+using com::sun::star::uno::Reference;
+
+using com::sun::star::beans::XPropertySet;
+
+namespace pq_sdbc_driver
+{
+IndexColumn::IndexColumn( const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex,
+ const Reference< css::sdbc::XConnection > & connection,
+ ConnectionSettings *pSettings )
+ : ReflectionBase(
+ getStatics().refl.indexColumn.implName,
+ getStatics().refl.indexColumn.serviceNames,
+ refMutex,
+ connection,
+ pSettings,
+ * getStatics().refl.indexColumn.pProps )
+{}
+
+Reference< XPropertySet > IndexColumn::createDataDescriptor( )
+{
+ rtl::Reference<IndexColumnDescriptor> pIndexColumn = new IndexColumnDescriptor(
+ m_xMutex, m_conn, m_pSettings );
+ pIndexColumn->copyValuesFrom( this );
+
+ return Reference< XPropertySet > ( pIndexColumn );
+}
+
+
+IndexColumnDescriptor::IndexColumnDescriptor(
+ const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex,
+ const Reference< css::sdbc::XConnection > & connection,
+ ConnectionSettings *pSettings )
+ : ReflectionBase(
+ getStatics().refl.indexColumnDescriptor.implName,
+ getStatics().refl.indexColumnDescriptor.serviceNames,
+ refMutex,
+ connection,
+ pSettings,
+ * getStatics().refl.indexColumnDescriptor.pProps )
+{}
+
+Reference< XPropertySet > IndexColumnDescriptor::createDataDescriptor( )
+{
+ rtl::Reference<IndexColumnDescriptor> pIndexColumn = new IndexColumnDescriptor(
+ m_xMutex, m_conn, m_pSettings );
+ pIndexColumn->copyValuesFrom( this );
+
+ return Reference< XPropertySet > ( pIndexColumn );
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/postgresql/pq_xindexcolumn.hxx b/connectivity/source/drivers/postgresql/pq_xindexcolumn.hxx
new file mode 100644
index 0000000000..7872985ec8
--- /dev/null
+++ b/connectivity/source/drivers/postgresql/pq_xindexcolumn.hxx
@@ -0,0 +1,83 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * Effective License of whole file:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011:
+ *
+ * The Contents of this file are made available subject to the terms of
+ * the GNU Lesser General Public License Version 2.1
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * Contributor(s): Joerg Budischewski
+ *
+ * All parts contributed on or after August 2011:
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ ************************************************************************/
+
+#pragma once
+
+#include <cppuhelper/component.hxx>
+#include <cppuhelper/propshlp.hxx>
+
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/sdbcx/XDataDescriptorFactory.hpp>
+
+#include "pq_connection.hxx"
+#include "pq_xbase.hxx"
+
+namespace pq_sdbc_driver
+{
+
+class IndexColumn : public ReflectionBase
+{
+public:
+ IndexColumn(
+ const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex,
+ const css::uno::Reference< css::sdbc::XConnection > & connection,
+ ConnectionSettings *pSettings);
+
+public: // XDataDescriptorFactory
+ virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL
+ createDataDescriptor( ) override;
+
+};
+
+class IndexColumnDescriptor : public ReflectionBase
+{
+public:
+ IndexColumnDescriptor(
+ const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex,
+ const css::uno::Reference< css::sdbc::XConnection > & connection,
+ ConnectionSettings *pSettings);
+
+public: // XDataDescriptorFactory
+ virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL
+ createDataDescriptor( ) override;
+
+};
+
+
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/postgresql/pq_xindexcolumns.cxx b/connectivity/source/drivers/postgresql/pq_xindexcolumns.cxx
new file mode 100644
index 0000000000..2bca00e13b
--- /dev/null
+++ b/connectivity/source/drivers/postgresql/pq_xindexcolumns.cxx
@@ -0,0 +1,268 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * Effective License of whole file:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011:
+ *
+ * The Contents of this file are made available subject to the terms of
+ * the GNU Lesser General Public License Version 2.1
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * Contributor(s): Joerg Budischewski
+ *
+ * All parts contributed on or after August 2011:
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ ************************************************************************/
+
+#include <sal/log.hxx>
+
+#include <string_view>
+#include <utility>
+#include <vector>
+
+#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <cppuhelper/exc_hlp.hxx>
+#include <rtl/ref.hxx>
+
+#include "pq_xcolumns.hxx"
+#include "pq_xindexcolumns.hxx"
+#include "pq_xindexcolumn.hxx"
+#include "pq_statics.hxx"
+#include "pq_tools.hxx"
+
+using osl::MutexGuard;
+
+using com::sun::star::beans::XPropertySet;
+
+using com::sun::star::uno::Any;
+using com::sun::star::uno::UNO_QUERY;
+using com::sun::star::uno::Reference;
+using com::sun::star::uno::Sequence;
+
+using com::sun::star::sdbc::XRow;
+using com::sun::star::sdbc::XResultSet;
+using com::sun::star::sdbc::XDatabaseMetaData;
+using com::sun::star::sdbc::SQLException;
+
+namespace pq_sdbc_driver
+{
+
+IndexColumns::IndexColumns(
+ const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex,
+ const css::uno::Reference< css::sdbc::XConnection > & origin,
+ ConnectionSettings *pSettings,
+ OUString schemaName,
+ OUString tableName,
+ OUString indexName,
+ const css::uno::Sequence< OUString > &columns )
+ : Container( refMutex, origin, pSettings, "INDEX_COLUMN" ),
+ m_schemaName(std::move( schemaName )),
+ m_tableName(std::move( tableName )),
+ m_indexName(std::move( indexName )),
+ m_columns( columns )
+{}
+
+IndexColumns::~IndexColumns()
+{}
+
+static sal_Int32 findInSequence( const Sequence< OUString > & seq , std::u16string_view str)
+{
+ int index;
+ for( index = 0 ; index < seq.getLength() ; index ++ )
+ {
+ if( str == seq[index] )
+ break;
+ }
+ return index;
+}
+
+void IndexColumns::refresh()
+{
+ try
+ {
+ SAL_INFO("connectivity.postgresql", "sdbcx.IndexColumns get refreshed for index " << m_indexName);
+
+ osl::MutexGuard guard( m_xMutex->GetMutex() );
+
+ Statics &st = getStatics();
+ Reference< XDatabaseMetaData > meta = m_origin->getMetaData();
+
+ Reference< XResultSet > rs =
+ meta->getColumns( Any(), m_schemaName, m_tableName, st.cPERCENT );
+
+ DisposeGuard disposeIt( rs );
+ Reference< XRow > xRow( rs , UNO_QUERY );
+ m_values.clear();
+ m_values.resize( m_columns.getLength() );
+
+ while( rs->next() )
+ {
+ OUString columnName = xRow->getString( 4 );
+
+ sal_Int32 index = findInSequence( m_columns, columnName );
+ if( index >= m_columns.getLength() )
+ continue;
+
+ rtl::Reference<IndexColumn> pIndexColumn =
+ new IndexColumn( m_xMutex, m_origin, m_pSettings );
+ Reference< css::beans::XPropertySet > prop = pIndexColumn;
+
+ columnMetaData2SDBCX( pIndexColumn.get(), xRow );
+ pIndexColumn->setPropertyValue_NoBroadcast_public(
+ st.IS_ASCENDING , Any( false ) );
+
+ m_values[ index ] <<= prop;
+ m_name2index[ columnName ] = index;
+ }
+ }
+ catch ( css::sdbc::SQLException & e )
+ {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ throw css::lang::WrappedTargetRuntimeException( e.Message,
+ e.Context, anyEx );
+ }
+
+ fire( RefreshedBroadcaster( *this ) );
+}
+
+
+void IndexColumns::appendByDescriptor(
+ const css::uno::Reference< css::beans::XPropertySet >& /*future*/ )
+{
+ throw css::sdbc::SQLException(
+ "SDBC-POSTGRESQL: IndexesColumns.appendByDescriptor not yet implemented",
+ *this, OUString(), 1, Any() );
+// osl::MutexGuard guard( m_xMutex->GetMutex() );
+// Statics & st = getStatics();
+// Reference< XPropertySet > past = createDataDescriptor();
+// past->setPropertyValue( st.IS_NULLABLE, makeAny( css::sdbc::ColumnValue::NULLABLE ) );
+// alterColumnByDescriptor(
+// m_schemaName, m_tableName, m_pSettings->encoding, m_origin->createStatement() , past, future );
+
+}
+
+void IndexColumns::dropByName( const OUString& )
+{
+ throw css::sdbc::SQLException(
+ "SDBC-POSTGRESQL: IndexesColumns.dropByName not yet implemented",
+ *this, OUString(), 1, Any() );
+// String2IntMap::const_iterator ii = m_name2index.find( elementName );
+// if( ii == m_name2index.end() )
+// {
+// OUStringBuffer buf( 128 );
+// buf.appendAscii( "Column " );
+// buf.append( elementName );
+// buf.appendAscii( " is unknown in table " );
+// buf.append( m_schemaName );
+// buf.appendAscii( "." );
+// buf.append( m_tableName );
+// buf.appendAscii( ", so it can't be dropped" );
+// throw css::container::NoSuchElementException(
+// buf.makeStringAndClear(), *this );
+// }
+// dropByIndex( ii->second );
+}
+
+void IndexColumns::dropByIndex( sal_Int32 )
+{
+ throw css::sdbc::SQLException(
+ "SDBC-POSTGRESQL: IndexesColumns.dropByIndex not yet implemented",
+ *this, OUString(), 1, Any() );
+// osl::MutexGuard guard( m_xMutex->GetMutex() );
+// if( index < 0 || index >= m_values.getLength() )
+// {
+// OUStringBuffer buf( 128 );
+// buf.appendAscii( "COLUMNS: Index out of range (allowed 0 to " );
+// buf.append((sal_Int32)(m_values.getLength() -1) );
+// buf.appendAscii( ", got " );
+// buf.append( index );
+// buf.appendAscii( ")" );
+// throw css::lang::IndexOutOfBoundsException(
+// buf.makeStringAndClear(), *this );
+// }
+
+// Reference< XPropertySet > set;
+// m_values[index] >>= set;
+// Statics &st = getStatics();
+// OUString name;
+// set->getPropertyValue( st.NAME ) >>= name;
+
+// OUStringBuffer update( 128 );
+// update.appendAscii( "ALTER TABLE ONLY");
+// bufferQuoteQualifiedIdentifier( update, m_schemaName, m_tableName );
+// update.appendAscii( "DROP COLUMN" );
+// bufferQuoteIdentifier( update, name );
+// Reference< XStatement > stmt = m_origin->createStatement( );
+// DisposeGuard disposeIt( stmt );
+// stmt->executeUpdate( update.makeStringAndClear() );
+
+}
+
+
+Reference< css::beans::XPropertySet > IndexColumns::createDataDescriptor()
+{
+ return new IndexColumnDescriptor( m_xMutex, m_origin, m_pSettings );
+}
+
+Reference< css::container::XNameAccess > IndexColumns::create(
+ const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex,
+ const css::uno::Reference< css::sdbc::XConnection > & origin,
+ ConnectionSettings *pSettings,
+ const OUString &schemaName,
+ const OUString &tableName,
+ const OUString &indexName,
+ const Sequence< OUString > &columns )
+{
+ rtl::Reference<IndexColumns> pIndexColumns = new IndexColumns(
+ refMutex, origin, pSettings, schemaName, tableName, indexName, columns );
+ pIndexColumns->refresh();
+
+ return pIndexColumns;
+}
+
+
+IndexColumnDescriptors::IndexColumnDescriptors(
+ const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex,
+ const css::uno::Reference< css::sdbc::XConnection > & origin,
+ ConnectionSettings *pSettings)
+ : Container( refMutex, origin, pSettings, getStatics().INDEX_COLUMN )
+{}
+
+Reference< css::container::XNameAccess > IndexColumnDescriptors::create(
+ const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex,
+ const css::uno::Reference< css::sdbc::XConnection > & origin,
+ ConnectionSettings *pSettings)
+{
+ return new IndexColumnDescriptors( refMutex, origin, pSettings );
+}
+
+css::uno::Reference< css::beans::XPropertySet > IndexColumnDescriptors::createDataDescriptor()
+{
+ return new IndexColumnDescriptor( m_xMutex, m_origin, m_pSettings );
+}
+
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/postgresql/pq_xindexcolumns.hxx b/connectivity/source/drivers/postgresql/pq_xindexcolumns.hxx
new file mode 100644
index 0000000000..a838d5d669
--- /dev/null
+++ b/connectivity/source/drivers/postgresql/pq_xindexcolumns.hxx
@@ -0,0 +1,110 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * Effective License of whole file:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011:
+ *
+ * The Contents of this file are made available subject to the terms of
+ * the GNU Lesser General Public License Version 2.1
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * Contributor(s): Joerg Budischewski
+ *
+ * All parts contributed on or after August 2011:
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ ************************************************************************/
+
+#pragma once
+
+#include "pq_xcontainer.hxx"
+
+namespace pq_sdbc_driver
+{
+
+class IndexColumns final : public Container
+{
+ OUString m_schemaName;
+ OUString m_tableName;
+ OUString m_indexName;
+ css::uno::Sequence< OUString > m_columns;
+
+public: // instances IndexColumns 'exception safe'
+ static css::uno::Reference< css::container::XNameAccess > create(
+ const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex,
+ const css::uno::Reference< css::sdbc::XConnection > & origin,
+ ConnectionSettings *pSettings,
+ const OUString &schemaName,
+ const OUString &tableName,
+ const OUString &indexName,
+ const css::uno::Sequence< OUString > &columns );
+
+private:
+ IndexColumns(
+ const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex,
+ const css::uno::Reference< css::sdbc::XConnection > & origin,
+ ConnectionSettings *pSettings,
+ OUString schemaName,
+ OUString tableName,
+ OUString indexName,
+ const css::uno::Sequence< OUString > &columns );
+
+ virtual ~IndexColumns() override;
+
+public: // XAppend
+ virtual void SAL_CALL appendByDescriptor(
+ const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override;
+
+public: // XDrop
+ virtual void SAL_CALL dropByName( const OUString& elementName ) override;
+ virtual void SAL_CALL dropByIndex( sal_Int32 index ) override;
+
+public: // XRefreshable
+ virtual void SAL_CALL refresh( ) override;
+
+public: // XDataDescriptorFactory
+ virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL createDataDescriptor( ) override;
+};
+
+
+class IndexColumnDescriptors final : public Container
+{
+
+public: // instances IndexColumns 'exception safe'
+ static css::uno::Reference< css::container::XNameAccess > create(
+ const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex,
+ const css::uno::Reference< css::sdbc::XConnection > & origin,
+ ConnectionSettings *pSettings );
+
+private:
+ IndexColumnDescriptors(
+ const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex,
+ const css::uno::Reference< css::sdbc::XConnection > & origin,
+ ConnectionSettings *pSettings);
+
+public: // XDataDescriptorFactory
+ virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL createDataDescriptor( ) override;
+};
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/postgresql/pq_xindexes.cxx b/connectivity/source/drivers/postgresql/pq_xindexes.cxx
new file mode 100644
index 0000000000..79f0939c1a
--- /dev/null
+++ b/connectivity/source/drivers/postgresql/pq_xindexes.cxx
@@ -0,0 +1,303 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * Effective License of whole file:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011:
+ *
+ * The Contents of this file are made available subject to the terms of
+ * the GNU Lesser General Public License Version 2.1
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * Contributor(s): Joerg Budischewski
+ *
+ * All parts contributed on or after August 2011:
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ ************************************************************************/
+
+#include <sal/log.hxx>
+#include <rtl/ref.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XParameters.hpp>
+#include <cppuhelper/exc_hlp.hxx>
+#include <o3tl/safeint.hxx>
+#include <utility>
+
+#include "pq_xindexes.hxx"
+#include "pq_xindex.hxx"
+#include "pq_statics.hxx"
+#include "pq_tools.hxx"
+
+using osl::MutexGuard;
+
+
+using com::sun::star::beans::XPropertySet;
+
+using com::sun::star::uno::Any;
+using com::sun::star::uno::UNO_QUERY;
+using com::sun::star::uno::Reference;
+using com::sun::star::uno::Sequence;
+
+using com::sun::star::container::XEnumerationAccess;
+using com::sun::star::container::XEnumeration;
+
+
+using com::sun::star::sdbcx::XColumnsSupplier;
+
+using com::sun::star::sdbc::XRow;
+using com::sun::star::sdbc::XResultSet;
+using com::sun::star::sdbc::XParameters;
+using com::sun::star::sdbc::XPreparedStatement;
+
+namespace pq_sdbc_driver
+{
+
+Indexes::Indexes(
+ const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex,
+ const css::uno::Reference< css::sdbc::XConnection > & origin,
+ ConnectionSettings *pSettings,
+ OUString schemaName,
+ OUString tableName)
+ : Container( refMutex, origin, pSettings, getStatics().KEY ),
+ m_schemaName(std::move( schemaName )),
+ m_tableName(std::move( tableName ))
+{
+}
+
+Indexes::~Indexes()
+{}
+
+void Indexes::refresh()
+{
+ try
+ {
+ SAL_INFO("connectivity.postgresql", "sdbcx.Indexes get refreshed for table " << m_schemaName << "." << m_tableName);
+
+ osl::MutexGuard guard( m_xMutex->GetMutex() );
+ Statics & st = getStatics();
+
+ Int2StringMap column2NameMap;
+ fillAttnum2attnameMap( column2NameMap, m_origin, m_schemaName, m_tableName );
+
+ // see XDatabaseMetaData::getIndexInfo()
+ Reference< XPreparedStatement > stmt = m_origin->prepareStatement(
+ "SELECT nspname, " // 1
+ "pg_class.relname, " // 2
+ "class2.relname, " // 3
+ "indisclustered, " // 4
+ "indisunique, " // 5
+ "indisprimary, " // 6
+ "indkey " // 7
+ "FROM pg_index INNER JOIN pg_class ON indrelid = pg_class.oid "
+ "INNER JOIN pg_namespace ON pg_class.relnamespace = pg_namespace.oid "
+ "INNER JOIN pg_class as class2 ON pg_index.indexrelid = class2.oid "
+ "WHERE nspname = ? AND pg_class.relname = ?" );
+
+ Reference< XParameters > params( stmt, UNO_QUERY);
+ params->setString( 1, m_schemaName );
+ params->setString( 2, m_tableName );
+ Reference< XResultSet > rs = stmt->executeQuery();
+
+ Reference< XRow > row( rs, UNO_QUERY );
+ String2IntMap map;
+ m_values.clear();
+ sal_Int32 index = 0;
+ while( rs->next() )
+ {
+ // C_SCHEMA = 1
+ // C_TABLENAME = 2
+ static const sal_Int32 C_INDEXNAME = 3;
+ static const sal_Int32 C_IS_CLUSTERED = 4;
+ static const sal_Int32 C_IS_UNIQUE = 5;
+ static const sal_Int32 C_IS_PRIMARY = 6;
+ static const sal_Int32 C_COLUMNS = 7;
+ OUString currentIndexName = row->getString( C_INDEXNAME );
+ rtl::Reference<Index> pIndex =
+ new Index( m_xMutex, m_origin, m_pSettings,
+ m_schemaName, m_tableName );
+
+ bool isUnique = row->getBoolean( C_IS_UNIQUE );
+ bool isPrimary = row->getBoolean( C_IS_PRIMARY );
+ bool isClusterd = row->getBoolean( C_IS_CLUSTERED );
+ Reference< css::beans::XPropertySet > prop = pIndex;
+ pIndex->setPropertyValue_NoBroadcast_public(
+ st.IS_UNIQUE, Any( isUnique ) );
+ pIndex->setPropertyValue_NoBroadcast_public(
+ st.IS_PRIMARY_KEY_INDEX, Any( isPrimary ) );
+ pIndex->setPropertyValue_NoBroadcast_public(
+ st.IS_CLUSTERED, Any( isClusterd ) );
+ pIndex->setPropertyValue_NoBroadcast_public(
+ st.NAME, Any( currentIndexName ) );
+
+ std::vector< sal_Int32 > seq = parseIntArray( row->getString( C_COLUMNS ) );
+ Sequence< OUString > columnNames(seq.size());
+ auto columnNamesRange = asNonConstRange(columnNames);
+ for( size_t columns = 0 ; columns < seq.size() ; columns ++ )
+ {
+ columnNamesRange[columns] = column2NameMap[ seq[columns] ];
+ }
+
+ pIndex->setPropertyValue_NoBroadcast_public(
+ st.PRIVATE_COLUMN_INDEXES, Any( columnNames ));
+
+ {
+ m_values.push_back( Any( prop ) );
+ map[ currentIndexName ] = index;
+ ++index;
+ }
+ }
+ m_name2index.swap( map );
+ }
+ catch ( css::sdbc::SQLException & e )
+ {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ throw css::lang::WrappedTargetRuntimeException( e.Message,
+ e.Context, anyEx );
+ }
+
+ fire( RefreshedBroadcaster( *this ) );
+}
+
+
+void Indexes::appendByDescriptor(
+ const css::uno::Reference< css::beans::XPropertySet >& descriptor )
+{
+ Statics & st = getStatics();
+ OUString name = extractStringProperty( descriptor, st.NAME );
+
+ bool isUnique = extractBoolProperty( descriptor, st.IS_UNIQUE );
+
+ OUStringBuffer buf( 128 );
+
+ buf.append( "CREATE " );
+ if( isUnique )
+ buf.append( "UNIQUE " );
+ buf.append( "INDEX " );
+ bufferQuoteIdentifier( buf, name, m_pSettings );
+ buf.append( " ON " );
+ bufferQuoteQualifiedIdentifier( buf, m_schemaName, m_tableName, m_pSettings );
+
+ buf.append( " ( " );
+
+ Reference< XColumnsSupplier > columns( descriptor, UNO_QUERY );
+ if( columns.is() )
+ {
+ Reference< XEnumerationAccess > access( columns->getColumns(), UNO_QUERY );
+ if( access.is() )
+ {
+ Reference< XEnumeration > xEnum( access->createEnumeration() );
+ bool first = true;
+ while( xEnum.is() && xEnum->hasMoreElements() )
+ {
+ Reference< XPropertySet > column( xEnum->nextElement(), UNO_QUERY );
+ if( first )
+ {
+ first = false;
+ }
+ else
+ {
+ buf.append( ", " );
+ }
+ buf.append( extractStringProperty( column, st.NAME ) );
+ }
+ }
+ }
+ buf.append( " ) " );
+
+ m_origin->createStatement()->executeUpdate( buf.makeStringAndClear() );
+ refresh();
+}
+
+void Indexes::dropByIndex( sal_Int32 index )
+{
+
+
+ osl::MutexGuard guard( m_xMutex->GetMutex() );
+ if( index < 0 || o3tl::make_unsigned(index) >= m_values.size() )
+ {
+ throw css::lang::IndexOutOfBoundsException(
+ "Indexes: Index out of range (allowed 0 to "
+ + OUString::number( m_values.size() -1 )
+ + ", got " + OUString::number( index )
+ + ")",
+ *this );
+ }
+
+ Reference< XPropertySet > set;
+ m_values[index] >>= set;
+ Statics &st = getStatics();
+
+ OUStringBuffer buf( 128 );
+ buf.append( "DROP INDEX " );
+ bufferQuoteIdentifier( buf, extractStringProperty( set, st.NAME ), m_pSettings );
+ m_origin->createStatement()->executeUpdate( buf.makeStringAndClear() );
+
+ Container::dropByIndex( index );
+}
+
+
+css::uno::Reference< css::beans::XPropertySet > Indexes::createDataDescriptor()
+{
+ return new IndexDescriptor( m_xMutex, m_origin, m_pSettings );
+}
+
+Reference< css::container::XNameAccess > Indexes::create(
+ const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex,
+ const css::uno::Reference< css::sdbc::XConnection > & origin,
+ ConnectionSettings *pSettings,
+ const OUString & schemaName,
+ const OUString & tableName)
+{
+ rtl::Reference<Indexes> pIndexes
+ = new Indexes( refMutex, origin, pSettings, schemaName, tableName );
+ pIndexes->refresh();
+ return pIndexes;
+}
+
+
+IndexDescriptors::IndexDescriptors(
+ const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex,
+ const css::uno::Reference< css::sdbc::XConnection > & origin,
+ ConnectionSettings *pSettings)
+ : Container( refMutex, origin, pSettings, getStatics().INDEX )
+{}
+
+Reference< css::container::XNameAccess > IndexDescriptors::create(
+ const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex,
+ const css::uno::Reference< css::sdbc::XConnection > & origin,
+ ConnectionSettings *pSettings)
+{
+ return new IndexDescriptors( refMutex, origin, pSettings );
+}
+
+css::uno::Reference< css::beans::XPropertySet > IndexDescriptors::createDataDescriptor()
+{
+ return new IndexDescriptor( m_xMutex, m_origin, m_pSettings );
+}
+
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/postgresql/pq_xindexes.hxx b/connectivity/source/drivers/postgresql/pq_xindexes.hxx
new file mode 100644
index 0000000000..536d17b961
--- /dev/null
+++ b/connectivity/source/drivers/postgresql/pq_xindexes.hxx
@@ -0,0 +1,102 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * Effective License of whole file:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011:
+ *
+ * The Contents of this file are made available subject to the terms of
+ * the GNU Lesser General Public License Version 2.1
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * Contributor(s): Joerg Budischewski
+ *
+ * All parts contributed on or after August 2011:
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ ************************************************************************/
+
+#pragma once
+
+#include "pq_xcontainer.hxx"
+
+namespace pq_sdbc_driver
+{
+class Indexes final : public Container
+{
+ OUString m_schemaName;
+ OUString m_tableName;
+
+public: // instances Columns 'exception safe'
+ static css::uno::Reference< css::container::XNameAccess > create(
+ const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex,
+ const css::uno::Reference< css::sdbc::XConnection > & origin,
+ ConnectionSettings *pSettings,
+ const OUString &schemaName,
+ const OUString &tableName);
+
+private:
+ Indexes(
+ const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex,
+ const css::uno::Reference< css::sdbc::XConnection > & origin,
+ ConnectionSettings *pSettings,
+ OUString schemaName,
+ OUString tableName);
+
+ virtual ~Indexes() override;
+
+public: // XAppend
+ virtual void SAL_CALL appendByDescriptor(
+ const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override;
+
+public: // XDrop
+ virtual void SAL_CALL dropByIndex( sal_Int32 index ) override;
+
+public: // XRefreshable
+ virtual void SAL_CALL refresh( ) override;
+
+public: // XDataDescriptorFactory
+ virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL createDataDescriptor( ) override;
+};
+
+
+class IndexDescriptors final : public Container
+{
+public: // instances IndexDescriptors 'exception safe'
+ static css::uno::Reference< css::container::XNameAccess > create(
+ const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex,
+ const css::uno::Reference< css::sdbc::XConnection > & origin,
+ ConnectionSettings *pSettings );
+
+private:
+ IndexDescriptors(
+ const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex,
+ const css::uno::Reference< css::sdbc::XConnection > & origin,
+ ConnectionSettings *pSettings );
+
+public: // XDataDescriptorFactory
+ virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL createDataDescriptor( ) override;
+
+};
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/postgresql/pq_xkey.cxx b/connectivity/source/drivers/postgresql/pq_xkey.cxx
new file mode 100644
index 0000000000..81d1f7a86e
--- /dev/null
+++ b/connectivity/source/drivers/postgresql/pq_xkey.cxx
@@ -0,0 +1,183 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * Effective License of whole file:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011:
+ *
+ * The Contents of this file are made available subject to the terms of
+ * the GNU Lesser General Public License Version 2.1
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * Contributor(s): Joerg Budischewski
+ *
+ * All parts contributed on or after August 2011:
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ ************************************************************************/
+
+#include <cppuhelper/typeprovider.hxx>
+#include <cppuhelper/queryinterface.hxx>
+#include <rtl/ref.hxx>
+#include <utility>
+
+#include "pq_xkey.hxx"
+#include "pq_xkeycolumns.hxx"
+#include "pq_statics.hxx"
+
+using com::sun::star::container::XNameAccess;
+
+using com::sun::star::uno::Reference;
+using com::sun::star::uno::Sequence;
+using com::sun::star::uno::Any;
+using com::sun::star::uno::Type;
+
+using com::sun::star::beans::XPropertySet;
+
+
+namespace pq_sdbc_driver
+{
+Key::Key( const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex,
+ const Reference< css::sdbc::XConnection > & connection,
+ ConnectionSettings *pSettings,
+ OUString schemaName,
+ OUString tableName )
+ : ReflectionBase(
+ getStatics().refl.key.implName,
+ getStatics().refl.key.serviceNames,
+ refMutex,
+ connection,
+ pSettings,
+ * getStatics().refl.key.pProps ),
+ m_schemaName(std::move( schemaName )),
+ m_tableName(std::move( tableName ))
+{}
+
+Reference< XPropertySet > Key::createDataDescriptor( )
+{
+ rtl::Reference<KeyDescriptor> pKeyDescriptor = new KeyDescriptor(
+ m_xMutex, m_conn, m_pSettings );
+ pKeyDescriptor->copyValuesFrom( this );
+
+ return Reference< XPropertySet > ( pKeyDescriptor );
+}
+
+Reference< XNameAccess > Key::getColumns( )
+{
+ // TODO: cash columns object !
+ if( !m_keyColumns.is() )
+ {
+ Sequence< OUString > columnNames, foreignColumnNames;
+ getPropertyValue( getStatics().PRIVATE_COLUMNS ) >>= columnNames;
+ getPropertyValue( getStatics().PRIVATE_FOREIGN_COLUMNS ) >>= foreignColumnNames;
+
+ m_keyColumns = KeyColumns::create(
+ m_xMutex, m_conn, m_pSettings, m_schemaName,
+ m_tableName, columnNames, foreignColumnNames );
+ }
+ return m_keyColumns;
+}
+
+Sequence<Type > Key::getTypes()
+{
+ static cppu::OTypeCollection collection(
+ cppu::UnoType<css::sdbcx::XColumnsSupplier>::get(),
+ ReflectionBase::getTypes());
+
+ return collection.getTypes();
+}
+
+Sequence< sal_Int8> Key::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+Any Key::queryInterface( const Type & reqType )
+{
+ Any ret = ReflectionBase::queryInterface( reqType );
+ if( ! ret.hasValue() )
+ ret = ::cppu::queryInterface(
+ reqType,
+ static_cast< css::sdbcx::XColumnsSupplier * > ( this ) );
+ return ret;
+}
+
+
+KeyDescriptor::KeyDescriptor( const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex,
+ const Reference< css::sdbc::XConnection > & connection,
+ ConnectionSettings *pSettings )
+ : ReflectionBase(
+ getStatics().refl.keyDescriptor.implName,
+ getStatics().refl.keyDescriptor.serviceNames,
+ refMutex,
+ connection,
+ pSettings,
+ * getStatics().refl.keyDescriptor.pProps )
+{
+}
+
+Reference< XPropertySet > KeyDescriptor::createDataDescriptor( )
+{
+ rtl::Reference<KeyDescriptor> pKeyDescriptor = new KeyDescriptor(
+ m_xMutex, m_conn, m_pSettings );
+ pKeyDescriptor->copyValuesFrom( this );
+
+ return Reference< XPropertySet > ( pKeyDescriptor );
+}
+
+Reference< XNameAccess > KeyDescriptor::getColumns( )
+{
+ // TODO: cash columns object !
+ if( !m_keyColumns.is() )
+ {
+ m_keyColumns = new KeyColumnDescriptors( m_xMutex, m_conn, m_pSettings );
+ }
+ return m_keyColumns;
+}
+
+Sequence<Type > KeyDescriptor::getTypes()
+{
+ static cppu::OTypeCollection collection(
+ cppu::UnoType<css::sdbcx::XColumnsSupplier>::get(),
+ ReflectionBase::getTypes());
+
+ return collection.getTypes();
+}
+
+Sequence< sal_Int8> KeyDescriptor::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+Any KeyDescriptor::queryInterface( const Type & reqType )
+{
+ Any ret = ReflectionBase::queryInterface( reqType );
+ if( ! ret.hasValue() )
+ ret = ::cppu::queryInterface(
+ reqType,
+ static_cast< css::sdbcx::XColumnsSupplier * > ( this ) );
+ return ret;
+}
+
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/postgresql/pq_xkey.hxx b/connectivity/source/drivers/postgresql/pq_xkey.hxx
new file mode 100644
index 0000000000..68f05fd27d
--- /dev/null
+++ b/connectivity/source/drivers/postgresql/pq_xkey.hxx
@@ -0,0 +1,119 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * Effective License of whole file:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011:
+ *
+ * The Contents of this file are made available subject to the terms of
+ * the GNU Lesser General Public License Version 2.1
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * Contributor(s): Joerg Budischewski
+ *
+ * All parts contributed on or after August 2011:
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ ************************************************************************/
+
+#pragma once
+
+#include <cppuhelper/component.hxx>
+#include <cppuhelper/propshlp.hxx>
+
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/sdbcx/XDataDescriptorFactory.hpp>
+#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
+
+#include "pq_connection.hxx"
+#include "pq_xbase.hxx"
+
+namespace pq_sdbc_driver
+{
+
+class Key : public ReflectionBase,
+ public css::sdbcx::XColumnsSupplier
+{
+ css::uno::Reference< css::container::XNameAccess > m_keyColumns;
+
+ OUString m_schemaName;
+ OUString m_tableName;
+
+public:
+ Key( const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex,
+ const css::uno::Reference< css::sdbc::XConnection > & connection,
+ ConnectionSettings *pSettings,
+ OUString schemaName,
+ OUString tableName);
+
+public: // XInterface
+ virtual void SAL_CALL acquire() noexcept override { ReflectionBase::acquire(); }
+ virtual void SAL_CALL release() noexcept override { ReflectionBase::release(); }
+ virtual css::uno::Any SAL_CALL queryInterface(
+ const css::uno::Type & reqType ) override;
+
+public: // XColumnsSupplier
+ virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL
+ getColumns( ) override;
+
+public: // XTypeProvider, first implemented by OPropertySetHelper
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override;
+ virtual css::uno::Sequence< sal_Int8> SAL_CALL getImplementationId() override;
+
+public: // XDataDescriptorFactory
+ virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL
+ createDataDescriptor( ) override;
+
+};
+
+
+class KeyDescriptor : public ReflectionBase, public css::sdbcx::XColumnsSupplier
+{
+ css::uno::Reference< css::container::XNameAccess > m_keyColumns;
+
+public:
+ KeyDescriptor( const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex,
+ const css::uno::Reference< css::sdbc::XConnection > & connection,
+ ConnectionSettings *pSettings );
+
+public: // XInterface
+ virtual void SAL_CALL acquire() noexcept override { ReflectionBase::acquire(); }
+ virtual void SAL_CALL release() noexcept override { ReflectionBase::release(); }
+ virtual css::uno::Any SAL_CALL queryInterface(
+ const css::uno::Type & reqType ) override;
+
+public: // XColumnsSupplier
+ virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL
+ getColumns( ) override;
+
+public: // XTypeProvider, first implemented by OPropertySetHelper
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override;
+ virtual css::uno::Sequence< sal_Int8> SAL_CALL getImplementationId() override;
+
+public: // XDataDescriptorFactory
+ virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL
+ createDataDescriptor( ) override;
+};
+
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/postgresql/pq_xkeycolumn.cxx b/connectivity/source/drivers/postgresql/pq_xkeycolumn.cxx
new file mode 100644
index 0000000000..30eef17971
--- /dev/null
+++ b/connectivity/source/drivers/postgresql/pq_xkeycolumn.cxx
@@ -0,0 +1,95 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * Effective License of whole file:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011:
+ *
+ * The Contents of this file are made available subject to the terms of
+ * the GNU Lesser General Public License Version 2.1
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * Contributor(s): Joerg Budischewski
+ *
+ * All parts contributed on or after August 2011:
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ ************************************************************************/
+
+#include <sal/config.h>
+
+#include <rtl/ref.hxx>
+
+#include "pq_statics.hxx"
+#include "pq_xkeycolumn.hxx"
+
+using com::sun::star::uno::Reference;
+
+using com::sun::star::beans::XPropertySet;
+
+namespace pq_sdbc_driver
+{
+KeyColumn::KeyColumn( const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex,
+ const Reference< css::sdbc::XConnection > & connection,
+ ConnectionSettings *pSettings)
+ : ReflectionBase(
+ getStatics().refl.keycolumn.implName,
+ getStatics().refl.keycolumn.serviceNames,
+ refMutex,
+ connection,
+ pSettings,
+ * getStatics().refl.keycolumn.pProps )
+{}
+
+Reference< XPropertySet > KeyColumn::createDataDescriptor( )
+{
+ rtl::Reference<KeyColumnDescriptor> pKeyColumn = new KeyColumnDescriptor(
+ m_xMutex, m_conn, m_pSettings );
+ pKeyColumn->copyValuesFrom( this );
+
+ return Reference< XPropertySet > ( pKeyColumn );
+}
+
+KeyColumnDescriptor::KeyColumnDescriptor(
+ const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex,
+ const Reference< css::sdbc::XConnection > & connection,
+ ConnectionSettings *pSettings)
+ : ReflectionBase(
+ getStatics().refl.keycolumnDescriptor.implName,
+ getStatics().refl.keycolumnDescriptor.serviceNames,
+ refMutex,
+ connection,
+ pSettings,
+ * getStatics().refl.keycolumnDescriptor.pProps )
+{}
+
+Reference< XPropertySet > KeyColumnDescriptor::createDataDescriptor( )
+{
+ rtl::Reference<KeyColumnDescriptor> pKeyColumn = new KeyColumnDescriptor(
+ m_xMutex, m_conn, m_pSettings );
+ pKeyColumn->copyValuesFrom( this );
+
+ return Reference< XPropertySet > ( pKeyColumn );
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/postgresql/pq_xkeycolumn.hxx b/connectivity/source/drivers/postgresql/pq_xkeycolumn.hxx
new file mode 100644
index 0000000000..7d49d5d265
--- /dev/null
+++ b/connectivity/source/drivers/postgresql/pq_xkeycolumn.hxx
@@ -0,0 +1,82 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * Effective License of whole file:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011:
+ *
+ * The Contents of this file are made available subject to the terms of
+ * the GNU Lesser General Public License Version 2.1
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * Contributor(s): Joerg Budischewski
+ *
+ * All parts contributed on or after August 2011:
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ ************************************************************************/
+
+#pragma once
+
+#include <cppuhelper/component.hxx>
+#include <cppuhelper/propshlp.hxx>
+
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/sdbcx/XDataDescriptorFactory.hpp>
+
+#include "pq_connection.hxx"
+#include "pq_xbase.hxx"
+
+namespace pq_sdbc_driver
+{
+
+class KeyColumn : public ReflectionBase
+{
+public:
+ KeyColumn( const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex,
+ const css::uno::Reference< css::sdbc::XConnection > & connection,
+ ConnectionSettings *pSettings);
+
+public: // XDataDescriptorFactory
+ virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL
+ createDataDescriptor( ) override;
+
+};
+
+class KeyColumnDescriptor : public ReflectionBase
+{
+public:
+ KeyColumnDescriptor(
+ const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex,
+ const css::uno::Reference< css::sdbc::XConnection > & connection,
+ ConnectionSettings *pSettings);
+
+public: // XDataDescriptorFactory
+ virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL
+ createDataDescriptor( ) override;
+
+};
+
+
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/postgresql/pq_xkeycolumns.cxx b/connectivity/source/drivers/postgresql/pq_xkeycolumns.cxx
new file mode 100644
index 0000000000..97e0ef29bb
--- /dev/null
+++ b/connectivity/source/drivers/postgresql/pq_xkeycolumns.cxx
@@ -0,0 +1,239 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * Effective License of whole file:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011:
+ *
+ * The Contents of this file are made available subject to the terms of
+ * the GNU Lesser General Public License Version 2.1
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * Contributor(s): Joerg Budischewski
+ *
+ * All parts contributed on or after August 2011:
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ ************************************************************************/
+
+#include <sal/log.hxx>
+#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <cppuhelper/exc_hlp.hxx>
+#include <rtl/ref.hxx>
+#include <utility>
+
+#include "pq_xcolumns.hxx"
+#include "pq_xkeycolumns.hxx"
+#include "pq_xkeycolumn.hxx"
+#include "pq_statics.hxx"
+#include "pq_tools.hxx"
+
+using osl::MutexGuard;
+
+using com::sun::star::beans::XPropertySet;
+
+using com::sun::star::uno::Any;
+using com::sun::star::uno::UNO_QUERY;
+using com::sun::star::uno::Reference;
+using com::sun::star::uno::Sequence;
+
+using com::sun::star::sdbc::XRow;
+using com::sun::star::sdbc::XResultSet;
+using com::sun::star::sdbc::XDatabaseMetaData;
+using com::sun::star::sdbc::SQLException;
+
+namespace pq_sdbc_driver
+{
+
+KeyColumns::KeyColumns(
+ const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex,
+ const css::uno::Reference< css::sdbc::XConnection > & origin,
+ ConnectionSettings *pSettings,
+ OUString schemaName,
+ OUString tableName,
+ const Sequence< OUString > &columnNames,
+ const Sequence< OUString > &foreignColumnNames )
+ : Container( refMutex, origin, pSettings, "KEY_COLUMN" ),
+ m_schemaName(std::move( schemaName )),
+ m_tableName(std::move( tableName )),
+ m_columnNames( columnNames ),
+ m_foreignColumnNames( foreignColumnNames )
+{}
+
+KeyColumns::~KeyColumns()
+{}
+
+
+void KeyColumns::refresh()
+{
+ try
+ {
+ SAL_INFO("connectivity.postgresql", "sdbcx.KeyColumns get refreshed for table " << m_schemaName << "." << m_tableName);
+
+ osl::MutexGuard guard( m_xMutex->GetMutex() );
+
+ Statics &st = getStatics();
+ Reference< XDatabaseMetaData > meta = m_origin->getMetaData();
+
+ Reference< XResultSet > rs =
+ meta->getColumns( Any(), m_schemaName, m_tableName, st.cPERCENT );
+
+ DisposeGuard disposeIt( rs );
+ Reference< XRow > xRow( rs , UNO_QUERY );
+
+ String2IntMap map;
+
+ m_values.clear();
+ sal_Int32 columnIndex = 0;
+ while( rs->next() )
+ {
+ OUString columnName = xRow->getString( 4 );
+
+ int keyindex;
+ for( keyindex = 0 ; keyindex < m_columnNames.getLength() ; keyindex ++ )
+ {
+ if( columnName == m_columnNames[keyindex] )
+ break;
+ }
+ if( m_columnNames.getLength() == keyindex )
+ continue;
+
+ rtl::Reference<KeyColumn> pKeyColumn =
+ new KeyColumn( m_xMutex, m_origin, m_pSettings );
+ Reference< css::beans::XPropertySet > prop = pKeyColumn;
+
+ OUString name = columnMetaData2SDBCX( pKeyColumn.get(), xRow );
+ if( keyindex < m_foreignColumnNames.getLength() )
+ {
+ pKeyColumn->setPropertyValue_NoBroadcast_public(
+ st.RELATED_COLUMN, Any( m_foreignColumnNames[keyindex]) );
+ }
+
+ {
+ m_values.push_back( Any( prop ) );
+ map[ name ] = columnIndex;
+ ++columnIndex;
+ }
+ }
+ m_name2index.swap( map );
+ }
+ catch ( css::sdbc::SQLException & e )
+ {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ throw css::lang::WrappedTargetRuntimeException( e.Message,
+ e.Context, anyEx );
+ }
+
+ fire( RefreshedBroadcaster( *this ) );
+}
+
+
+void KeyColumns::appendByDescriptor(
+ const css::uno::Reference< css::beans::XPropertySet >& )
+{
+ throw css::sdbc::SQLException(
+ "KeyColumns::appendByDescriptor not implemented yet",
+ *this, OUString(), 1, Any() );
+
+// osl::MutexGuard guard( m_xMutex->GetMutex() );
+// Statics & st = getStatics();
+// Reference< XPropertySet > past = createDataDescriptor();
+// past->setPropertyValue( st.IS_NULLABLE, makeAny( css::sdbc::ColumnValue::NULLABLE ) );
+// alterColumnByDescriptor(
+// m_schemaName, m_tableName, m_pSettings->encoding, m_origin->createStatement() , past, future );
+
+}
+
+
+void KeyColumns::dropByIndex( sal_Int32 )
+{
+ throw css::sdbc::SQLException(
+ "KeyColumns::dropByIndex not implemented yet",
+ *this, OUString(), 1, Any() );
+// osl::MutexGuard guard( m_xMutex->GetMutex() );
+// if( index < 0 || index >= m_values.getLength() )
+// {
+// OUStringBuffer buf( 128 );
+// buf.appendAscii( "COLUMNS: Index out of range (allowed 0 to " );
+// buf.append((sal_Int32)(m_values.getLength() -1) );
+// buf.appendAscii( ", got " );
+// buf.append( index );
+// buf.appendAscii( ")" );
+// throw css::lang::IndexOutOfBoundsException(
+// buf.makeStringAndClear(), *this );
+// }
+
+// Reference< XPropertySet > set;
+// m_values[index] >>= set;
+// Statics &st = getStatics();
+// OUString name;
+// set->getPropertyValue( st.NAME ) >>= name;
+
+// OUStringBuffer update( 128 );
+// update.appendAscii( "ALTER TABLE ONLY");
+// bufferQuoteQualifiedIdentifier( update, m_schemaName, m_tableName );
+// update.appendAscii( "DROP COLUMN" );
+// bufferQuoteIdentifier( update, name );
+// Reference< XStatement > stmt = m_origin->createStatement( );
+// DisposeGuard disposeIt( stmt );
+// stmt->executeUpdate( update.makeStringAndClear() );
+
+}
+
+
+Reference< css::beans::XPropertySet > KeyColumns::createDataDescriptor()
+{
+ return new KeyColumnDescriptor( m_xMutex, m_origin, m_pSettings );
+}
+
+Reference< css::container::XNameAccess > KeyColumns::create(
+ const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex,
+ const css::uno::Reference< css::sdbc::XConnection > & origin,
+ ConnectionSettings *pSettings,
+ const OUString &schemaName,
+ const OUString &tableName,
+ const Sequence< OUString > &columnNames ,
+ const Sequence< OUString > &foreignColumnNames )
+{
+ rtl::Reference<KeyColumns> pKeyColumns = new KeyColumns(
+ refMutex, origin, pSettings, schemaName, tableName, columnNames, foreignColumnNames );
+ pKeyColumns->refresh();
+
+ return pKeyColumns;
+}
+
+
+KeyColumnDescriptors::KeyColumnDescriptors(
+ const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex,
+ const css::uno::Reference< css::sdbc::XConnection > & origin,
+ ConnectionSettings *pSettings )
+ : Container( refMutex, origin, pSettings, "KEY_COLUMN" )
+{}
+
+Reference< css::beans::XPropertySet > KeyColumnDescriptors::createDataDescriptor()
+{
+ return new KeyColumnDescriptor( m_xMutex, m_origin, m_pSettings );
+}
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/postgresql/pq_xkeycolumns.hxx b/connectivity/source/drivers/postgresql/pq_xkeycolumns.hxx
new file mode 100644
index 0000000000..60bbd0c0de
--- /dev/null
+++ b/connectivity/source/drivers/postgresql/pq_xkeycolumns.hxx
@@ -0,0 +1,101 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * Effective License of whole file:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011:
+ *
+ * The Contents of this file are made available subject to the terms of
+ * the GNU Lesser General Public License Version 2.1
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * Contributor(s): Joerg Budischewski
+ *
+ * All parts contributed on or after August 2011:
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ ************************************************************************/
+
+#pragma once
+
+#include "pq_xcontainer.hxx"
+
+namespace pq_sdbc_driver
+{
+
+class KeyColumns final : public Container
+{
+ OUString m_schemaName;
+ OUString m_tableName;
+ css::uno::Sequence< OUString > m_columnNames;
+ css::uno::Sequence< OUString > m_foreignColumnNames;
+
+public: // instances KeyColumns 'exception safe'
+ static css::uno::Reference< css::container::XNameAccess > create(
+ const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex,
+ const css::uno::Reference< css::sdbc::XConnection > & origin,
+ ConnectionSettings *pSettings,
+ const OUString &schemaName,
+ const OUString &tableName,
+ const css::uno::Sequence< OUString > &keyColumns,
+ const css::uno::Sequence< OUString > &foreignColumnNames );
+
+private:
+ KeyColumns(
+ const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex,
+ const css::uno::Reference< css::sdbc::XConnection > & origin,
+ ConnectionSettings *pSettings,
+ OUString schemaName,
+ OUString tableName,
+ const css::uno::Sequence< OUString > &keyColumns,
+ const css::uno::Sequence< OUString > &foreignColumnNames);
+
+ virtual ~KeyColumns() override;
+
+public: // XAppend
+ virtual void SAL_CALL appendByDescriptor(
+ const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override;
+
+public: // XDrop
+ virtual void SAL_CALL dropByIndex( sal_Int32 index ) override;
+
+public: // XRefreshable
+ virtual void SAL_CALL refresh( ) override;
+
+public: // XDataDescriptorFactory
+ virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL createDataDescriptor( ) override;
+};
+
+
+class KeyColumnDescriptors : public Container
+{
+public:
+ KeyColumnDescriptors(
+ const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex,
+ const css::uno::Reference< css::sdbc::XConnection > & origin,
+ ConnectionSettings *pSettings);
+
+public: // XDataDescriptorFactory
+ virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL createDataDescriptor( ) override;
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/postgresql/pq_xkeys.cxx b/connectivity/source/drivers/postgresql/pq_xkeys.cxx
new file mode 100644
index 0000000000..0758be630e
--- /dev/null
+++ b/connectivity/source/drivers/postgresql/pq_xkeys.cxx
@@ -0,0 +1,295 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * Effective License of whole file:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011:
+ *
+ * The Contents of this file are made available subject to the terms of
+ * the GNU Lesser General Public License Version 2.1
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * Contributor(s): Joerg Budischewski
+ *
+ * All parts contributed on or after August 2011:
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ ************************************************************************/
+
+#include <sal/config.h>
+
+#include <string_view>
+
+#include <sal/log.hxx>
+#include <rtl/ref.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XParameters.hpp>
+#include <com/sun/star/sdbc/KeyRule.hpp>
+#include <com/sun/star/sdbcx/KeyType.hpp>
+#include <cppuhelper/exc_hlp.hxx>
+#include <o3tl/safeint.hxx>
+#include <utility>
+
+#include "pq_xkeys.hxx"
+#include "pq_xkey.hxx"
+#include "pq_statics.hxx"
+#include "pq_tools.hxx"
+
+using osl::MutexGuard;
+
+
+using css::beans::XPropertySet;
+
+using com::sun::star::uno::Any;
+using com::sun::star::uno::UNO_QUERY;
+using com::sun::star::uno::Reference;
+
+
+using com::sun::star::sdbc::XRow;
+using com::sun::star::sdbc::XStatement;
+using com::sun::star::sdbc::XResultSet;
+using com::sun::star::sdbc::XParameters;
+using com::sun::star::sdbc::XPreparedStatement;
+
+namespace pq_sdbc_driver
+{
+
+Keys::Keys(
+ const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex,
+ const css::uno::Reference< css::sdbc::XConnection > & origin,
+ ConnectionSettings *pSettings,
+ OUString schemaName,
+ OUString tableName)
+ : Container( refMutex, origin, pSettings, getStatics().KEY ),
+ m_schemaName(std::move( schemaName )),
+ m_tableName(std::move( tableName ))
+{}
+
+Keys::~Keys()
+{}
+
+static sal_Int32 string2keytype( std::u16string_view type )
+{
+ sal_Int32 ret = css::sdbcx::KeyType::UNIQUE;
+ if ( type == u"p" )
+ ret = css::sdbcx::KeyType::PRIMARY;
+ else if ( type == u"f" )
+ ret = css::sdbcx::KeyType::FOREIGN;
+ return ret;
+}
+
+static sal_Int32 string2keyrule( std::u16string_view rule )
+{
+ sal_Int32 ret = css::sdbc::KeyRule::NO_ACTION;
+ if( rule == u"r" )
+ ret = css::sdbc::KeyRule::RESTRICT;
+ else if( rule == u"c" )
+ ret = css::sdbc::KeyRule::CASCADE;
+ else if( rule == u"n" )
+ ret = css::sdbc::KeyRule::SET_NULL;
+ else if( rule == u"d" )
+ ret = css::sdbc::KeyRule::SET_DEFAULT;
+ return ret;
+}
+
+void Keys::refresh()
+{
+ try
+ {
+ SAL_INFO("connectivity.postgresql", "sdbcx.Keys get refreshed for table " << m_schemaName << "." << m_tableName);
+
+ osl::MutexGuard guard( m_xMutex->GetMutex() );
+ Statics & st = getStatics();
+
+ Int2StringMap mainMap;
+ fillAttnum2attnameMap( mainMap, m_origin, m_schemaName, m_tableName );
+
+ Reference< XPreparedStatement > stmt = m_origin->prepareStatement(
+ "SELECT conname, " // 1
+ "contype, " // 2
+ "confupdtype, " // 3
+ "confdeltype, " // 4
+ "class2.relname, " // 5
+ "nmsp2.nspname, " // 6
+ "conkey," // 7
+ "confkey " // 8
+ "FROM pg_constraint INNER JOIN pg_class ON conrelid = pg_class.oid "
+ "INNER JOIN pg_namespace ON pg_class.relnamespace = pg_namespace.oid "
+ "LEFT JOIN pg_class AS class2 ON confrelid = class2.oid "
+ "LEFT JOIN pg_namespace AS nmsp2 ON class2.relnamespace=nmsp2.oid "
+ "WHERE pg_class.relname = ? AND pg_namespace.nspname = ?" );
+
+ Reference< XParameters > paras( stmt, UNO_QUERY );
+ paras->setString( 1 , m_tableName );
+ paras->setString( 2 , m_schemaName );
+ Reference< XResultSet > rs = stmt->executeQuery();
+
+ Reference< XRow > xRow( rs , UNO_QUERY );
+
+ String2IntMap map;
+ m_values.clear();
+ int keyIndex = 0;
+ while( rs->next() )
+ {
+ rtl::Reference<Key> pKey =
+ new Key( m_xMutex, m_origin, m_pSettings , m_schemaName, m_tableName );
+ Reference< css::beans::XPropertySet > prop = pKey;
+
+ pKey->setPropertyValue_NoBroadcast_public(
+ st.NAME, Any( xRow->getString( 1 ) ) );
+ sal_Int32 keyType = string2keytype( xRow->getString(2) );
+ pKey->setPropertyValue_NoBroadcast_public( st.TYPE, Any( keyType ) );
+ pKey->setPropertyValue_NoBroadcast_public(
+ st.UPDATE_RULE, Any( string2keyrule( xRow->getString(3) ) ) );
+ pKey->setPropertyValue_NoBroadcast_public(
+ st.DELETE_RULE, Any( string2keyrule( xRow->getString(4) ) ) );
+ pKey->setPropertyValue_NoBroadcast_public(
+ st.PRIVATE_COLUMNS,
+ Any(
+ convertMappedIntArray2StringArray(
+ mainMap,
+ string2intarray( xRow->getString( 7 ) ) ) ) );
+
+ if( css::sdbcx::KeyType::FOREIGN == keyType )
+ {
+ OUString buf = xRow->getString( 6 ) + "." + xRow->getString( 5 );
+ pKey->setPropertyValue_NoBroadcast_public(
+ st.REFERENCED_TABLE, Any( buf ) );
+
+ Int2StringMap foreignMap;
+ fillAttnum2attnameMap( foreignMap, m_origin, xRow->getString(6), xRow->getString(5));
+ pKey->setPropertyValue_NoBroadcast_public(
+ st.PRIVATE_FOREIGN_COLUMNS,
+ Any(
+ convertMappedIntArray2StringArray(
+ foreignMap,
+ string2intarray( xRow->getString(8) ) ) ) );
+ }
+
+
+ {
+ map[ xRow->getString( 1 ) ] = keyIndex;
+ m_values.push_back( Any( prop ) );
+ ++keyIndex;
+ }
+ }
+ m_name2index.swap( map );
+ }
+ catch ( css::sdbc::SQLException & e )
+ {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ throw css::lang::WrappedTargetRuntimeException( e.Message,
+ e.Context, anyEx );
+ }
+
+ fire( RefreshedBroadcaster( *this ) );
+}
+
+
+void Keys::appendByDescriptor(
+ const css::uno::Reference< css::beans::XPropertySet >& descriptor )
+{
+ osl::MutexGuard guard( m_xMutex->GetMutex() );
+
+ OUStringBuffer buf( 128 );
+ buf.append( "ALTER TABLE " );
+ bufferQuoteQualifiedIdentifier( buf, m_schemaName, m_tableName, m_pSettings );
+ buf.append( " ADD " );
+ bufferKey2TableConstraint( buf, descriptor, m_pSettings );
+
+ Reference< XStatement > stmt =
+ m_origin->createStatement();
+ stmt->executeUpdate( buf.makeStringAndClear() );
+}
+
+
+void Keys::dropByIndex( sal_Int32 index )
+{
+ osl::MutexGuard guard( m_xMutex->GetMutex() );
+ if( index < 0 || o3tl::make_unsigned(index) >= m_values.size() )
+ {
+ throw css::lang::IndexOutOfBoundsException(
+ "TABLES: Index out of range (allowed 0 to " + OUString::number(m_values.size() -1)
+ + ", got " + OUString::number( index ) + ")",
+ *this );
+ }
+
+
+ Reference< XPropertySet > set;
+ m_values[index] >>= set;
+
+ OUStringBuffer buf( 128 );
+ buf.append( "ALTER TABLE " );
+ bufferQuoteQualifiedIdentifier( buf, m_schemaName, m_tableName, m_pSettings );
+ buf.append( " DROP CONSTRAINT " );
+ bufferQuoteIdentifier( buf, extractStringProperty( set , getStatics().NAME ), m_pSettings );
+ m_origin->createStatement()->executeUpdate( buf.makeStringAndClear() );
+
+
+ Container::dropByIndex( index );
+}
+
+
+css::uno::Reference< css::beans::XPropertySet > Keys::createDataDescriptor()
+{
+ return new KeyDescriptor( m_xMutex, m_origin, m_pSettings );
+}
+
+Reference< css::container::XIndexAccess > Keys::create(
+ const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex,
+ const css::uno::Reference< css::sdbc::XConnection > & origin,
+ ConnectionSettings *pSettings,
+ const OUString & schemaName,
+ const OUString & tableName)
+{
+ rtl::Reference<Keys> pKeys = new Keys( refMutex, origin, pSettings, schemaName, tableName );
+ pKeys->refresh();
+
+ return pKeys;
+}
+
+KeyDescriptors::KeyDescriptors(
+ const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex,
+ const css::uno::Reference< css::sdbc::XConnection > & origin,
+ ConnectionSettings *pSettings)
+ : Container( refMutex, origin, pSettings, getStatics().KEY )
+{}
+
+Reference< css::container::XIndexAccess > KeyDescriptors::create(
+ const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex,
+ const css::uno::Reference< css::sdbc::XConnection > & origin,
+ ConnectionSettings *pSettings)
+{
+ return new KeyDescriptors( refMutex, origin, pSettings );
+}
+
+css::uno::Reference< css::beans::XPropertySet > KeyDescriptors::createDataDescriptor()
+{
+ return new KeyDescriptor( m_xMutex, m_origin, m_pSettings );
+}
+
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/postgresql/pq_xkeys.hxx b/connectivity/source/drivers/postgresql/pq_xkeys.hxx
new file mode 100644
index 0000000000..ef6376d4d7
--- /dev/null
+++ b/connectivity/source/drivers/postgresql/pq_xkeys.hxx
@@ -0,0 +1,101 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * Effective License of whole file:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011:
+ *
+ * The Contents of this file are made available subject to the terms of
+ * the GNU Lesser General Public License Version 2.1
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * Contributor(s): Joerg Budischewski
+ *
+ * All parts contributed on or after August 2011:
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ ************************************************************************/
+
+#pragma once
+
+#include "pq_xcontainer.hxx"
+
+namespace pq_sdbc_driver
+{
+class Keys final : public Container
+{
+ OUString m_schemaName;
+ OUString m_tableName;
+
+public: // instances Columns 'exception safe'
+ static css::uno::Reference< css::container::XIndexAccess > create(
+ const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex,
+ const css::uno::Reference< css::sdbc::XConnection > & origin,
+ ConnectionSettings *pSettings,
+ const OUString &schemaName,
+ const OUString &tableName);
+
+private:
+ Keys(
+ const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex,
+ const css::uno::Reference< css::sdbc::XConnection > & origin,
+ ConnectionSettings *pSettings,
+ OUString schemaName,
+ OUString tableName);
+
+ virtual ~Keys() override;
+
+public: // XAppend
+ virtual void SAL_CALL appendByDescriptor(
+ const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override;
+
+public: // XDrop
+ virtual void SAL_CALL dropByIndex( sal_Int32 index ) override;
+
+public: // XRefreshable
+ virtual void SAL_CALL refresh( ) override;
+
+public: // XDataDescriptorFactory
+ virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL createDataDescriptor( ) override;
+};
+
+
+class KeyDescriptors final : public Container
+{
+public: // instances Columns 'exception safe'
+ static css::uno::Reference< css::container::XIndexAccess > create(
+ const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex,
+ const css::uno::Reference< css::sdbc::XConnection > & origin,
+ ConnectionSettings *pSettings );
+
+private:
+ KeyDescriptors(
+ const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex,
+ const css::uno::Reference< css::sdbc::XConnection > & origin,
+ ConnectionSettings *pSettings );
+
+public: // XDataDescriptorFactory
+ virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL createDataDescriptor( ) override;
+};
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/postgresql/pq_xtable.cxx b/connectivity/source/drivers/postgresql/pq_xtable.cxx
new file mode 100644
index 0000000000..de8196f9fe
--- /dev/null
+++ b/connectivity/source/drivers/postgresql/pq_xtable.cxx
@@ -0,0 +1,393 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * Effective License of whole file:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011:
+ *
+ * The Contents of this file are made available subject to the terms of
+ * the GNU Lesser General Public License Version 2.1
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * Contributor(s): Joerg Budischewski
+ *
+ * All parts contributed on or after August 2011:
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ ************************************************************************/
+
+#include <rtl/ref.hxx>
+#include <rtl/ustrbuf.hxx>
+
+#include <cppuhelper/typeprovider.hxx>
+#include <cppuhelper/queryinterface.hxx>
+
+#include <com/sun/star/sdbc/SQLException.hpp>
+
+#include "pq_xtable.hxx"
+#include "pq_xtables.hxx"
+#include "pq_xviews.hxx"
+#include "pq_xindexes.hxx"
+#include "pq_xkeys.hxx"
+#include "pq_xcolumns.hxx"
+#include "pq_tools.hxx"
+#include "pq_statics.hxx"
+
+using osl::MutexGuard;
+
+using com::sun::star::container::XNameAccess;
+using com::sun::star::container::XIndexAccess;
+
+using com::sun::star::uno::Reference;
+using com::sun::star::uno::UNO_QUERY;
+using com::sun::star::uno::Sequence;
+using com::sun::star::uno::Any;
+using com::sun::star::uno::Type;
+
+using com::sun::star::beans::XPropertySet;
+
+using com::sun::star::sdbc::XStatement;
+using com::sun::star::sdbc::SQLException;
+
+namespace pq_sdbc_driver
+{
+Table::Table( const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex,
+ const Reference< css::sdbc::XConnection > & connection,
+ ConnectionSettings *pSettings)
+ : ReflectionBase(
+ getStatics().refl.table.implName,
+ getStatics().refl.table.serviceNames,
+ refMutex,
+ connection,
+ pSettings,
+ * getStatics().refl.table.pProps )
+{}
+
+Reference< XPropertySet > Table::createDataDescriptor( )
+{
+ rtl::Reference<TableDescriptor> pTable = new TableDescriptor(
+ m_xMutex, m_conn, m_pSettings );
+ pTable->copyValuesFrom( this );
+
+ return Reference< XPropertySet > ( pTable );
+}
+
+Reference< XNameAccess > Table::getColumns( )
+{
+ if( ! m_columns.is() )
+ {
+ m_columns = Columns::create(
+ m_xMutex,
+ m_conn,
+ m_pSettings,
+ extractStringProperty( this, getStatics().SCHEMA_NAME ),
+ extractStringProperty( this, getStatics().NAME ),
+ &m_pColumns);
+ }
+ return m_columns;
+}
+
+Reference< XNameAccess > Table::getIndexes()
+{
+ if( ! m_indexes.is() )
+ {
+ m_indexes = ::pq_sdbc_driver::Indexes::create(
+ m_xMutex,
+ m_conn,
+ m_pSettings,
+ extractStringProperty( this, getStatics().SCHEMA_NAME ),
+ extractStringProperty( this, getStatics().NAME ) );
+ }
+ return m_indexes;
+}
+
+Reference< XIndexAccess > Table::getKeys( )
+{
+ if( ! m_keys.is() )
+ {
+ m_keys = ::pq_sdbc_driver::Keys::create(
+ m_xMutex,
+ m_conn,
+ m_pSettings,
+ extractStringProperty( this, getStatics().SCHEMA_NAME ),
+ extractStringProperty( this, getStatics().NAME ) );
+ }
+ return m_keys;
+}
+
+void Table::rename( const OUString& newName )
+{
+ MutexGuard guard( m_xMutex->GetMutex() );
+ Statics & st = getStatics();
+
+ OUString oldName = extractStringProperty(this,st.NAME );
+ OUString schema = extractStringProperty(this,st.SCHEMA_NAME );
+ OUString fullOldName = concatQualified( schema, oldName );
+
+ OUString newTableName;
+ OUString newSchemaName;
+ // OOo2.0 passes schema + dot + new-table-name while
+ // OO1.1.x passes new Name without schema
+ // in case name contains a dot, it is interpreted as schema.tablename
+ if( newName.indexOf( '.' ) >= 0 )
+ {
+ splitConcatenatedIdentifier( newName, &newSchemaName, &newTableName );
+ }
+ else
+ {
+ newTableName = newName;
+ newSchemaName = schema;
+ }
+ OUString fullNewName = concatQualified( newSchemaName, newTableName );
+
+ if( extractStringProperty( this, st.TYPE ) == st.VIEW && m_pSettings->views.is() )
+ {
+ // maintain view list (really strange API !)
+ Any a = m_pSettings->pViewsImpl->getByName( fullOldName );
+ Reference< css::sdbcx::XRename > Xrename;
+ a >>= Xrename;
+ if( Xrename.is() )
+ {
+ Xrename->rename( newName );
+ setPropertyValue_NoBroadcast_public( st.SCHEMA_NAME, Any(newSchemaName) );
+ }
+ }
+ else
+ {
+ if( newSchemaName != schema )
+ {
+ // try new schema name first
+ try
+ {
+ OUStringBuffer buf(128);
+ buf.append( "ALTER TABLE" );
+ bufferQuoteQualifiedIdentifier(buf, schema, oldName, m_pSettings );
+ buf.append( "SET SCHEMA" );
+ bufferQuoteIdentifier( buf, newSchemaName, m_pSettings );
+ Reference< XStatement > statement = m_conn->createStatement();
+ statement->executeUpdate( buf.makeStringAndClear() );
+ setPropertyValue_NoBroadcast_public( st.SCHEMA_NAME, Any(newSchemaName) );
+ disposeNoThrow( statement );
+ schema = newSchemaName;
+ }
+ catch( css::sdbc::SQLException &e )
+ {
+ e.Message += "(NOTE: Only postgresql server >= V8.1 support changing a table's schema)";
+ throw;
+ }
+
+ }
+ if( newTableName != oldName ) // might also be just the change of a schema name
+ {
+ OUStringBuffer buf(128);
+ buf.append( "ALTER TABLE" );
+ bufferQuoteQualifiedIdentifier(buf, schema, oldName, m_pSettings );
+ buf.append( "RENAME TO" );
+ bufferQuoteIdentifier( buf, newTableName, m_pSettings );
+ Reference< XStatement > statement = m_conn->createStatement();
+ statement->executeUpdate( buf.makeStringAndClear() );
+ disposeNoThrow( statement );
+ }
+ }
+ setPropertyValue_NoBroadcast_public( st.NAME, Any(newTableName) );
+ // inform the container of the name change !
+ if( m_pSettings->tables.is() )
+ {
+ m_pSettings->pTablesImpl->rename( fullOldName, fullNewName );
+ }
+}
+
+void Table::alterColumnByName(
+ const OUString& colName,
+ const Reference< XPropertySet >& descriptor )
+{
+ Reference< css::container::XNameAccess > columns = getColumns();
+
+ OUString newName = extractStringProperty(descriptor, getStatics().NAME );
+ ::pq_sdbc_driver::alterColumnByDescriptor(
+ extractStringProperty( this, getStatics().SCHEMA_NAME ),
+ extractStringProperty( this, getStatics().NAME ),
+ m_pSettings,
+ m_conn->createStatement(),
+ Reference< css::beans::XPropertySet>( columns->getByName( colName ), UNO_QUERY) ,
+ descriptor );
+
+ if( colName != newName )
+ {
+// m_pColumns->rename( colName, newName );
+ m_pColumns->refresh();
+ }
+}
+
+void Table::alterColumnByIndex(
+ sal_Int32 index,
+ const css::uno::Reference< css::beans::XPropertySet >& descriptor )
+{
+ Reference< css::container::XIndexAccess > columns( getColumns(), UNO_QUERY );
+ Reference< css::beans::XPropertySet> column(columns->getByIndex( index ), UNO_QUERY );
+ ::pq_sdbc_driver::alterColumnByDescriptor(
+ extractStringProperty( this, getStatics().SCHEMA_NAME ),
+ extractStringProperty( this, getStatics().NAME ),
+ m_pSettings,
+ m_conn->createStatement(),
+ column,
+ descriptor );
+ m_pColumns->refresh();
+}
+
+Sequence<Type > Table::getTypes()
+{
+ static cppu::OTypeCollection collection(
+ cppu::UnoType<css::sdbcx::XIndexesSupplier>::get(),
+ cppu::UnoType<css::sdbcx::XKeysSupplier>::get(),
+ cppu::UnoType<css::sdbcx::XColumnsSupplier>::get(),
+ cppu::UnoType<css::sdbcx::XRename>::get(),
+ cppu::UnoType<css::sdbcx::XAlterTable>::get(),
+ ReflectionBase::getTypes());
+
+ return collection.getTypes();
+}
+
+Sequence< sal_Int8> Table::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+Any Table::queryInterface( const Type & reqType )
+{
+ Any ret = ReflectionBase::queryInterface( reqType );
+ if( ! ret.hasValue() )
+ ret = ::cppu::queryInterface(
+ reqType,
+ static_cast< css::sdbcx::XIndexesSupplier * > ( this ),
+ static_cast< css::sdbcx::XKeysSupplier * > ( this ),
+ static_cast< css::sdbcx::XColumnsSupplier * > ( this ),
+ static_cast< css::sdbcx::XRename * > ( this ),
+ static_cast< css::sdbcx::XAlterTable * > ( this )
+ );
+ return ret;
+}
+
+OUString Table::getName( )
+{
+ Statics & st = getStatics();
+ return concatQualified(
+ extractStringProperty( this, st.SCHEMA_NAME ),
+ extractStringProperty( this, st.NAME ) );
+}
+
+void Table::setName( const OUString& aName )
+{
+ rename( aName );
+}
+
+
+TableDescriptor::TableDescriptor(
+ const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex,
+ const Reference< css::sdbc::XConnection > & connection,
+ ConnectionSettings *pSettings)
+ : ReflectionBase(
+ getStatics().refl.tableDescriptor.implName,
+ getStatics().refl.tableDescriptor.serviceNames,
+ refMutex,
+ connection,
+ pSettings,
+ * getStatics().refl.tableDescriptor.pProps )
+{
+}
+
+Reference< XNameAccess > TableDescriptor::getColumns( )
+{
+ if( ! m_columns.is() )
+ {
+ m_columns = new ColumnDescriptors(m_xMutex, m_conn, m_pSettings );
+ }
+ return m_columns;
+}
+
+Reference< XNameAccess > TableDescriptor::getIndexes()
+{
+ if( ! m_indexes.is() )
+ {
+ m_indexes = ::pq_sdbc_driver::IndexDescriptors::create(
+ m_xMutex,
+ m_conn,
+ m_pSettings);
+ }
+ return m_indexes;
+}
+
+Reference< XIndexAccess > TableDescriptor::getKeys( )
+{
+ if( ! m_keys.is() )
+ {
+ m_keys = ::pq_sdbc_driver::KeyDescriptors::create(
+ m_xMutex,
+ m_conn,
+ m_pSettings );
+ }
+ return m_keys;
+}
+
+
+Sequence<Type > TableDescriptor::getTypes()
+{
+ static cppu::OTypeCollection collection(
+ cppu::UnoType<css::sdbcx::XIndexesSupplier>::get(),
+ cppu::UnoType<css::sdbcx::XKeysSupplier>::get(),
+ cppu::UnoType<css::sdbcx::XColumnsSupplier>::get(),
+ ReflectionBase::getTypes());
+
+ return collection.getTypes();
+}
+
+Sequence< sal_Int8> TableDescriptor::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+Any TableDescriptor::queryInterface( const Type & reqType )
+{
+ Any ret = ReflectionBase::queryInterface( reqType );
+ if( ! ret.hasValue() )
+ ret = ::cppu::queryInterface(
+ reqType,
+ static_cast< css::sdbcx::XIndexesSupplier * > ( this ),
+ static_cast< css::sdbcx::XKeysSupplier * > ( this ),
+ static_cast< css::sdbcx::XColumnsSupplier * > ( this ));
+ return ret;
+}
+
+
+Reference< XPropertySet > TableDescriptor::createDataDescriptor( )
+{
+ rtl::Reference<TableDescriptor> pTable = new TableDescriptor(
+ m_xMutex, m_conn, m_pSettings );
+
+ // TODO: deep copies
+ pTable->m_values = m_values;
+
+ return Reference< XPropertySet > ( pTable );
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/postgresql/pq_xtable.hxx b/connectivity/source/drivers/postgresql/pq_xtable.hxx
new file mode 100644
index 0000000000..7c8ca73f56
--- /dev/null
+++ b/connectivity/source/drivers/postgresql/pq_xtable.hxx
@@ -0,0 +1,161 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * Effective License of whole file:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011:
+ *
+ * The Contents of this file are made available subject to the terms of
+ * the GNU Lesser General Public License Version 2.1
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * Contributor(s): Joerg Budischewski
+ *
+ * All parts contributed on or after August 2011:
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ ************************************************************************/
+
+#pragma once
+
+#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
+#include <com/sun/star/sdbcx/XIndexesSupplier.hpp>
+#include <com/sun/star/sdbcx/XKeysSupplier.hpp>
+#include <com/sun/star/sdbcx/XRename.hpp>
+#include <com/sun/star/sdbcx/XAlterTable.hpp>
+
+#include "pq_xbase.hxx"
+#include "pq_xcolumns.hxx"
+
+namespace pq_sdbc_driver
+{
+
+class Columns;
+
+class Table : public ReflectionBase,
+ public css::sdbcx::XColumnsSupplier,
+ public css::sdbcx::XIndexesSupplier,
+ public css::sdbcx::XKeysSupplier,
+ public css::sdbcx::XRename,
+ public css::sdbcx::XAlterTable
+{
+ css::uno::Reference< css::container::XNameAccess > m_columns;
+ css::uno::Reference< css::container::XIndexAccess > m_keys;
+ css::uno::Reference< css::container::XNameAccess > m_indexes;
+ rtl::Reference<Columns> m_pColumns;
+
+public:
+ Table( const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex,
+ const css::uno::Reference< css::sdbc::XConnection > & connection,
+ ConnectionSettings *pSettings);
+
+ // XInterface
+ virtual void SAL_CALL acquire() noexcept override { ReflectionBase::acquire(); }
+ virtual void SAL_CALL release() noexcept override { ReflectionBase::release(); }
+ virtual css::uno::Any SAL_CALL queryInterface(
+ const css::uno::Type & reqType ) override;
+
+ // XTypeProvider, first implemented by OPropertySetHelper
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override;
+ virtual css::uno::Sequence< sal_Int8> SAL_CALL getImplementationId() override;
+
+ // XDataDescriptorFactory
+ virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL
+ createDataDescriptor( ) override;
+
+ // XColumnsSupplier
+ virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL
+ getColumns( ) override;
+
+ // XIndexesSupplier
+ virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL
+ getIndexes( ) override;
+
+ // XKeysSupplier
+ virtual css::uno::Reference< css::container::XIndexAccess > SAL_CALL
+ getKeys( ) override;
+
+ // XRename
+ virtual void SAL_CALL rename( const OUString& newName ) override;
+
+ // XAlterTable
+ virtual void SAL_CALL alterColumnByName(
+ const OUString& colName,
+ const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override;
+
+ virtual void SAL_CALL alterColumnByIndex(
+ sal_Int32 index,
+ const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override;
+
+ // XNamed
+ virtual OUString SAL_CALL getName( ) override;
+ virtual void SAL_CALL setName( const OUString& aName ) override;
+};
+
+
+class TableDescriptor
+ : public ReflectionBase,
+ public css::sdbcx::XColumnsSupplier,
+ public css::sdbcx::XIndexesSupplier,
+ public css::sdbcx::XKeysSupplier
+{
+ css::uno::Reference< css::container::XNameAccess > m_columns;
+ css::uno::Reference< css::container::XIndexAccess > m_keys;
+ css::uno::Reference< css::container::XNameAccess > m_indexes;
+
+public:
+ TableDescriptor(
+ const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex,
+ const css::uno::Reference< css::sdbc::XConnection > & connection,
+ ConnectionSettings *pSettings);
+
+public: // XInterface
+ virtual void SAL_CALL acquire() noexcept override { ReflectionBase::acquire(); }
+ virtual void SAL_CALL release() noexcept override { ReflectionBase::release(); }
+ virtual css::uno::Any SAL_CALL queryInterface(
+ const css::uno::Type & reqType ) override;
+
+public: // XTypeProvider, first implemented by OPropertySetHelper
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override;
+ virtual css::uno::Sequence< sal_Int8> SAL_CALL getImplementationId() override;
+
+public: // XColumnsSupplier
+ virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL
+ getColumns( ) override;
+
+public: // XIndexesSupplier
+ virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL
+ getIndexes( ) override;
+
+public: // XKeysSupplier
+ virtual css::uno::Reference< css::container::XIndexAccess > SAL_CALL
+ getKeys( ) override;
+
+public: // XDataDescriptorFactory
+ virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL
+ createDataDescriptor( ) override;
+};
+
+
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/postgresql/pq_xtables.cxx b/connectivity/source/drivers/postgresql/pq_xtables.cxx
new file mode 100644
index 0000000000..423ec81f21
--- /dev/null
+++ b/connectivity/source/drivers/postgresql/pq_xtables.cxx
@@ -0,0 +1,369 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * Effective License of whole file:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011:
+ *
+ * The Contents of this file are made available subject to the terms of
+ * the GNU Lesser General Public License Version 2.1
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * Contributor(s): Joerg Budischewski
+ *
+ * All parts contributed on or after August 2011:
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ ************************************************************************/
+
+#include <rtl/ref.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbcx/Privilege.hpp>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <cppuhelper/exc_hlp.hxx>
+#include <o3tl/safeint.hxx>
+
+#include "pq_xtables.hxx"
+#include "pq_xviews.hxx"
+#include "pq_xtable.hxx"
+#include "pq_statics.hxx"
+#include "pq_tools.hxx"
+
+using osl::MutexGuard;
+
+using com::sun::star::beans::XPropertySet;
+
+using com::sun::star::uno::Any;
+using com::sun::star::uno::UNO_QUERY;
+using com::sun::star::uno::Reference;
+using com::sun::star::uno::Sequence;
+
+using com::sun::star::container::XEnumerationAccess;
+using com::sun::star::container::XEnumeration;
+
+using com::sun::star::sdbc::XRow;
+using com::sun::star::sdbc::XStatement;
+using com::sun::star::sdbc::XResultSet;
+using com::sun::star::sdbc::XDatabaseMetaData;
+using com::sun::star::sdbcx::XColumnsSupplier;
+using com::sun::star::sdbcx::XKeysSupplier;
+
+namespace pq_sdbc_driver
+{
+Tables::Tables(
+ const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex,
+ const css::uno::Reference< css::sdbc::XConnection > & origin,
+ ConnectionSettings *pSettings )
+ : Container( refMutex, origin, pSettings, getStatics().TABLE )
+{}
+
+Tables::~Tables()
+{}
+
+void Tables::refresh()
+{
+ try
+ {
+ osl::MutexGuard guard( m_xMutex->GetMutex() );
+ Statics & st = getStatics();
+
+ Reference< XDatabaseMetaData > meta = m_origin->getMetaData();
+
+ Reference< XResultSet > rs =
+ meta->getTables( Any(), st.cPERCENT,st.cPERCENT, Sequence< OUString > () );
+
+ Reference< XRow > xRow( rs , UNO_QUERY );
+
+ String2IntMap map;
+
+ m_values.clear();
+ sal_Int32 tableIndex = 0;
+ while( rs->next() )
+ {
+ // if creating all these tables turns out to have too bad performance, we might
+ // instead offer a factory interface
+ rtl::Reference<Table> pTable =
+ new Table( m_xMutex, m_origin, m_pSettings );
+ Reference< css::beans::XPropertySet > prop = pTable;
+
+ OUString name = xRow->getString( TABLE_INDEX_NAME+1);
+ OUString schema = xRow->getString( TABLE_INDEX_SCHEMA+1);
+ pTable->setPropertyValue_NoBroadcast_public(
+ st.CATALOG_NAME , Any(xRow->getString( TABLE_INDEX_CATALOG+1) ) );
+ pTable->setPropertyValue_NoBroadcast_public( st.NAME , Any( name ) );
+ pTable->setPropertyValue_NoBroadcast_public( st.SCHEMA_NAME , Any( schema ));
+ pTable->setPropertyValue_NoBroadcast_public(
+ st.TYPE , Any( xRow->getString( TABLE_INDEX_TYPE+1) ) );
+ pTable->setPropertyValue_NoBroadcast_public(
+ st.DESCRIPTION , Any( xRow->getString( TABLE_INDEX_REMARKS+1) ) );
+ pTable->setPropertyValue_NoBroadcast_public(
+ st.PRIVILEGES ,
+ Any( sal_Int32( css::sdbcx::Privilege::SELECT |
+ css::sdbcx::Privilege::INSERT |
+ css::sdbcx::Privilege::UPDATE |
+ css::sdbcx::Privilege::DELETE |
+ css::sdbcx::Privilege::READ |
+ css::sdbcx::Privilege::CREATE |
+ css::sdbcx::Privilege::ALTER |
+ css::sdbcx::Privilege::REFERENCE |
+ css::sdbcx::Privilege::DROP ) ) );
+
+ {
+ m_values.push_back( Any( prop ) );
+ map[ schema + "." + name ] = tableIndex;
+ ++tableIndex;
+ }
+ }
+ m_name2index.swap( map );
+ }
+ catch ( const css::sdbc::SQLException & e )
+ {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ throw css::lang::WrappedTargetRuntimeException( e.Message,
+ e.Context, anyEx );
+ }
+
+ fire( RefreshedBroadcaster( *this ) );
+}
+
+
+static void appendColumnList(
+ OUStringBuffer &buf, const Reference< XColumnsSupplier > & columnSupplier, ConnectionSettings *settings )
+{
+ if( !columnSupplier.is() )
+ return;
+
+ Reference< XEnumerationAccess > columns( columnSupplier->getColumns(),UNO_QUERY );
+ if( !columns.is() )
+ return;
+
+ Reference< XEnumeration > xEnum( columns->createEnumeration() );
+ bool first = true;
+ Statics & st = getStatics();
+
+ while( xEnum.is() && xEnum->hasMoreElements() )
+ {
+ if( first )
+ {
+ first = false;
+ }
+ else
+ {
+ buf.append( ", " );
+ }
+ Reference< XPropertySet > column( xEnum->nextElement(), UNO_QUERY );
+ OUString name = extractStringProperty( column, st.NAME );
+ OUString defaultValue = extractStringProperty( column, st.DEFAULT_VALUE );
+ bool isNullable = extractBoolProperty( column, st.IS_NULLABLE );
+ bool isAutoIncrement = extractBoolProperty( column, st.IS_AUTO_INCREMENT );
+
+ bufferQuoteIdentifier( buf, name, settings );
+
+ OUString type = sqltype2string( column );
+ if( isAutoIncrement )
+ {
+ sal_Int32 dataType = 0;
+ column->getPropertyValue( st.TYPE ) >>= dataType;
+ if( css::sdbc::DataType::INTEGER == dataType )
+ {
+ buf.append( " serial ");
+ isNullable = false;
+ }
+ else if( css::sdbc::DataType::BIGINT == dataType )
+ {
+ buf.append( " serial8 " );
+ isNullable = false;
+ }
+ else
+ buf.append( type );
+ }
+ else
+ {
+ buf.append( type );
+ }
+ if( !defaultValue.isEmpty() )
+ {
+ bufferQuoteConstant( buf, defaultValue, settings );
+ }
+
+ if( ! isNullable )
+ buf.append( " NOT NULL " );
+
+ }
+}
+
+static void appendKeyList(
+ OUStringBuffer & buf, const Reference< XKeysSupplier > &keySupplier, ConnectionSettings *settings )
+{
+ if( !keySupplier.is() )
+ return;
+
+ Reference< XEnumerationAccess > keys( keySupplier->getKeys(), UNO_QUERY );
+ if(keys.is() )
+ {
+ Reference< XEnumeration > xEnum = keys->createEnumeration();
+ while( xEnum.is() && xEnum->hasMoreElements() )
+ {
+ buf.append( ", " );
+ Reference< XPropertySet > key( xEnum->nextElement(), UNO_QUERY );
+ bufferKey2TableConstraint( buf, key, settings );
+ }
+ }
+}
+
+void Tables::appendByDescriptor(
+ const css::uno::Reference< css::beans::XPropertySet >& descriptor )
+{
+ osl::MutexGuard guard( m_xMutex->GetMutex() );
+ Reference< XStatement > stmt =
+ m_origin->createStatement();
+
+ Statics &st = getStatics();
+ OUString name,schema;
+ descriptor->getPropertyValue( st.SCHEMA_NAME ) >>= schema;
+ descriptor->getPropertyValue( st.NAME ) >>= name;
+
+ TransactionGuard transaction( stmt );
+
+ OUStringBuffer buf( 128 );
+ buf.append( "CREATE TABLE" );
+ bufferQuoteQualifiedIdentifier( buf, schema, name , m_pSettings);
+ buf.append( "(" );
+
+ // columns
+ Reference< XColumnsSupplier > supplier( descriptor, UNO_QUERY );
+ appendColumnList( buf, supplier, m_pSettings );
+
+ appendKeyList( buf, Reference< XKeysSupplier >( descriptor, UNO_QUERY ), m_pSettings );
+
+ buf.append( ") " );
+ // execute the creation !
+ transaction.executeUpdate( buf.makeStringAndClear() );
+
+ // description...
+ OUString description = extractStringProperty( descriptor, st.DESCRIPTION );
+ if( !description.isEmpty() )
+ {
+ buf.truncate();
+ buf.append( "COMMENT ON TABLE" );
+ bufferQuoteQualifiedIdentifier( buf, schema, name, m_pSettings );
+ buf.append( "IS " );
+ bufferQuoteConstant( buf, description, m_pSettings);
+
+ transaction.executeUpdate( buf.makeStringAndClear() );
+ }
+
+ // column descriptions
+ if( supplier.is() )
+ {
+ Reference< XEnumerationAccess > columns( supplier->getColumns(),UNO_QUERY );
+ if( columns.is() )
+ {
+ Reference< XEnumeration > xEnum( columns->createEnumeration() );
+ while( xEnum.is() && xEnum->hasMoreElements() )
+ {
+ Reference< XPropertySet > column( xEnum->nextElement(), UNO_QUERY );
+ description = extractStringProperty( column,st.DESCRIPTION );
+ if( !description.isEmpty() )
+ {
+ buf.truncate();
+ buf.append( "COMMENT ON COLUMN " );
+ bufferQuoteQualifiedIdentifier(
+ buf, schema, name, extractStringProperty( column, st.NAME ), m_pSettings );
+ buf.append( "IS " );
+ bufferQuoteConstant( buf, description, m_pSettings );
+ transaction.executeUpdate( buf.makeStringAndClear() );
+ }
+ }
+ }
+ }
+
+ transaction.commit();
+
+ disposeNoThrow( stmt );
+ // TODO: cheaper recalculate
+// Container::append( concatQualified( schema, name ), descriptor ); // maintain the lists
+ refresh();
+}
+
+void Tables::dropByIndex( sal_Int32 index )
+{
+ osl::MutexGuard guard( m_xMutex->GetMutex() );
+ if( index < 0 || o3tl::make_unsigned(index) >= m_values.size() )
+ {
+ throw css::lang::IndexOutOfBoundsException(
+ "TABLES: Index out of range (allowed 0 to " + OUString::number(m_values.size() -1)
+ + ", got " + OUString::number( index ) + ")",
+ *this );
+ }
+
+ Reference< XPropertySet > set;
+ m_values[index] >>= set;
+ Statics &st = getStatics();
+ OUString name,schema;
+ set->getPropertyValue( st.SCHEMA_NAME ) >>= schema;
+ set->getPropertyValue( st.NAME ) >>= name;
+ if( extractStringProperty( set, st.TYPE ) == st.VIEW && m_pSettings->views.is() )
+ {
+ m_pSettings->pViewsImpl->dropByName( concatQualified( schema, name ) );
+ }
+ else
+ {
+ OUStringBuffer update( 128 );
+ update.append( "DROP " );
+ if( extractStringProperty( set, st.TYPE ) == st.VIEW )
+ update.append( "VIEW " );
+ else
+ update.append( "TABLE " );
+ bufferQuoteQualifiedIdentifier( update, schema, name, m_pSettings );
+ Reference< XStatement > stmt = m_origin->createStatement( );
+ DisposeGuard dispGuard( stmt );
+ stmt->executeUpdate( update.makeStringAndClear() );
+ }
+
+ Container::dropByIndex( index );
+}
+
+
+css::uno::Reference< css::beans::XPropertySet > Tables::createDataDescriptor()
+{
+ return new TableDescriptor( m_xMutex, m_origin, m_pSettings );
+}
+
+Reference< css::container::XNameAccess > Tables::create(
+ const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex,
+ const css::uno::Reference< css::sdbc::XConnection > & origin,
+ ConnectionSettings *pSettings,
+ rtl::Reference<Tables> *ppTables)
+{
+ *ppTables = new Tables( refMutex, origin, pSettings );
+ (*ppTables)->refresh();
+
+ return *ppTables;
+}
+
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/postgresql/pq_xtables.hxx b/connectivity/source/drivers/postgresql/pq_xtables.hxx
new file mode 100644
index 0000000000..9222db82c7
--- /dev/null
+++ b/connectivity/source/drivers/postgresql/pq_xtables.hxx
@@ -0,0 +1,91 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * Effective License of whole file:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011:
+ *
+ * The Contents of this file are made available subject to the terms of
+ * the GNU Lesser General Public License Version 2.1
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * Contributor(s): Joerg Budischewski
+ *
+ * All parts contributed on or after August 2011:
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ ************************************************************************/
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <rtl/ref.hxx>
+
+#include "pq_xcontainer.hxx"
+
+namespace pq_sdbc_driver
+{
+
+struct ConnectionSettings;
+
+class Tables : public Container
+{
+
+public: // instances Tables 'exception safe'
+ static css::uno::Reference< css::container::XNameAccess > create(
+ const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex,
+ const css::uno::Reference< css::sdbc::XConnection > & origin,
+ ConnectionSettings *pSettings,
+ rtl::Reference<Tables> * ppTables);
+
+protected:
+ Tables(
+ const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex,
+ const css::uno::Reference< css::sdbc::XConnection > & origin,
+ ConnectionSettings *pSettings );
+
+ virtual ~Tables() override;
+
+public: // XAppend
+ virtual void SAL_CALL appendByDescriptor(
+ const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override;
+
+public: // XDrop
+// virtual void SAL_CALL dropByName( const OUString& elementName )
+// throw (css::sdbc::SQLException,
+// css::container::NoSuchElementException,
+// css::uno::RuntimeException);
+ virtual void SAL_CALL dropByIndex( sal_Int32 index ) override;
+
+public: // XRefreshable
+ virtual void SAL_CALL refresh( ) override;
+
+public: // XDataDescriptorFactory
+ virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL createDataDescriptor( ) override;
+
+protected:
+ using Container::disposing;
+};
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/postgresql/pq_xuser.cxx b/connectivity/source/drivers/postgresql/pq_xuser.cxx
new file mode 100644
index 0000000000..4d0a01f636
--- /dev/null
+++ b/connectivity/source/drivers/postgresql/pq_xuser.cxx
@@ -0,0 +1,172 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * Effective License of whole file:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011:
+ *
+ * The Contents of this file are made available subject to the terms of
+ * the GNU Lesser General Public License Version 2.1
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * Contributor(s): Joerg Budischewski
+ *
+ * All parts contributed on or after August 2011:
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ ************************************************************************/
+
+#include <sal/log.hxx>
+#include <rtl/ref.hxx>
+#include <rtl/ustrbuf.hxx>
+
+#include <cppuhelper/typeprovider.hxx>
+#include <cppuhelper/queryinterface.hxx>
+
+#include <com/sun/star/sdbc/SQLException.hpp>
+
+#include "pq_xuser.hxx"
+#include "pq_tools.hxx"
+#include "pq_statics.hxx"
+
+using com::sun::star::uno::Reference;
+using com::sun::star::uno::Sequence;
+using com::sun::star::uno::Any;
+using com::sun::star::uno::Type;
+
+using com::sun::star::beans::XPropertySet;
+
+using com::sun::star::sdbc::XStatement;
+using com::sun::star::sdbc::SQLException;
+
+namespace pq_sdbc_driver
+{
+
+User::User( const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex,
+ const Reference< css::sdbc::XConnection > & connection,
+ ConnectionSettings *pSettings )
+ : ReflectionBase(
+ getStatics().refl.user.implName,
+ getStatics().refl.user.serviceNames,
+ refMutex,
+ connection,
+ pSettings,
+ * getStatics().refl.user.pProps )
+{}
+
+Reference< XPropertySet > User::createDataDescriptor( )
+{
+ rtl::Reference<UserDescriptor> pUser = new UserDescriptor( m_xMutex, m_conn, m_pSettings );
+ pUser->copyValuesFrom( this );
+
+ return Reference< XPropertySet > ( pUser );
+}
+
+
+Sequence<Type > User::getTypes()
+{
+ static cppu::OTypeCollection collection(
+ cppu::UnoType<css::sdbcx::XUser>::get(),
+ ReflectionBase::getTypes());
+
+ return collection.getTypes();
+}
+
+Sequence< sal_Int8> User::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+Any User::queryInterface( const Type & reqType )
+{
+ Any ret = ReflectionBase::queryInterface( reqType );
+ if( ! ret.hasValue() )
+ ret = ::cppu::queryInterface(
+ reqType,
+ static_cast< css::sdbcx::XUser * > ( this ) );
+ return ret;
+}
+
+
+void User::changePassword(
+ const OUString&, const OUString& newPassword )
+{
+ OUStringBuffer buf(128);
+ buf.append( "ALTER USER " );
+ bufferQuoteIdentifier( buf, extractStringProperty( this, getStatics().NAME ), m_pSettings );
+ buf.append( " PASSWORD " );
+ bufferQuoteConstant( buf, newPassword, m_pSettings );
+ Reference< XStatement > stmt = m_conn->createStatement();
+ DisposeGuard guard( stmt );
+ stmt->executeUpdate( buf.makeStringAndClear() );
+}
+
+sal_Int32 User::getPrivileges( const OUString& objName, sal_Int32 objType )
+{
+ SAL_INFO("connectivity.postgresql", "User::getPrivileges[\"Name\"] got called for " << objName << "(type=" << objType << ")");
+ // all privileges
+ return 0xffffffff;
+}
+
+sal_Int32 User::getGrantablePrivileges( const OUString&, sal_Int32 )
+{
+ // all privileges
+ return 0xffffffff;
+}
+
+void User::grantPrivileges( const OUString&, sal_Int32, sal_Int32 )
+{
+ throw css::sdbc::SQLException("pq_driver: privilege change not implemented yet",
+ *this, OUString(), 1, Any() );
+}
+
+void User::revokePrivileges( const OUString&, sal_Int32, sal_Int32 )
+{
+ throw css::sdbc::SQLException("pq_driver: privilege change not implemented yet",
+ *this, OUString(), 1, Any() );
+}
+
+
+UserDescriptor::UserDescriptor(
+ const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex,
+ const Reference< css::sdbc::XConnection > & connection,
+ ConnectionSettings *pSettings )
+ : ReflectionBase(
+ getStatics().refl.userDescriptor.implName,
+ getStatics().refl.userDescriptor.serviceNames,
+ refMutex,
+ connection,
+ pSettings,
+ * getStatics().refl.userDescriptor.pProps )
+{}
+
+Reference< XPropertySet > UserDescriptor::createDataDescriptor( )
+{
+ rtl::Reference<UserDescriptor> pUser = new UserDescriptor( m_xMutex, m_conn, m_pSettings );
+ pUser->copyValuesFrom( this );
+
+ return Reference< XPropertySet > ( pUser );
+}
+
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/postgresql/pq_xuser.hxx b/connectivity/source/drivers/postgresql/pq_xuser.hxx
new file mode 100644
index 0000000000..702787a674
--- /dev/null
+++ b/connectivity/source/drivers/postgresql/pq_xuser.hxx
@@ -0,0 +1,93 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * Effective License of whole file:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011:
+ *
+ * The Contents of this file are made available subject to the terms of
+ * the GNU Lesser General Public License Version 2.1
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * Contributor(s): Joerg Budischewski
+ *
+ * All parts contributed on or after August 2011:
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ ************************************************************************/
+
+#pragma once
+
+#include <com/sun/star/sdbcx/XUser.hpp>
+
+#include "pq_xbase.hxx"
+
+namespace pq_sdbc_driver
+{
+
+class User : public ReflectionBase,
+ public css::sdbcx::XUser
+{
+
+public:
+ User( const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex,
+ const css::uno::Reference< css::sdbc::XConnection > & connection,
+ ConnectionSettings *pSettings);
+
+ // XInterface
+ virtual void SAL_CALL acquire() noexcept override { ReflectionBase::acquire(); }
+ virtual void SAL_CALL release() noexcept override { ReflectionBase::release(); }
+ virtual css::uno::Any SAL_CALL queryInterface(
+ const css::uno::Type & reqType ) override;
+
+ // XTypeProvider, first implemented by OPropertySetHelper
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override;
+ virtual css::uno::Sequence< sal_Int8> SAL_CALL getImplementationId() override;
+
+ // XDataDescriptorFactory
+ virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL
+ createDataDescriptor( ) override;
+
+ // XUser : XAuthorizable
+ virtual sal_Int32 SAL_CALL getPrivileges( const OUString& objName, sal_Int32 objType ) override;
+ virtual sal_Int32 SAL_CALL getGrantablePrivileges( const OUString& objName, sal_Int32 objType ) override;
+ virtual void SAL_CALL grantPrivileges( const OUString& objName, sal_Int32 objType, sal_Int32 objPrivileges ) override;
+ virtual void SAL_CALL revokePrivileges( const OUString& objName, sal_Int32 objType, sal_Int32 objPrivileges ) override;
+ virtual void SAL_CALL changePassword( const OUString& oldPassword, const OUString& newPassword ) override;
+};
+
+class UserDescriptor : public ReflectionBase
+{
+public:
+ UserDescriptor(
+ const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex,
+ const css::uno::Reference< css::sdbc::XConnection > & connection,
+ ConnectionSettings *pSettings);
+
+public: // XDataDescriptorFactory
+ virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL
+ createDataDescriptor( ) override;
+};
+
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/postgresql/pq_xusers.cxx b/connectivity/source/drivers/postgresql/pq_xusers.cxx
new file mode 100644
index 0000000000..08cdf2d1c1
--- /dev/null
+++ b/connectivity/source/drivers/postgresql/pq_xusers.cxx
@@ -0,0 +1,202 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * Effective License of whole file:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011:
+ *
+ * The Contents of this file are made available subject to the terms of
+ * the GNU Lesser General Public License Version 2.1
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * Contributor(s): Joerg Budischewski
+ *
+ * All parts contributed on or after August 2011:
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ ************************************************************************/
+
+#include <rtl/ref.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <cppuhelper/exc_hlp.hxx>
+#include <o3tl/safeint.hxx>
+
+#include "pq_xusers.hxx"
+#include "pq_xuser.hxx"
+#include "pq_statics.hxx"
+#include "pq_tools.hxx"
+
+using osl::MutexGuard;
+
+using com::sun::star::beans::XPropertySet;
+
+using com::sun::star::uno::Any;
+using com::sun::star::uno::UNO_QUERY;
+using com::sun::star::uno::Reference;
+
+using com::sun::star::container::NoSuchElementException;
+
+using com::sun::star::sdbc::XRow;
+using com::sun::star::sdbc::XStatement;
+using com::sun::star::sdbc::XResultSet;
+
+namespace pq_sdbc_driver
+{
+Users::Users(
+ const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex,
+ const css::uno::Reference< css::sdbc::XConnection > & origin,
+ ConnectionSettings *pSettings )
+ : Container( refMutex, origin, pSettings, getStatics().USER )
+{}
+
+Users::~Users()
+{}
+
+void Users::refresh()
+{
+ try
+ {
+ osl::MutexGuard guard( m_xMutex->GetMutex() );
+ Statics & st = getStatics();
+
+ Reference< XStatement > stmt = m_origin->createStatement();
+
+ Reference< XResultSet > rs = stmt->executeQuery( "SELECT usename FROM pg_shadow" );
+
+ Reference< XRow > xRow( rs , UNO_QUERY );
+
+ String2IntMap map;
+
+ m_values.clear();
+ sal_Int32 tableIndex = 0;
+ while( rs->next() )
+ {
+ rtl::Reference<User> pUser =
+ new User( m_xMutex, m_origin, m_pSettings );
+ Reference< css::beans::XPropertySet > prop = pUser;
+
+ OUString name = xRow->getString( 1);
+ pUser->setPropertyValue_NoBroadcast_public(
+ st.NAME , Any(xRow->getString( TABLE_INDEX_CATALOG+1) ) );
+
+ {
+ m_values.push_back( Any( prop ) );
+ map[ name ] = tableIndex;
+ ++tableIndex;
+ }
+ }
+ m_name2index.swap( map );
+ }
+ catch ( css::sdbc::SQLException & e )
+ {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ throw css::lang::WrappedTargetRuntimeException( e.Message,
+ e.Context, anyEx );
+ }
+
+ fire( RefreshedBroadcaster( *this ) );
+}
+
+
+void Users::appendByDescriptor(
+ const css::uno::Reference< css::beans::XPropertySet >& descriptor )
+{
+ osl::MutexGuard guard( m_xMutex->GetMutex() );
+
+ OUStringBuffer update( 128 );
+ update.append( "CREATE USER " );
+ bufferQuoteIdentifier( update, extractStringProperty( descriptor, getStatics().NAME ), m_pSettings );
+ update.append( " PASSWORD " );
+ bufferQuoteConstant( update, extractStringProperty( descriptor, getStatics().PASSWORD ), m_pSettings );
+
+ Reference< XStatement > stmt = m_origin->createStatement( );
+ DisposeGuard disposeGuard( stmt );
+ stmt->executeUpdate( update.makeStringAndClear() );
+}
+
+void Users::dropByName( const OUString& elementName )
+{
+ String2IntMap::const_iterator ii = m_name2index.find( elementName );
+ if( ii == m_name2index.end() )
+ {
+ throw css::container::NoSuchElementException(
+ "User " + elementName + " is unknown, so it can't be dropped",
+ *this );
+ }
+ dropByIndex( ii->second );
+}
+
+void Users::dropByIndex( sal_Int32 index )
+{
+
+ osl::MutexGuard guard( m_xMutex->GetMutex() );
+ if( index < 0 || o3tl::make_unsigned(index) >= m_values.size() )
+ {
+ throw css::lang::IndexOutOfBoundsException(
+ "USERS: Index out of range (allowed 0 to "
+ + OUString::number( m_values.size() -1 )
+ + ", got " + OUString::number( index )
+ + ")",
+ *this );
+ }
+
+ Reference< XPropertySet > set;
+ m_values[index] >>= set;
+ OUString name;
+ set->getPropertyValue( getStatics().NAME ) >>= name;
+
+ OUStringBuffer update( 128 );
+ update.append( "DROP USER " );
+ bufferQuoteIdentifier( update, name, m_pSettings );
+
+ Reference< XStatement > stmt = m_origin->createStatement( );
+ DisposeGuard disposeGuard( stmt );
+ stmt->executeUpdate( update.makeStringAndClear() );
+}
+
+
+css::uno::Reference< css::beans::XPropertySet > Users::createDataDescriptor()
+{
+ return new UserDescriptor( m_xMutex, m_origin, m_pSettings );
+}
+
+Reference< css::container::XNameAccess > Users::create(
+ const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex,
+ const css::uno::Reference< css::sdbc::XConnection > & origin,
+ ConnectionSettings *pSettings )
+{
+ rtl::Reference<Users> pUsers = new Users( refMutex, origin, pSettings );
+ pUsers->refresh();
+
+ return pUsers;
+}
+
+void Users::disposing()
+{
+}
+
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/postgresql/pq_xusers.hxx b/connectivity/source/drivers/postgresql/pq_xusers.hxx
new file mode 100644
index 0000000000..f95ec17491
--- /dev/null
+++ b/connectivity/source/drivers/postgresql/pq_xusers.hxx
@@ -0,0 +1,82 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * Effective License of whole file:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011:
+ *
+ * The Contents of this file are made available subject to the terms of
+ * the GNU Lesser General Public License Version 2.1
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * Contributor(s): Joerg Budischewski
+ *
+ * All parts contributed on or after August 2011:
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ ************************************************************************/
+
+#pragma once
+
+#include "pq_xcontainer.hxx"
+
+namespace pq_sdbc_driver
+{
+
+class Users final : public Container
+{
+
+public: // instances Tables 'exception safe'
+ static css::uno::Reference< css::container::XNameAccess > create(
+ const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex,
+ const css::uno::Reference< css::sdbc::XConnection > & origin,
+ ConnectionSettings *pSettings );
+
+private:
+ Users(
+ const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex,
+ const css::uno::Reference< css::sdbc::XConnection > & origin,
+ ConnectionSettings *pSettings );
+
+ virtual ~Users() override;
+
+public:
+ // XAppend
+ virtual void SAL_CALL appendByDescriptor(
+ const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override;
+
+ // XDrop
+ virtual void SAL_CALL dropByName( const OUString& elementName ) override;
+ virtual void SAL_CALL dropByIndex( sal_Int32 index ) override;
+
+ // XRefreshable
+ virtual void SAL_CALL refresh( ) override;
+
+ // XDataDescriptorFactory
+ virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL createDataDescriptor( ) override;
+
+private:
+ virtual void SAL_CALL disposing() override;
+};
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/postgresql/pq_xview.cxx b/connectivity/source/drivers/postgresql/pq_xview.cxx
new file mode 100644
index 0000000000..c2e936e9a3
--- /dev/null
+++ b/connectivity/source/drivers/postgresql/pq_xview.cxx
@@ -0,0 +1,217 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * Effective License of whole file:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011:
+ *
+ * The Contents of this file are made available subject to the terms of
+ * the GNU Lesser General Public License Version 2.1
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * Contributor(s): Joerg Budischewski
+ *
+ * All parts contributed on or after August 2011:
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ ************************************************************************/
+
+#include <rtl/ref.hxx>
+#include <rtl/ustrbuf.hxx>
+
+#include <cppuhelper/typeprovider.hxx>
+#include <cppuhelper/queryinterface.hxx>
+
+#include <com/sun/star/sdbc/SQLException.hpp>
+
+#include "pq_xview.hxx"
+#include "pq_xviews.hxx"
+#include "pq_statics.hxx"
+#include "pq_tools.hxx"
+
+using osl::MutexGuard;
+
+using com::sun::star::uno::Reference;
+using com::sun::star::uno::Sequence;
+using com::sun::star::uno::Any;
+using com::sun::star::uno::Type;
+
+using com::sun::star::beans::XPropertySet;
+
+using com::sun::star::sdbc::XStatement;
+using com::sun::star::sdbc::SQLException;
+
+namespace pq_sdbc_driver
+{
+
+View::View( const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex,
+ const Reference< css::sdbc::XConnection > & connection,
+ ConnectionSettings *pSettings)
+ : ReflectionBase(
+ getStatics().refl.view.implName,
+ getStatics().refl.view.serviceNames,
+ refMutex,
+ connection,
+ pSettings,
+ * getStatics().refl.view.pProps )
+{}
+
+Reference< XPropertySet > View::createDataDescriptor( )
+{
+ rtl::Reference<ViewDescriptor> pView = new ViewDescriptor(
+ m_xMutex, m_conn, m_pSettings );
+ pView->copyValuesFrom( this );
+
+ return Reference< XPropertySet > ( pView );
+}
+
+void View::rename( const OUString& newName )
+{
+ MutexGuard guard( m_xMutex->GetMutex() );
+
+ Statics & st = getStatics();
+
+ OUString oldName = extractStringProperty(this,st.NAME );
+ OUString schema = extractStringProperty(this,st.SCHEMA_NAME );
+ OUString fullOldName = concatQualified( schema, oldName );
+
+ OUString newTableName;
+ OUString newSchemaName;
+ // OOo2.0 passes schema + dot + new-table-name while
+ // OO1.1.x passes new Name without schema
+ // in case name contains a dot, it is interpreted as schema.tablename
+ if( newName.indexOf( '.' ) >= 0 )
+ {
+ splitConcatenatedIdentifier( newName, &newSchemaName, &newTableName );
+ }
+ else
+ {
+ newTableName = newName;
+ newSchemaName = schema;
+ }
+ OUString fullNewName = concatQualified( newSchemaName, newTableName );
+
+ if( schema != newSchemaName )
+ {
+ try
+ {
+ OUStringBuffer buf(128);
+ buf.append( "ALTER TABLE" );
+ bufferQuoteQualifiedIdentifier(buf, schema, oldName, m_pSettings );
+ buf.append( "SET SCHEMA" );
+ bufferQuoteIdentifier( buf, newSchemaName, m_pSettings );
+ Reference< XStatement > statement = m_conn->createStatement();
+ statement->executeUpdate( buf.makeStringAndClear() );
+ setPropertyValue_NoBroadcast_public( st.SCHEMA_NAME, Any(newSchemaName) );
+ disposeNoThrow( statement );
+ schema = newSchemaName;
+ }
+ catch( css::sdbc::SQLException &e )
+ {
+ e.Message += "(NOTE: Only postgresql server >= V8.1 support changing a table's schema)";
+ throw;
+ }
+
+ }
+ if( oldName != newTableName )
+ {
+ OUStringBuffer buf(128);
+ buf.append( "ALTER TABLE" );
+ bufferQuoteQualifiedIdentifier( buf, schema, oldName, m_pSettings );
+ buf.append( "RENAME TO" );
+ bufferQuoteIdentifier( buf, newTableName, m_pSettings );
+ Reference< XStatement > statement = m_conn->createStatement();
+ statement->executeUpdate( buf.makeStringAndClear() );
+ setPropertyValue_NoBroadcast_public( st.NAME, Any(newTableName) );
+ }
+
+ // inform the container of the name change !
+ if( m_pSettings->views.is() )
+ {
+ m_pSettings->pViewsImpl->rename( fullOldName, fullNewName );
+ }
+}
+
+Sequence<Type > View::getTypes()
+{
+ static cppu::OTypeCollection collection(
+ cppu::UnoType<css::sdbcx::XRename>::get(),
+ ReflectionBase::getTypes());
+
+ return collection.getTypes();
+}
+
+Sequence< sal_Int8> View::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+Any View::queryInterface( const Type & reqType )
+{
+ Any ret = ReflectionBase::queryInterface( reqType );
+ if( ! ret.hasValue() )
+ ret = ::cppu::queryInterface(
+ reqType,
+ static_cast< css::sdbcx::XRename * > ( this )
+ );
+ return ret;
+}
+
+OUString View::getName( )
+{
+ Statics & st = getStatics();
+ return concatQualified(
+ extractStringProperty( this, st.SCHEMA_NAME ),
+ extractStringProperty( this, st.NAME ) );
+}
+
+void View::setName( const OUString& aName )
+{
+ rename( aName );
+}
+
+
+ViewDescriptor::ViewDescriptor(
+ const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex,
+ const Reference< css::sdbc::XConnection > & connection,
+ ConnectionSettings *pSettings)
+ : ReflectionBase(
+ getStatics().refl.viewDescriptor.implName,
+ getStatics().refl.viewDescriptor.serviceNames,
+ refMutex,
+ connection,
+ pSettings,
+ * getStatics().refl.viewDescriptor.pProps )
+{}
+
+Reference< XPropertySet > ViewDescriptor::createDataDescriptor( )
+{
+ rtl::Reference<ViewDescriptor> pView = new ViewDescriptor(
+ m_xMutex, m_conn, m_pSettings );
+ pView->copyValuesFrom( this );
+
+ return Reference< XPropertySet > ( pView );
+}
+
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/postgresql/pq_xview.hxx b/connectivity/source/drivers/postgresql/pq_xview.hxx
new file mode 100644
index 0000000000..f68b5535a8
--- /dev/null
+++ b/connectivity/source/drivers/postgresql/pq_xview.hxx
@@ -0,0 +1,92 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * Effective License of whole file:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011:
+ *
+ * The Contents of this file are made available subject to the terms of
+ * the GNU Lesser General Public License Version 2.1
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * Contributor(s): Joerg Budischewski
+ *
+ * All parts contributed on or after August 2011:
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ ************************************************************************/
+
+#pragma once
+
+#include <com/sun/star/sdbcx/XRename.hpp>
+
+#include "pq_xbase.hxx"
+
+namespace pq_sdbc_driver
+{
+class View : public ReflectionBase,
+ public css::sdbcx::XRename
+{
+public:
+ View( const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex,
+ const css::uno::Reference< css::sdbc::XConnection > & connection,
+ ConnectionSettings *pSettings);
+
+ // XInterface
+ virtual void SAL_CALL acquire() noexcept override { ReflectionBase::acquire(); }
+ virtual void SAL_CALL release() noexcept override { ReflectionBase::release(); }
+ virtual css::uno::Any SAL_CALL queryInterface(
+ const css::uno::Type & reqType ) override;
+
+ // XTypeProvider, first implemented by OPropertySetHelper
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override;
+ virtual css::uno::Sequence< sal_Int8> SAL_CALL getImplementationId() override;
+
+ // XDataDescriptorFactory
+ virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL
+ createDataDescriptor( ) override;
+
+ // XRename
+ virtual void SAL_CALL rename( const OUString& newName ) override;
+
+ // XNamed
+ virtual OUString SAL_CALL getName( ) override;
+ virtual void SAL_CALL setName( const OUString& aName ) override;
+
+};
+
+
+class ViewDescriptor : public ReflectionBase
+{
+public:
+ ViewDescriptor( const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex,
+ const css::uno::Reference< css::sdbc::XConnection > & connection,
+ ConnectionSettings *pSettings);
+
+ // XDataDescriptorFactory
+ virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL
+ createDataDescriptor( ) override;
+};
+
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/postgresql/pq_xviews.cxx b/connectivity/source/drivers/postgresql/pq_xviews.cxx
new file mode 100644
index 0000000000..1f5b6c4fa5
--- /dev/null
+++ b/connectivity/source/drivers/postgresql/pq_xviews.cxx
@@ -0,0 +1,219 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * Effective License of whole file:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011:
+ *
+ * The Contents of this file are made available subject to the terms of
+ * the GNU Lesser General Public License Version 2.1
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * Contributor(s): Joerg Budischewski
+ *
+ * All parts contributed on or after August 2011:
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ ************************************************************************/
+
+#include <rtl/ref.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <cppuhelper/exc_hlp.hxx>
+#include <o3tl/safeint.hxx>
+
+#include "pq_xviews.hxx"
+#include "pq_xview.hxx"
+#include "pq_xtables.hxx"
+#include "pq_statics.hxx"
+#include "pq_tools.hxx"
+
+using osl::MutexGuard;
+
+using com::sun::star::beans::XPropertySet;
+
+using com::sun::star::uno::Any;
+using com::sun::star::uno::UNO_QUERY;
+using com::sun::star::uno::Reference;
+
+using com::sun::star::container::NoSuchElementException;
+
+using com::sun::star::sdbc::XRow;
+using com::sun::star::sdbc::XStatement;
+using com::sun::star::sdbc::XResultSet;
+
+
+namespace pq_sdbc_driver
+{
+Views::Views(
+ const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex,
+ const css::uno::Reference< css::sdbc::XConnection > & origin,
+ ConnectionSettings *pSettings )
+ : Container( refMutex, origin, pSettings, getStatics().VIEW )
+{}
+
+Views::~Views()
+{}
+
+void Views::refresh()
+{
+ try
+ {
+ osl::MutexGuard guard( m_xMutex->GetMutex() );
+ Statics & st = getStatics();
+
+ Reference< XStatement > stmt = m_origin->createStatement();
+
+ Reference< XResultSet > rs = stmt->executeQuery("SELECT "
+ "DISTINCT ON( pg_namespace.nspname, relname) " // needed because of duplicates
+ "pg_namespace.nspname," // 1
+ "relname," // 2
+ "pg_get_viewdef(ev_class) " // 3
+ "FROM pg_namespace, pg_class, pg_rewrite "
+ "WHERE pg_namespace.oid = relnamespace "
+ "AND pg_class.oid = ev_class "
+ "AND relkind=\'v\'" );
+
+ Reference< XRow > xRow( rs , UNO_QUERY );
+
+ m_values.clear();
+ String2IntMap map;
+ sal_Int32 viewIndex = 0;
+
+ while( rs->next() )
+ {
+ OUString table, schema, command;
+ schema = xRow->getString( 1 );
+ table = xRow->getString( 2 );
+ command = xRow->getString( 3 );
+
+ rtl::Reference<View> pView = new View (m_xMutex, m_origin, m_pSettings );
+ Reference< css::beans::XPropertySet > prop = pView;
+
+ pView->setPropertyValue_NoBroadcast_public(st.NAME , Any(table) );
+ pView->setPropertyValue_NoBroadcast_public(st.SCHEMA_NAME, Any(schema) );
+ pView->setPropertyValue_NoBroadcast_public(st.COMMAND, Any(command) );
+
+ {
+ m_values.push_back( Any( prop ) );
+ map[ schema + "." + table ] = viewIndex;
+ ++viewIndex;
+ }
+ }
+ m_name2index.swap( map );
+ }
+ catch ( css::sdbc::SQLException & e )
+ {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ throw css::lang::WrappedTargetRuntimeException( e.Message,
+ e.Context, anyEx );
+ }
+ fire( RefreshedBroadcaster( *this ) );
+}
+
+
+void Views::appendByDescriptor(
+ const css::uno::Reference< css::beans::XPropertySet >& descriptor )
+{
+ osl::MutexGuard guard( m_xMutex->GetMutex() );
+
+ Statics &st = getStatics();
+ OUString name,schema,command;
+ descriptor->getPropertyValue( st.SCHEMA_NAME ) >>= schema;
+ descriptor->getPropertyValue( st.NAME ) >>= name;
+ descriptor->getPropertyValue( st.COMMAND ) >>= command;
+
+ Reference< XStatement > stmt = m_origin->createStatement();
+
+ OUStringBuffer buf( 128 );
+
+ buf.append( "CREATE VIEW ");
+ bufferQuoteQualifiedIdentifier( buf, schema, name, m_pSettings );
+ buf.append(" AS " + command );
+
+ stmt->executeUpdate( buf.makeStringAndClear() );
+
+ disposeNoThrow( stmt );
+ refresh();
+ if( m_pSettings->tables.is() )
+ {
+ m_pSettings->pTablesImpl->refresh();
+ }
+}
+
+void Views::dropByName( const OUString& elementName )
+{
+ String2IntMap::const_iterator ii = m_name2index.find( elementName );
+ if( ii == m_name2index.end() )
+ {
+ throw css::container::NoSuchElementException(
+ "View " + elementName + " is unknown, so it can't be dropped", *this );
+ }
+ dropByIndex( ii->second );
+}
+
+void Views::dropByIndex( sal_Int32 index )
+{
+ osl::MutexGuard guard( m_xMutex->GetMutex() );
+ if( index < 0 || o3tl::make_unsigned(index) >= m_values.size() )
+ {
+ throw css::lang::IndexOutOfBoundsException(
+ "VIEWS: Index out of range (allowed 0 to " + OUString::number(m_values.size() -1)
+ + ", got " + OUString::number( index ) + ")",
+ *this );
+ }
+
+ Reference< XPropertySet > set;
+ m_values[index] >>= set;
+ Statics &st = getStatics();
+ OUString name,schema;
+ set->getPropertyValue( st.SCHEMA_NAME ) >>= schema;
+ set->getPropertyValue( st.NAME ) >>= name;
+
+ Reference< XStatement > stmt = m_origin->createStatement( );
+
+ stmt->executeUpdate( "DROP VIEW \"" + schema + "\".\"" + name + "\"" );
+}
+
+
+css::uno::Reference< css::beans::XPropertySet > Views::createDataDescriptor()
+{
+ return new ViewDescriptor( m_xMutex, m_origin, m_pSettings );
+}
+
+Reference< css::container::XNameAccess > Views::create(
+ const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex,
+ const css::uno::Reference< css::sdbc::XConnection > & origin,
+ ConnectionSettings *pSettings,
+ rtl::Reference<Views> *ppViews)
+{
+ *ppViews = new Views( refMutex, origin, pSettings );
+ (*ppViews)->refresh();
+
+ return *ppViews;
+}
+
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/postgresql/pq_xviews.hxx b/connectivity/source/drivers/postgresql/pq_xviews.hxx
new file mode 100644
index 0000000000..04137b6868
--- /dev/null
+++ b/connectivity/source/drivers/postgresql/pq_xviews.hxx
@@ -0,0 +1,88 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * Effective License of whole file:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011:
+ *
+ * The Contents of this file are made available subject to the terms of
+ * the GNU Lesser General Public License Version 2.1
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * Contributor(s): Joerg Budischewski
+ *
+ * All parts contributed on or after August 2011:
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ ************************************************************************/
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <rtl/ref.hxx>
+
+#include "pq_xcontainer.hxx"
+
+namespace pq_sdbc_driver
+{
+
+struct ConnectionSettings;
+
+class Views : public Container
+{
+
+public: // instances Views 'exception safe'
+ static css::uno::Reference< css::container::XNameAccess > create(
+ const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex,
+ const css::uno::Reference< css::sdbc::XConnection > & origin,
+ ConnectionSettings *pSettings,
+ rtl::Reference<Views> *ppViews );
+
+protected:
+ Views(
+ const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex,
+ const css::uno::Reference< css::sdbc::XConnection > & origin,
+ ConnectionSettings *pSettings);
+
+ virtual ~Views() override;
+
+public: // XAppend
+ virtual void SAL_CALL appendByDescriptor(
+ const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override;
+
+public: // XDrop
+ virtual void SAL_CALL dropByName( const OUString& elementName ) override;
+ virtual void SAL_CALL dropByIndex( sal_Int32 index ) override;
+
+public: // XRefreshable
+ virtual void SAL_CALL refresh( ) override;
+
+public: // XDataDescriptorFactory
+ virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL createDataDescriptor( ) override;
+
+protected:
+ using Container::disposing;
+
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/writer/WCatalog.cxx b/connectivity/source/drivers/writer/WCatalog.cxx
new file mode 100644
index 0000000000..8671af7bd5
--- /dev/null
+++ b/connectivity/source/drivers/writer/WCatalog.cxx
@@ -0,0 +1,60 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <writer/WCatalog.hxx>
+#include <writer/WTables.hxx>
+
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XResultSet.hpp>
+
+#include <connectivity/sdbcx/VCollection.hxx>
+
+#include <writer/WConnection.hxx>
+
+using namespace ::com::sun::star;
+
+namespace connectivity::writer
+{
+OWriterCatalog::OWriterCatalog(OWriterConnection* pConnection)
+ : file::OFileCatalog(pConnection)
+{
+}
+
+void OWriterCatalog::refreshTables()
+{
+ ::std::vector<OUString> aVector;
+ uno::Sequence<OUString> aTypes;
+ OWriterConnection::ODocHolder aDocHolder(static_cast<OWriterConnection*>(m_pConnection));
+ uno::Reference<sdbc::XResultSet> xResult = m_xMetaData->getTables(uno::Any(), "%", "%", aTypes);
+
+ if (xResult.is())
+ {
+ uno::Reference<sdbc::XRow> xRow(xResult, uno::UNO_QUERY);
+ while (xResult->next())
+ aVector.push_back(xRow->getString(3));
+ }
+ if (m_pTables)
+ m_pTables->reFill(aVector);
+ else
+ m_pTables = std::make_unique<OWriterTables>(m_xMetaData, *this, m_aMutex, aVector);
+}
+
+} // namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/writer/WConnection.cxx b/connectivity/source/drivers/writer/WConnection.cxx
new file mode 100644
index 0000000000..39724538cb
--- /dev/null
+++ b/connectivity/source/drivers/writer/WConnection.cxx
@@ -0,0 +1,245 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <writer/WConnection.hxx>
+#include <writer/WDatabaseMetaData.hxx>
+#include <writer/WCatalog.hxx>
+#include <writer/WDriver.hxx>
+#include <resource/sharedresources.hxx>
+#include <strings.hrc>
+#include <com/sun/star/frame/Desktop.hpp>
+#include <com/sun/star/text/XTextDocument.hpp>
+#include <tools/urlobj.hxx>
+#include <sal/log.hxx>
+#include <component/CPreparedStatement.hxx>
+#include <component/CStatement.hxx>
+#include <unotools/pathoptions.hxx>
+#include <connectivity/dbexception.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+#include <comphelper/diagnose_ex.hxx>
+
+using namespace ::com::sun::star;
+
+using OConnection_BASE = connectivity::file::OConnection;
+
+namespace connectivity::writer
+{
+OWriterConnection::OWriterConnection(ODriver* _pDriver)
+ : OConnection(_pDriver)
+{
+}
+
+OWriterConnection::~OWriterConnection() = default;
+
+void OWriterConnection::construct(const OUString& rURL,
+ const uno::Sequence<beans::PropertyValue>& rInfo)
+{
+ // open file
+
+ sal_Int32 nLen = rURL.indexOf(':');
+ nLen = rURL.indexOf(':', nLen + 1);
+ OUString aDSN(rURL.copy(nLen + 1));
+
+ m_aFileName = aDSN;
+ INetURLObject aURL;
+ aURL.SetSmartProtocol(INetProtocol::File);
+ {
+ SvtPathOptions aPathOptions;
+ m_aFileName = aPathOptions.SubstituteVariable(m_aFileName);
+ }
+ aURL.SetSmartURL(m_aFileName);
+ if (aURL.GetProtocol() == INetProtocol::NotValid)
+ {
+ // don't pass invalid URL to loadComponentFromURL
+ throw sdbc::SQLException();
+ }
+ m_aFileName = aURL.GetMainURL(INetURLObject::DecodeMechanism::NONE);
+
+ m_sPassword.clear();
+ const char pPwd[] = "password";
+
+ const beans::PropertyValue* pIter = rInfo.getConstArray();
+ const beans::PropertyValue* pEnd = pIter + rInfo.getLength();
+ for (; pIter != pEnd; ++pIter)
+ {
+ if (pIter->Name == pPwd)
+ {
+ pIter->Value >>= m_sPassword;
+ break;
+ }
+ } // for(;pIter != pEnd;++pIter)
+ ODocHolder aDocHolder(this); // just to test that the doc can be loaded
+ acquireDoc();
+}
+
+uno::Reference<text::XTextDocument> const& OWriterConnection::acquireDoc()
+{
+ if (m_xDoc.is())
+ {
+ osl_atomic_increment(&m_nDocCount);
+ return m_xDoc;
+ }
+ // open read-only as long as updating isn't implemented
+ uno::Sequence<beans::PropertyValue> aArgs(m_sPassword.isEmpty() ? 2 : 3);
+ auto pArgs = aArgs.getArray();
+ pArgs[0].Name = "Hidden";
+ pArgs[0].Value <<= true;
+ pArgs[1].Name = "ReadOnly";
+ pArgs[1].Value <<= true;
+
+ if (!m_sPassword.isEmpty())
+ {
+ pArgs[2].Name = "Password";
+ pArgs[2].Value <<= m_sPassword;
+ }
+
+ uno::Reference<frame::XDesktop2> xDesktop
+ = frame::Desktop::create(getDriver()->getComponentContext());
+ uno::Reference<lang::XComponent> xComponent;
+ uno::Any aLoaderException;
+ try
+ {
+ xComponent = xDesktop->loadComponentFromURL(m_aFileName, "_blank", 0, aArgs);
+ }
+ catch (const uno::Exception&)
+ {
+ aLoaderException = ::cppu::getCaughtException();
+ }
+
+ m_xDoc.set(xComponent, uno::UNO_QUERY);
+
+ // if the URL is not a text document, throw the exception here
+ // instead of at the first access to it
+ if (!m_xDoc.is())
+ {
+ if (aLoaderException.hasValue())
+ {
+ uno::Exception aLoaderError;
+ OSL_VERIFY(aLoaderException >>= aLoaderError);
+
+ SAL_WARN("connectivity.writer",
+ "empty m_xDoc, " << exceptionToString(aLoaderException));
+ }
+
+ const OUString sError(m_aResources.getResourceStringWithSubstitution(
+ STR_COULD_NOT_LOAD_FILE, "$filename$", m_aFileName));
+ ::dbtools::throwGenericSQLException(sError, *this);
+ }
+ osl_atomic_increment(&m_nDocCount);
+ m_xCloseVetoButTerminateListener.set(new CloseVetoButTerminateListener);
+ m_xCloseVetoButTerminateListener->start(m_xDoc, xDesktop);
+ return m_xDoc;
+}
+
+void OWriterConnection::releaseDoc()
+{
+ if (osl_atomic_decrement(&m_nDocCount) == 0)
+ {
+ if (m_xCloseVetoButTerminateListener.is())
+ {
+ m_xCloseVetoButTerminateListener->stop(); // dispose m_xDoc
+ m_xCloseVetoButTerminateListener.clear();
+ }
+ m_xDoc.clear();
+ }
+}
+
+void OWriterConnection::disposing()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+
+ m_nDocCount = 0;
+ if (m_xCloseVetoButTerminateListener.is())
+ {
+ m_xCloseVetoButTerminateListener->stop(); // dispose m_xDoc
+ m_xCloseVetoButTerminateListener.clear();
+ }
+ m_xDoc.clear();
+
+ OConnection::disposing();
+}
+
+// XServiceInfo
+
+IMPLEMENT_SERVICE_INFO(OWriterConnection, "com.sun.star.sdbc.drivers.writer.Connection",
+ "com.sun.star.sdbc.Connection")
+
+uno::Reference<sdbc::XDatabaseMetaData> SAL_CALL OWriterConnection::getMetaData()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(OConnection_BASE::rBHelper.bDisposed);
+
+ uno::Reference<sdbc::XDatabaseMetaData> xMetaData = m_xMetaData;
+ if (!xMetaData.is())
+ {
+ xMetaData = new OWriterDatabaseMetaData(this);
+ m_xMetaData = xMetaData;
+ }
+
+ return xMetaData;
+}
+
+css::uno::Reference<css::sdbcx::XTablesSupplier> OWriterConnection::createCatalog()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ uno::Reference<css::sdbcx::XTablesSupplier> xTab = m_xCatalog;
+ if (!xTab.is())
+ {
+ xTab = new OWriterCatalog(this);
+ m_xCatalog = xTab;
+ }
+ return xTab;
+}
+
+uno::Reference<sdbc::XStatement> SAL_CALL OWriterConnection::createStatement()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(OConnection_BASE::rBHelper.bDisposed);
+
+ uno::Reference<sdbc::XStatement> xReturn = new component::OComponentStatement(this);
+ m_aStatements.push_back(uno::WeakReferenceHelper(xReturn));
+ return xReturn;
+}
+
+uno::Reference<sdbc::XPreparedStatement>
+ SAL_CALL OWriterConnection::prepareStatement(const OUString& sql)
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(OConnection_BASE::rBHelper.bDisposed);
+
+ rtl::Reference<component::OComponentPreparedStatement> pStmt
+ = new component::OComponentPreparedStatement(this);
+ pStmt->construct(sql);
+ m_aStatements.push_back(uno::WeakReferenceHelper(*pStmt));
+ return pStmt;
+}
+
+uno::Reference<sdbc::XPreparedStatement>
+ SAL_CALL OWriterConnection::prepareCall(const OUString& /*sql*/)
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(OConnection_BASE::rBHelper.bDisposed);
+
+ ::dbtools::throwFeatureNotImplementedSQLException("XConnection::prepareCall", *this);
+ return nullptr;
+}
+
+} // namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/writer/WDatabaseMetaData.cxx b/connectivity/source/drivers/writer/WDatabaseMetaData.cxx
new file mode 100644
index 0000000000..f944d86a7f
--- /dev/null
+++ b/connectivity/source/drivers/writer/WDatabaseMetaData.cxx
@@ -0,0 +1,112 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <writer/WDatabaseMetaData.hxx>
+#include <writer/WConnection.hxx>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <com/sun/star/text/XTextDocument.hpp>
+#include <com/sun/star/text/XTextTablesSupplier.hpp>
+
+using namespace ::com::sun::star;
+
+namespace connectivity::writer
+{
+OWriterDatabaseMetaData::OWriterDatabaseMetaData(file::OConnection* pConnection)
+ : OComponentDatabaseMetaData(pConnection)
+{
+}
+
+OWriterDatabaseMetaData::~OWriterDatabaseMetaData() = default;
+
+OUString SAL_CALL OWriterDatabaseMetaData::getURL()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+
+ return "sdbc:writer:" + m_pConnection->getURL();
+}
+
+uno::Reference<sdbc::XResultSet> SAL_CALL OWriterDatabaseMetaData::getTables(
+ const uno::Any& /*catalog*/, const OUString& /*schemaPattern*/,
+ const OUString& tableNamePattern, const uno::Sequence<OUString>& types)
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+
+ rtl::Reference<ODatabaseMetaDataResultSet> pResult
+ = new ODatabaseMetaDataResultSet(ODatabaseMetaDataResultSet::eTables);
+
+ // check if ORowSetValue type is given
+ // when no types are given then we have to return all tables e.g. TABLE
+
+ OUString aTable("TABLE");
+
+ bool bTableFound = true;
+ sal_Int32 nLength = types.getLength();
+ if (nLength)
+ {
+ bTableFound = false;
+
+ const OUString* pIter = types.getConstArray();
+ const OUString* pEnd = pIter + nLength;
+ for (; pIter != pEnd; ++pIter)
+ {
+ if (*pIter == aTable)
+ {
+ bTableFound = true;
+ break;
+ }
+ }
+ }
+ if (!bTableFound)
+ return pResult;
+
+ // get the table names from the document
+
+ OWriterConnection::ODocHolder aDocHolder(static_cast<OWriterConnection*>(m_pConnection));
+ uno::Reference<text::XTextTablesSupplier> xDoc(aDocHolder.getDoc(), uno::UNO_QUERY);
+ if (!xDoc.is())
+ throw sdbc::SQLException();
+ uno::Reference<container::XNameAccess> xTables = xDoc->getTextTables();
+ if (!xTables.is())
+ throw sdbc::SQLException();
+ uno::Sequence<OUString> aTableNames = xTables->getElementNames();
+
+ ODatabaseMetaDataResultSet::ORows aRows;
+ sal_Int32 nTableCount = aTableNames.getLength();
+ for (sal_Int32 nTable = 0; nTable < nTableCount; nTable++)
+ {
+ const OUString& rName = aTableNames[nTable];
+ if (match(tableNamePattern, rName, '\0'))
+ {
+ ODatabaseMetaDataResultSet::ORow aRow{ nullptr, nullptr, nullptr };
+ aRow.reserve(6);
+ aRow.push_back(new ORowSetValueDecorator(rName));
+ aRow.push_back(new ORowSetValueDecorator(aTable));
+ aRow.push_back(ODatabaseMetaDataResultSet::getEmptyValue());
+ aRows.push_back(aRow);
+ }
+ }
+
+ pResult->setRows(std::move(aRows));
+
+ return pResult;
+}
+
+} // namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/writer/WDriver.cxx b/connectivity/source/drivers/writer/WDriver.cxx
new file mode 100644
index 0000000000..21325d73f6
--- /dev/null
+++ b/connectivity/source/drivers/writer/WDriver.cxx
@@ -0,0 +1,87 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <writer/WDriver.hxx>
+#include <writer/WConnection.hxx>
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <connectivity/dbexception.hxx>
+#include <resource/sharedresources.hxx>
+#include <strings.hrc>
+
+using namespace connectivity::file;
+using namespace ::com::sun::star;
+
+namespace connectivity::writer
+{
+OUString SAL_CALL ODriver::getImplementationName()
+{
+ return "com.sun.star.comp.sdbc.writer.ODriver";
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+connectivity_writer_ODriver(css::uno::XComponentContext* context,
+ css::uno::Sequence<css::uno::Any> const& /*rArguments*/)
+{
+ try
+ {
+ return acquire(new ODriver(context));
+ }
+ catch (...)
+ {
+ }
+ return nullptr;
+}
+
+uno::Reference<sdbc::XConnection>
+ SAL_CALL ODriver::connect(const OUString& url, const uno::Sequence<beans::PropertyValue>& info)
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ if (ODriver_BASE::rBHelper.bDisposed)
+ throw lang::DisposedException();
+
+ if (!acceptsURL(url))
+ return nullptr;
+
+ rtl::Reference<OWriterConnection> pCon = new OWriterConnection(this);
+ pCon->construct(url, info);
+ m_xConnections.push_back(uno::WeakReferenceHelper(*pCon));
+
+ return pCon;
+}
+
+sal_Bool SAL_CALL ODriver::acceptsURL(const OUString& url)
+{
+ return url.startsWith("sdbc:writer:");
+}
+
+uno::Sequence<sdbc::DriverPropertyInfo> SAL_CALL
+ODriver::getPropertyInfo(const OUString& url, const uno::Sequence<beans::PropertyValue>& /*info*/)
+{
+ if (!acceptsURL(url))
+ {
+ SharedResources aResources;
+ const OUString sMessage = aResources.getResourceString(STR_URI_SYNTAX_ERROR);
+ ::dbtools::throwGenericSQLException(sMessage, *this);
+ }
+ return {};
+}
+
+} // namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/writer/WTable.cxx b/connectivity/source/drivers/writer/WTable.cxx
new file mode 100644
index 0000000000..2f0f44855d
--- /dev/null
+++ b/connectivity/source/drivers/writer/WTable.cxx
@@ -0,0 +1,234 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <writer/WTable.hxx>
+#include <com/sun/star/sdbc/ColumnValue.hpp>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <com/sun/star/text/XTextDocument.hpp>
+#include <com/sun/star/text/XTextTable.hpp>
+#include <com/sun/star/text/XTextTablesSupplier.hpp>
+#include <com/sun/star/table/XCellRange.hpp>
+#include <com/sun/star/text/XText.hpp>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <writer/WConnection.hxx>
+#include <connectivity/sdbcx/VColumn.hxx>
+#include <sal/log.hxx>
+
+namespace com::sun::star::text
+{
+class XTextDocument;
+}
+
+using namespace ::com::sun::star;
+
+static void lcl_GetDataArea(const uno::Reference<text::XTextTable>& xTable, sal_Int32& rColumnCount,
+ sal_Int32& rRowCount)
+{
+ uno::Reference<container::XIndexAccess> xColumns = xTable->getColumns();
+ if (xColumns.is())
+ rColumnCount = xColumns->getCount();
+
+ uno::Reference<container::XIndexAccess> xRows = xTable->getRows();
+ if (xRows.is())
+ rRowCount = xRows->getCount() - 1; // first row (headers) is not counted
+}
+
+static void lcl_GetColumnInfo(const uno::Reference<text::XTextTable>& xTable, sal_Int32 nDocColumn,
+ bool bHasHeaders, OUString& rName, sal_Int32& rDataType,
+ bool& rCurrency)
+{
+ uno::Reference<table::XCellRange> xCellRange(xTable, uno::UNO_QUERY);
+ // get column name from first row, if range contains headers
+ if (bHasHeaders)
+ {
+ uno::Reference<text::XText> xHeaderText(
+ xCellRange->getCellByPosition(nDocColumn, /*nStartRow*/ 0), uno::UNO_QUERY);
+ if (xHeaderText.is())
+ rName = xHeaderText->getString();
+ }
+
+ rCurrency = false;
+ rDataType = sdbc::DataType::VARCHAR;
+}
+
+static void lcl_SetValue(connectivity::ORowSetValue& rValue,
+ const uno::Reference<text::XTextTable>& xTable, sal_Int32 nStartCol,
+ bool bHasHeaders, sal_Int32 nDBRow, sal_Int32 nDBColumn)
+{
+ sal_Int32 nDocColumn = nStartCol + nDBColumn - 1; // database counts from 1
+ sal_Int32 nDocRow = nDBRow - 1;
+ if (bHasHeaders)
+ ++nDocRow;
+
+ uno::Reference<table::XCellRange> xCellRange(xTable, uno::UNO_QUERY);
+ uno::Reference<table::XCell> xCell;
+ try
+ {
+ xCell = xCellRange->getCellByPosition(nDocColumn, nDocRow);
+ }
+ catch (const lang::IndexOutOfBoundsException& /*rException*/)
+ {
+ SAL_WARN("connectivity.writer",
+ "getCellByPosition(" << nDocColumn << ", " << nDocRow << ") failed");
+ rValue = OUString();
+ }
+
+ if (xCell.is())
+ {
+ const uno::Reference<text::XText> xText(xCell, uno::UNO_QUERY);
+ if (xText.is())
+ rValue = xText->getString();
+ }
+}
+
+namespace connectivity::writer
+{
+void OWriterTable::fillColumns()
+{
+ if (!m_xTable.is())
+ throw sdbc::SQLException();
+
+ OUString aTypeName;
+ ::comphelper::UStringMixEqual aCase(
+ m_pConnection->getMetaData()->supportsMixedCaseQuotedIdentifiers());
+ const bool bStoresMixedCaseQuotedIdentifiers
+ = getConnection()->getMetaData()->supportsMixedCaseQuotedIdentifiers();
+
+ for (sal_Int32 i = 0; i < m_nDataCols; i++)
+ {
+ OUString aColumnName;
+ sal_Int32 eType = sdbc::DataType::OTHER;
+ bool bCurrency = false;
+
+ lcl_GetColumnInfo(m_xTable, m_nStartCol + i, m_bHasHeaders, aColumnName, eType, bCurrency);
+
+ sal_Int32 nPrecision = 0; //! ...
+ sal_Int32 nDecimals = 0; //! ...
+
+ switch (eType)
+ {
+ case sdbc::DataType::VARCHAR:
+ aTypeName = "VARCHAR";
+ break;
+ case sdbc::DataType::DECIMAL:
+ aTypeName = "DECIMAL";
+ break;
+ case sdbc::DataType::BIT:
+ aTypeName = "BOOL";
+ break;
+ case sdbc::DataType::DATE:
+ aTypeName = "DATE";
+ break;
+ case sdbc::DataType::TIME:
+ aTypeName = "TIME";
+ break;
+ case sdbc::DataType::TIMESTAMP:
+ aTypeName = "TIMESTAMP";
+ break;
+ default:
+ SAL_WARN("connectivity.writer", "missing type name");
+ aTypeName.clear();
+ }
+
+ // check if the column name already exists
+ OUString aAlias = aColumnName;
+ auto aFind = connectivity::find(m_aColumns->begin(), m_aColumns->end(), aAlias, aCase);
+ sal_Int32 nExprCnt = 0;
+ while (aFind != m_aColumns->end())
+ {
+ aAlias = aColumnName + OUString::number(++nExprCnt);
+ aFind = connectivity::find(m_aColumns->begin(), m_aColumns->end(), aAlias, aCase);
+ }
+
+ rtl::Reference<sdbcx::OColumn> pColumn = new sdbcx::OColumn(
+ aAlias, aTypeName, OUString(), OUString(), sdbc::ColumnValue::NULLABLE, nPrecision,
+ nDecimals, eType, false, false, bCurrency, bStoresMixedCaseQuotedIdentifiers,
+ m_CatalogName, getSchema(), getName());
+ m_aColumns->push_back(pColumn);
+ }
+}
+
+OWriterTable::OWriterTable(sdbcx::OCollection* _pTables, OWriterConnection* _pConnection,
+ const OUString& Name, const OUString& Type)
+ : OWriterTable_BASE(_pTables, _pConnection, Name, Type, OUString() /*Description*/,
+ OUString() /*SchemaName*/, OUString() /*CatalogName*/)
+ , m_pWriterConnection(_pConnection)
+{
+}
+
+void OWriterTable::construct()
+{
+ uno::Reference<text::XTextDocument> xDoc = m_pWriterConnection->acquireDoc();
+ if (xDoc.is())
+ {
+ uno::Reference<text::XTextTablesSupplier> xTextTablesSupplier(xDoc, uno::UNO_QUERY);
+ uno::Reference<container::XNameAccess> xTables = xTextTablesSupplier->getTextTables();
+ if (xTables.is() && xTables->hasByName(m_Name))
+ {
+ m_xTable.set(xTables->getByName(m_Name), uno::UNO_QUERY);
+ if (m_xTable.is())
+ {
+ lcl_GetDataArea(m_xTable, m_nDataCols, m_nDataRows);
+ m_bHasHeaders = true;
+ }
+ }
+ }
+
+ fillColumns();
+
+ refreshColumns();
+}
+
+void SAL_CALL OWriterTable::disposing()
+{
+ OFileTable::disposing();
+ ::osl::MutexGuard aGuard(m_aMutex);
+ m_aColumns = nullptr;
+ if (m_pWriterConnection)
+ m_pWriterConnection->releaseDoc();
+ m_pWriterConnection = nullptr;
+}
+
+bool OWriterTable::fetchRow(OValueRefRow& _rRow, const OSQLColumns& _rCols, bool bRetrieveData)
+{
+ // read the bookmark
+
+ _rRow->setDeleted(false);
+ *(*_rRow)[0] = m_nFilePos;
+
+ if (!bRetrieveData)
+ return true;
+
+ // fields
+
+ const OValueRefVector::size_type nCount = std::min(_rRow->size(), _rCols.size() + 1);
+ for (OValueRefVector::size_type i = 1; i < nCount; i++)
+ {
+ if ((*_rRow)[i]->isBound())
+ {
+ lcl_SetValue((*_rRow)[i]->get(), m_xTable, m_nStartCol, m_bHasHeaders, m_nFilePos, i);
+ }
+ }
+ return true;
+}
+
+} // namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/writer/WTables.cxx b/connectivity/source/drivers/writer/WTables.cxx
new file mode 100644
index 0000000000..8b2692d93a
--- /dev/null
+++ b/connectivity/source/drivers/writer/WTables.cxx
@@ -0,0 +1,45 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <writer/WTables.hxx>
+
+#include <sal/config.h>
+
+#include <writer/WConnection.hxx>
+#include <file/FCatalog.hxx>
+#include <writer/WTable.hxx>
+
+using namespace ::com::sun::star;
+
+namespace connectivity::writer
+{
+sdbcx::ObjectType OWriterTables::createObject(const OUString& rName)
+{
+ rtl::Reference<OWriterTable> pTable
+ = new OWriterTable(this,
+ static_cast<OWriterConnection*>(
+ static_cast<file::OFileCatalog&>(m_rParent).getConnection()),
+ rName, "TABLE");
+ pTable->construct();
+ return pTable;
+}
+
+} // namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/writer/writer.component b/connectivity/source/drivers/writer/writer.component
new file mode 100644
index 0000000000..3a0432412b
--- /dev/null
+++ b/connectivity/source/drivers/writer/writer.component
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ -->
+
+<component loader="com.sun.star.loader.SharedLibrary" environment="@CPPU_ENV@"
+ xmlns="http://openoffice.org/2010/uno-components">
+ <implementation name="com.sun.star.comp.sdbc.writer.ODriver"
+ constructor="connectivity_writer_ODriver">
+ <service name="com.sun.star.sdbc.Driver"/>
+ <service name="com.sun.star.sdbcx.Driver"/>
+ </implementation>
+</component>
diff --git a/connectivity/source/inc/AutoRetrievingBase.hxx b/connectivity/source/inc/AutoRetrievingBase.hxx
new file mode 100644
index 0000000000..a85b92c636
--- /dev/null
+++ b/connectivity/source/inc/AutoRetrievingBase.hxx
@@ -0,0 +1,50 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <rtl/ustring.hxx>
+#include <connectivity/dbtoolsdllapi.hxx>
+
+namespace connectivity
+{
+ class OOO_DLLPUBLIC_DBTOOLS OAutoRetrievingBase
+ {
+ OUString m_sGeneratedValueStatement; // contains the statement which should be used when query for automatically generated values
+ bool m_bAutoRetrievingEnabled; // set to when we should allow to query for generated values
+ protected:
+ OAutoRetrievingBase() : m_bAutoRetrievingEnabled(false) {}
+ virtual ~OAutoRetrievingBase(){}
+
+ void enableAutoRetrievingEnabled(bool _bAutoEnable) { m_bAutoRetrievingEnabled = _bAutoEnable; }
+ void setAutoRetrievingStatement(const OUString& _sStmt) { m_sGeneratedValueStatement = _sStmt; }
+ public:
+ bool isAutoRetrievingEnabled() const { return m_bAutoRetrievingEnabled; }
+
+ /** transform the statement to query for auto generated values
+ @param _sInsertStatement
+ The "INSERT" statement, is used to query for column and table names
+ @return
+ The transformed generated statement.
+ */
+ OUString getTransformedGeneratedStatement(const OUString& _sInsertStatement) const;
+ };
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/FDatabaseMetaDataResultSet.hxx b/connectivity/source/inc/FDatabaseMetaDataResultSet.hxx
new file mode 100644
index 0000000000..c469f06716
--- /dev/null
+++ b/connectivity/source/inc/FDatabaseMetaDataResultSet.hxx
@@ -0,0 +1,270 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <vector>
+
+#include <com/sun/star/sdbc/XResultSet.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
+#include <com/sun/star/sdbc/XCloseable.hpp>
+#include <com/sun/star/sdbc/XColumnLocate.hpp>
+#include <com/sun/star/util/XCancellable.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/sdbc/XWarningsSupplier.hpp>
+#include <cppuhelper/compbase.hxx>
+#include <cppuhelper/basemutex.hxx>
+#include <comphelper/proparrhlp.hxx>
+#include <comphelper/propertycontainer.hxx>
+#include <connectivity/FValue.hxx>
+#include <connectivity/dbtoolsdllapi.hxx>
+
+namespace connectivity
+{
+ typedef ::cppu::WeakComponentImplHelper< css::sdbc::XResultSet,
+ css::sdbc::XRow,
+ css::sdbc::XResultSetMetaDataSupplier,
+ css::util::XCancellable,
+ css::sdbc::XWarningsSupplier,
+ css::sdbc::XCloseable,
+ css::lang::XInitialization,
+ css::lang::XServiceInfo,
+ css::sdbc::XColumnLocate> ODatabaseMetaDataResultSet_BASE;
+
+ // typedef ORefVector<ORowSetValue> ORow;
+ // typedef ORefVector<ORow> ORows;
+
+ class OOO_DLLPUBLIC_DBTOOLS ODatabaseMetaDataResultSet :
+ public cppu::BaseMutex,
+ public ODatabaseMetaDataResultSet_BASE,
+ public ::comphelper::OPropertyContainer,
+ public ::comphelper::OPropertyArrayUsageHelper<ODatabaseMetaDataResultSet>
+ {
+
+ public:
+ typedef std::vector<ORowSetValueDecoratorRef> ORow;
+ typedef std::vector<ORow> ORows;
+
+ enum MetaDataResultSetType
+ {
+ /// describes a result set as expected by XDatabaseMetaData::getCatalogs
+ eCatalogs = 0,
+ /// describes a result set as expected by XDatabaseMetaData::getSchemas
+ eSchemas = 1,
+ /// describes a result set as expected by XDatabaseMetaData::getColumnPrivileges
+ eColumnPrivileges = 2,
+ /// describes a result set as expected by XDatabaseMetaData::getColumns
+ eColumns = 3,
+ /// describes a result set as expected by XDatabaseMetaData::getTables
+ eTables = 4,
+ /// describes a result set as expected by XDatabaseMetaData::getTableTypes
+ eTableTypes = 5,
+ /// describes a result set as expected by XDatabaseMetaData::getProcedureColumns
+ eProcedureColumns = 6,
+ /// describes a result set as expected by XDatabaseMetaData::getProcedures
+ eProcedures = 7,
+ /// describes a result set as expected by XDatabaseMetaData::getExportedKeys
+ eExportedKeys = 8,
+ /// describes a result set as expected by XDatabaseMetaData::getImportedKeys
+ eImportedKeys = 9,
+ /// describes a result set as expected by XDatabaseMetaData::getPrimaryKeys
+ ePrimaryKeys = 10,
+ /// describes a result set as expected by XDatabaseMetaData::getIndexInfo
+ eIndexInfo = 11,
+ /// describes a result set as expected by XDatabaseMetaData::getTablePrivileges
+ eTablePrivileges = 12,
+ /// describes a result set as expected by XDatabaseMetaData::getCrossReference
+ eCrossReference = 13,
+ /// describes a result set as expected by XDatabaseMetaData::getTypeInfo
+ eTypeInfo = 14,
+ /// describes a result set as expected by XDatabaseMetaData::getBestRowIdentifier
+ eBestRowIdentifier = 15,
+ /// describes a result set as expected by XDatabaseMetaData::getVersionColumns
+ eVersionColumns = 16,
+ /// describes a result set as expected by XDatabaseMetaData::getUDTs
+ eUDTs = 17
+ };
+
+ private:
+ ORowSetValue m_aEmptyValue;
+ css::uno::WeakReferenceHelper m_aStatement;
+ css::uno::Reference< css::sdbc::XResultSetMetaData> m_xMetaData;
+ sal_Int32 m_nColPos;
+
+ sal_Int32 m_nFetchSize;
+ sal_Int32 m_nResultSetType;
+ sal_Int32 m_nFetchDirection;
+ sal_Int32 m_nResultSetConcurrency;
+
+ void construct();
+ /// @throws css::sdbc::SQLException
+ void checkIndex(sal_Int32 columnIndex );
+ void setType(MetaDataResultSetType _eType);
+
+ protected:
+ ORows m_aRows;
+ ORows::iterator m_aRowsIter;
+ bool m_bBOF;
+ bool m_bEOF;
+
+ virtual const ORowSetValue& getValue(sal_Int32 columnIndex);
+
+ // OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override;
+ // OPropertySetHelper
+ virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override;
+
+ virtual ~ODatabaseMetaDataResultSet() override;
+ public:
+
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+
+ /// default construction
+ ODatabaseMetaDataResultSet();
+ /// construction of a pre-defined result set type
+ ODatabaseMetaDataResultSet( MetaDataResultSetType _eType );
+
+ void setRows(ORows&& _rRows);
+
+ // XServiceInfo
+
+ protected:
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+ // ::cppu::OComponentHelper
+ virtual void SAL_CALL disposing() override;
+ // XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ //XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override;
+ // XPropertySet
+ virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override;
+ // XResultSet
+ virtual sal_Bool SAL_CALL next( ) override;
+ virtual sal_Bool SAL_CALL isBeforeFirst( ) override;
+ virtual sal_Bool SAL_CALL isAfterLast( ) override;
+ virtual sal_Bool SAL_CALL isFirst( ) override;
+ virtual sal_Bool SAL_CALL isLast( ) override;
+ virtual void SAL_CALL beforeFirst( ) override;
+ virtual void SAL_CALL afterLast( ) override;
+ virtual sal_Bool SAL_CALL first( ) override;
+ virtual sal_Bool SAL_CALL last( ) override;
+ virtual sal_Int32 SAL_CALL getRow( ) override;
+ virtual sal_Bool SAL_CALL absolute( sal_Int32 row ) override;
+ virtual sal_Bool SAL_CALL relative( sal_Int32 rows ) override;
+ virtual sal_Bool SAL_CALL previous( ) override;
+ virtual void SAL_CALL refreshRow( ) override;
+ virtual sal_Bool SAL_CALL rowUpdated( ) override;
+ virtual sal_Bool SAL_CALL rowInserted( ) override;
+ virtual sal_Bool SAL_CALL rowDeleted( ) override;
+ virtual css::uno::Reference< css::uno::XInterface > SAL_CALL getStatement( ) override;
+ // XRow
+ virtual sal_Bool SAL_CALL wasNull( ) override;
+ virtual OUString SAL_CALL getString( sal_Int32 columnIndex ) override;
+ virtual sal_Bool SAL_CALL getBoolean( sal_Int32 columnIndex ) override;
+ virtual sal_Int8 SAL_CALL getByte( sal_Int32 columnIndex ) override;
+ virtual sal_Int16 SAL_CALL getShort( sal_Int32 columnIndex ) override;
+ virtual sal_Int32 SAL_CALL getInt( sal_Int32 columnIndex ) override;
+ virtual sal_Int64 SAL_CALL getLong( sal_Int32 columnIndex ) override;
+ virtual float SAL_CALL getFloat( sal_Int32 columnIndex ) override;
+ virtual double SAL_CALL getDouble( sal_Int32 columnIndex ) override;
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getBytes( sal_Int32 columnIndex ) override;
+ virtual css::util::Date SAL_CALL getDate( sal_Int32 columnIndex ) override;
+ virtual css::util::Time SAL_CALL getTime( sal_Int32 columnIndex ) override;
+ virtual css::util::DateTime SAL_CALL getTimestamp( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getBinaryStream( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getCharacterStream( sal_Int32 columnIndex ) override;
+ virtual css::uno::Any SAL_CALL getObject( sal_Int32 columnIndex, const css::uno::Reference< css::container::XNameAccess >& typeMap ) override;
+ virtual css::uno::Reference< css::sdbc::XRef > SAL_CALL getRef( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XBlob > SAL_CALL getBlob( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XClob > SAL_CALL getClob( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XArray > SAL_CALL getArray( sal_Int32 columnIndex ) override;
+ // XResultSetMetaDataSupplier
+ virtual css::uno::Reference< css::sdbc::XResultSetMetaData > SAL_CALL getMetaData( ) override;
+ // XCancellable
+ virtual void SAL_CALL cancel( ) override;
+ // XCloseable
+ virtual void SAL_CALL close( ) override;
+ // XWarningsSupplier
+ virtual css::uno::Any SAL_CALL getWarnings( ) override;
+ virtual void SAL_CALL clearWarnings( ) override;
+ // XColumnLocate
+ virtual sal_Int32 SAL_CALL findColumn( const OUString& columnName ) override;
+
+ // XInitialization
+ virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override;
+
+ void setCatalogsMap();
+ void setSchemasMap();
+ void setColumnPrivilegesMap();
+ void setColumnsMap();
+ void setTablesMap();
+ void setTableTypes();
+ void setProcedureColumnsMap();
+ void setProceduresMap();
+ void setExportedKeysMap();
+ void setImportedKeysMap();
+ void setPrimaryKeysMap();
+ void setIndexInfoMap();
+ void setTablePrivilegesMap();
+ void setCrossReferenceMap();
+ void setTypeInfoMap();
+ void setBestRowIdentifierMap();
+ void setVersionColumnsMap();
+ void setUDTsMap();
+ public:
+ // some methods to get already defined ORowSetValues
+ // this increase the reuse of ORowSetValues
+ /// return an empty ORowSetValueDecorator
+ static ORowSetValueDecoratorRef const & getEmptyValue();
+ /// return an ORowSetValueDecorator with 0 as value
+ static ORowSetValueDecoratorRef const & get0Value();
+ /// return an ORowSetValueDecorator with 1 as value
+ static ORowSetValueDecoratorRef const & get1Value();
+ /// return an ORowSetValueDecorator with ColumnSearch::BASIC as value
+ static ORowSetValueDecoratorRef const & getBasicValue();
+ /// return an ORowSetValueDecorator with string SELECT as value
+ static ORowSetValueDecoratorRef const & getSelectValue();
+ /// return an ORowSetValueDecorator with string INSERT as value
+ static ORowSetValueDecoratorRef const & getInsertValue();
+ /// return an ORowSetValueDecorator with string DELETE as value
+ static ORowSetValueDecoratorRef const & getDeleteValue();
+ /// return an ORowSetValueDecorator with string UPDATE as value
+ static ORowSetValueDecoratorRef const & getUpdateValue();
+ /// return an ORowSetValueDecorator with string CREATE as value
+ static ORowSetValueDecoratorRef const & getCreateValue();
+ /// return an ORowSetValueDecorator with string READ as value
+ static ORowSetValueDecoratorRef const & getReadValue();
+ /// return an ORowSetValueDecorator with string ALTER as value
+ static ORowSetValueDecoratorRef const & getAlterValue();
+ /// return an ORowSetValueDecorator with string DROP as value
+ static ORowSetValueDecoratorRef const & getDropValue();
+ /// return an ORowSetValueDecorator with string ' as value
+ static ORowSetValueDecoratorRef const & getQuoteValue();
+
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/FDatabaseMetaDataResultSetMetaData.hxx b/connectivity/source/inc/FDatabaseMetaDataResultSetMetaData.hxx
new file mode 100644
index 0000000000..9de1226722
--- /dev/null
+++ b/connectivity/source/inc/FDatabaseMetaDataResultSetMetaData.hxx
@@ -0,0 +1,96 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/sdbc/XResultSetMetaData.hpp>
+#include <cppuhelper/implbase.hxx>
+#include <map>
+#include <vector>
+#include "OColumn.hxx"
+
+namespace connectivity
+{
+
+ //************ Class: ODatabaseMetaDataResultSetMetaData
+
+ typedef ::cppu::WeakImplHelper< css::sdbc::XResultSetMetaData> ODatabaseMetaResultSetMetaData_BASE;
+
+ class ODatabaseMetaDataResultSetMetaData : public ODatabaseMetaResultSetMetaData_BASE
+ {
+ std::map<sal_Int32,connectivity::OColumn> m_mColumns;
+ std::map<sal_Int32,connectivity::OColumn>::const_iterator m_mColumnsIter;
+
+ protected:
+ virtual ~ODatabaseMetaDataResultSetMetaData() override;
+ public:
+ // a Constructor, that is needed for when returning the object is needed:
+ ODatabaseMetaDataResultSetMetaData( )
+ {
+ }
+
+ virtual sal_Int32 SAL_CALL getColumnCount( ) override;
+ virtual sal_Bool SAL_CALL isAutoIncrement( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isCaseSensitive( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isSearchable( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isCurrency( sal_Int32 column ) override;
+ virtual sal_Int32 SAL_CALL isNullable( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isSigned( sal_Int32 column ) override;
+ virtual sal_Int32 SAL_CALL getColumnDisplaySize( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getColumnLabel( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getColumnName( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getSchemaName( sal_Int32 column ) override;
+ virtual sal_Int32 SAL_CALL getPrecision( sal_Int32 column ) override;
+ virtual sal_Int32 SAL_CALL getScale( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getTableName( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getCatalogName( sal_Int32 column ) override;
+ virtual sal_Int32 SAL_CALL getColumnType( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getColumnTypeName( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isReadOnly( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isWritable( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isDefinitelyWritable( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getColumnServiceName( sal_Int32 column ) override;
+
+ // methods to set the right column mapping
+ void setColumnPrivilegesMap();
+ void setColumnMap();
+ void setColumnsMap();
+ void setTableNameMap();
+ void setTablesMap();
+ void setProcedureColumnsMap();
+ void setPrimaryKeysMap();
+ void setIndexInfoMap();
+ void setTablePrivilegesMap();
+ void setCrossReferenceMap();
+ void setTypeInfoMap();
+ void setProcedureNameMap();
+ void setProceduresMap();
+ void setTableTypes();
+ void setBestRowIdentifierMap() { setVersionColumnsMap();}
+ void setVersionColumnsMap();
+ void setExportedKeysMap() { setCrossReferenceMap(); }
+ void setImportedKeysMap() { setCrossReferenceMap(); }
+ void setCatalogsMap();
+ void setSchemasMap();
+ void setUDTsMap();
+ };
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/OColumn.hxx b/connectivity/source/inc/OColumn.hxx
new file mode 100644
index 0000000000..2131b3e152
--- /dev/null
+++ b/connectivity/source/inc/OColumn.hxx
@@ -0,0 +1,119 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <rtl/ustring.hxx>
+#include <sal/types.h>
+#include <connectivity/dbtoolsdllapi.hxx>
+#include <utility>
+
+namespace connectivity
+{
+ class OOO_DLLPUBLIC_DBTOOLS OColumn
+ {
+ OUString m_TableName;
+ OUString m_ColumnName;
+ OUString m_ColumnLabel;
+
+ sal_Int32 m_Nullable;
+ sal_Int32 m_ColumnDisplaySize;
+ sal_Int32 m_Precision;
+ sal_Int32 m_Scale;
+ sal_Int32 m_ColumnType;
+
+ bool m_AutoIncrement;
+ bool m_CaseSensitive;
+ bool m_Searchable;
+ bool m_Currency;
+ bool m_Signed;
+ bool m_ReadOnly;
+ bool m_Writable;
+ bool m_DefinitelyWritable;
+
+ public:
+ OColumn()
+ : m_Nullable(0)
+ , m_ColumnDisplaySize(0)
+ , m_Precision(0)
+ , m_Scale(0)
+ , m_ColumnType(0)
+
+ , m_AutoIncrement(false)
+ , m_CaseSensitive(false)
+ , m_Searchable(true)
+ , m_Currency(false)
+ , m_Signed(false)
+ , m_ReadOnly(true)
+ , m_Writable(false)
+ , m_DefinitelyWritable(false)
+ {}
+
+ OColumn(OUString _aTableName,
+ const OUString &_aColumnName,
+ sal_Int32 _aNullable,
+ sal_Int32 _aColumnDisplaySize,
+ sal_Int32 _aPrecision,
+ sal_Int32 _aScale,
+ sal_Int32 _aColumnType)
+ : m_TableName(std::move(_aTableName)),
+ m_ColumnName(_aColumnName),
+ m_ColumnLabel(),
+
+ m_Nullable(_aNullable),
+ m_ColumnDisplaySize(_aColumnDisplaySize),
+ m_Precision(_aPrecision),
+ m_Scale(_aScale),
+ m_ColumnType(_aColumnType),
+
+ m_AutoIncrement(false),
+ m_CaseSensitive(false),
+ m_Searchable(true),
+ m_Currency(false),
+ m_Signed(false),
+ m_ReadOnly(true),
+ m_Writable(false),
+ m_DefinitelyWritable(false)
+ {
+ if(m_ColumnLabel.isEmpty())
+ m_ColumnLabel = _aColumnName;
+ }
+
+ bool isAutoIncrement() const { return m_AutoIncrement; }
+ bool isCaseSensitive() const { return m_CaseSensitive; }
+ bool isSearchable() const { return m_Searchable; }
+ bool isCurrency() const { return m_Currency; }
+ bool isSigned() const { return m_Signed; }
+ bool isReadOnly() const { return m_ReadOnly; }
+ bool isWritable() const { return m_Writable; }
+ bool isDefinitelyWritable() const { return m_DefinitelyWritable; }
+
+ sal_Int32 isNullable() const { return m_Nullable; }
+ sal_Int32 getColumnDisplaySize() const { return m_ColumnDisplaySize; }
+ sal_Int32 getPrecision() const { return m_Precision; }
+ sal_Int32 getScale() const { return m_Scale; }
+ sal_Int32 getColumnType() const { return m_ColumnType; }
+
+ const OUString& getColumnLabel() const { return m_ColumnLabel; }
+ const OUString& getColumnName() const { return m_ColumnName; }
+ const OUString& getTableName() const { return m_TableName; }
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/OTypeInfo.hxx b/connectivity/source/inc/OTypeInfo.hxx
new file mode 100644
index 0000000000..4e9cbdf05e
--- /dev/null
+++ b/connectivity/source/inc/OTypeInfo.hxx
@@ -0,0 +1,50 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/sdbc/DataType.hpp>
+
+#include <rtl/ustring.hxx>
+
+namespace connectivity
+{
+ struct OTypeInfo
+ {
+ OUString aTypeName; // Name of the type in the database
+ OUString aLocalTypeName;
+
+ sal_Int32 nPrecision; // Length of the type
+
+ sal_Int16 nMaximumScale; // Decimal places
+
+ sal_Int16 nType; // Database type
+
+ OTypeInfo()
+ :nPrecision(0)
+ ,nMaximumScale(0)
+ ,nType( css::sdbc::DataType::OTHER)
+ {}
+
+ bool operator == (const OTypeInfo& lh) const { return lh.nType == nType; }
+ bool operator != (const OTypeInfo& lh) const { return lh.nType != nType; }
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/ParameterSubstitution.hxx b/connectivity/source/inc/ParameterSubstitution.hxx
new file mode 100644
index 0000000000..a76bd09398
--- /dev/null
+++ b/connectivity/source/inc/ParameterSubstitution.hxx
@@ -0,0 +1,63 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/util/XStringSubstitution.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/weakref.hxx>
+
+namespace connectivity
+{
+ typedef ::cppu::WeakImplHelper< css::util::XStringSubstitution
+ ,css::lang::XServiceInfo
+ ,css::lang::XInitialization > ParameterSubstitution_BASE;
+ class ParameterSubstitution final : public ParameterSubstitution_BASE
+ {
+ ::osl::Mutex m_aMutex;
+ css::uno::Reference< css::uno::XComponentContext > m_xContext;
+ css::uno::WeakReference< css::sdbc::XConnection > m_xConnection;
+
+ ParameterSubstitution( const ParameterSubstitution& ) = delete;
+ ParameterSubstitution& operator=( const ParameterSubstitution& ) = delete;
+ public:
+ ParameterSubstitution(css::uno::Reference< css::uno::XComponentContext > _rContext );
+ private:
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+ // XInitialization
+ virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override;
+
+ // XStringSubstitution
+ virtual OUString SAL_CALL substituteVariables( const OUString& aText, sal_Bool bSubstRequired ) override;
+ virtual OUString SAL_CALL reSubstituteVariables( const OUString& aText ) override;
+ virtual OUString SAL_CALL getSubstituteVariableValue( const OUString& variable ) override;
+ };
+
+} // connectivity
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/RowFunctionParser.hxx b/connectivity/source/inc/RowFunctionParser.hxx
new file mode 100644
index 0000000000..059544e51f
--- /dev/null
+++ b/connectivity/source/inc/RowFunctionParser.hxx
@@ -0,0 +1,109 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+#include "FDatabaseMetaDataResultSet.hxx"
+#include <connectivity/dbtoolsdllapi.hxx>
+#include <memory>
+
+namespace connectivity
+{
+enum class ExpressionFunct
+{
+ Equation,
+ And,
+ Or
+};
+
+#define EXPRESSION_FLAG_SUMANGLE_MODE 1
+
+class OOO_DLLPUBLIC_DBTOOLS SAL_NO_VTABLE ExpressionNode
+{
+public:
+ virtual ~ExpressionNode() {}
+
+ /** Operator to calculate function value.
+
+ This method calculates the function value.
+ */
+ virtual ORowSetValueDecoratorRef
+ evaluate(const ODatabaseMetaDataResultSet::ORow& _aRow) const = 0;
+
+ virtual void fill(const ODatabaseMetaDataResultSet::ORow& _aRow) const = 0;
+};
+
+/** This exception is thrown, when the arithmetic expression
+ parser failed to parse a string.
+ */
+struct OOO_DLLPUBLIC_DBTOOLS ParseError
+{
+ ParseError(const char*) {}
+};
+
+class FunctionParser
+{
+public:
+ /** Parse a string
+
+ The following grammar is accepted by this method:
+ <code>
+
+ number_digit = '0'|'1'|'2'|'3'|'4'|'5'|'6'|'7'|'8'|'9'
+
+ number = number number_digit | number_digit
+
+ equal_function = '='
+ ternary_function = 'if'
+
+ string_reference = 'a-z,A-Z,0-9' ' '
+ modifier_reference = '$' '0-9' ' '
+
+ basic_expression =
+ number |
+ string_reference |
+ additive_expression equal_function additive_expression |
+ unary_function '(' number_digit ')'
+ ternary_function '(' additive_expression ',' additive_expression ',
+ ' additive_expression ')' | '(' additive_expression ')'
+
+ </code>
+
+ @param rFunction
+ The string to parse
+
+ @throws ParseError if an invalid expression is given.
+
+ @return the generated function object.
+ */
+
+ static std::shared_ptr<ExpressionNode> const& parseFunction(const OUString& _sFunction);
+
+private:
+ // disabled constructor/destructor, since this is
+ // supposed to be a singleton
+ FunctionParser() = delete;
+ FunctionParser(const FunctionParser&) = delete;
+ FunctionParser& operator=(const FunctionParser&) = delete;
+};
+
+} // namespace connectivity
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/TConnection.hxx b/connectivity/source/inc/TConnection.hxx
new file mode 100644
index 0000000000..2dbe2ef6a7
--- /dev/null
+++ b/connectivity/source/inc/TConnection.hxx
@@ -0,0 +1,81 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <rtl/textenc.h>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/lang/XUnoTunnel.hpp>
+#include <com/sun/star/sdbc/XWarningsSupplier.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <cppuhelper/compbase.hxx>
+#include "propertyids.hxx"
+#include <connectivity/CommonTools.hxx>
+#include <connectivity/dbtoolsdllapi.hxx>
+#include "resource/sharedresources.hxx"
+
+namespace connectivity
+{
+ typedef ::cppu::WeakComponentImplHelper< css::sdbc::XConnection,
+ css::sdbc::XWarningsSupplier,
+ css::lang::XServiceInfo,
+ css::lang::XUnoTunnel
+ > OMetaConnection_BASE;
+
+ class OOO_DLLPUBLIC_DBTOOLS OMetaConnection : public OMetaConnection_BASE
+ {
+ protected:
+ ::osl::Mutex m_aMutex;
+ css::uno::Sequence< css::beans::PropertyValue >
+ m_aConnectionInfo;
+ connectivity::OWeakRefArray m_aStatements; // vector containing a list
+ // of all the Statement objects
+ // for this Connection
+ OUString m_sURL;
+ rtl_TextEncoding m_nTextEncoding; // the encoding which is used for all text conversions
+ css::uno::WeakReference< css::sdbc::XDatabaseMetaData >
+ m_xMetaData;
+ SharedResources m_aResources;
+ public:
+
+ static ::dbtools::OPropertyMap& getPropMap();
+
+ OMetaConnection();
+
+ rtl_TextEncoding getTextEncoding() const { return m_nTextEncoding; }
+ const OUString& getURL() const { return m_sURL; }
+ void setURL(const OUString& _rsUrl) { m_sURL = _rsUrl; }
+ void throwGenericSQLException(TranslateId pErrorResourceId, const css::uno::Reference< css::uno::XInterface>& _xContext);
+ const SharedResources& getResources() const { return m_aResources;}
+
+ void setConnectionInfo(const css::uno::Sequence< css::beans::PropertyValue >& _aInfo) { m_aConnectionInfo = _aInfo; }
+ const css::uno::Sequence< css::beans::PropertyValue >&
+ getConnectionInfo() const { return m_aConnectionInfo; }
+
+ // OComponentHelper
+ virtual void SAL_CALL disposing() override;
+
+ //XUnoTunnel
+ virtual sal_Int64 SAL_CALL getSomething( const css::uno::Sequence< sal_Int8 >& aIdentifier ) override;
+ static const css::uno::Sequence< sal_Int8 > & getUnoTunnelId();
+ };
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/TDatabaseMetaDataBase.hxx b/connectivity/source/inc/TDatabaseMetaDataBase.hxx
new file mode 100644
index 0000000000..4d8c7715ca
--- /dev/null
+++ b/connectivity/source/inc/TDatabaseMetaDataBase.hxx
@@ -0,0 +1,133 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/sdbc/XDatabaseMetaData2.hpp>
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/basemutex.hxx>
+#include <com/sun/star/lang/XEventListener.hpp>
+#include "FDatabaseMetaDataResultSet.hxx"
+#include <functional>
+#include <connectivity/dbtoolsdllapi.hxx>
+
+namespace connectivity
+{
+ class OOO_DLLPUBLIC_DBTOOLS ODatabaseMetaDataBase :
+ public cppu::BaseMutex,
+ public ::cppu::WeakImplHelper< css::sdbc::XDatabaseMetaData2,
+ css::lang::XEventListener>
+ {
+ private:
+ css::uno::Sequence< css::beans::PropertyValue > m_aConnectionInfo;
+ ::connectivity::ODatabaseMetaDataResultSet::ORows m_aTypeInfoRows;
+
+ // cached database information
+ std::pair<bool,bool> m_isCatalogAtStart;
+ std::pair<bool,OUString> m_sCatalogSeparator;
+ std::pair<bool,OUString> m_sIdentifierQuoteString;
+ std::pair<bool,bool> m_supportsCatalogsInTableDefinitions;
+ std::pair<bool,bool> m_supportsSchemasInTableDefinitions;
+ std::pair<bool,bool> m_supportsCatalogsInDataManipulation;
+ std::pair<bool,bool> m_supportsSchemasInDataManipulation;
+ std::pair<bool,bool> m_supportsMixedCaseQuotedIdentifiers;
+ std::pair<bool,bool> m_supportsAlterTableWithAddColumn;
+ std::pair<bool,bool> m_supportsAlterTableWithDropColumn;
+ std::pair<bool,sal_Int32> m_MaxStatements;
+ std::pair<bool,sal_Int32> m_MaxTablesInSelect;
+ std::pair<bool,bool> m_storesMixedCaseQuotedIdentifiers;
+
+ template <typename T> T callImplMethod(std::pair<bool,T>& _rCache,const std::function<T(ODatabaseMetaDataBase *)>& _pImplMethod)
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( !_rCache.first )
+ {
+ _rCache.second = _pImplMethod(this);
+ _rCache.first = true;
+ }
+ return _rCache.second;
+ }
+ protected:
+ css::uno::Reference< css::sdbc::XConnection > m_xConnection;
+ css::uno::Reference< css::lang::XEventListener> m_xListenerHelper; // forward the calls from the connection to me
+
+ virtual ~ODatabaseMetaDataBase() override;
+
+ protected:
+ virtual css::uno::Reference< css::sdbc::XResultSet > impl_getTypeInfo_throw() = 0;
+ // cached database information
+ virtual OUString impl_getIdentifierQuoteString_throw( ) = 0;
+ virtual bool impl_isCatalogAtStart_throw( ) = 0;
+ virtual OUString impl_getCatalogSeparator_throw( ) = 0;
+ virtual bool impl_supportsCatalogsInTableDefinitions_throw( ) = 0;
+ virtual bool impl_supportsSchemasInTableDefinitions_throw( ) = 0;
+ virtual bool impl_supportsCatalogsInDataManipulation_throw( ) = 0;
+ virtual bool impl_supportsSchemasInDataManipulation_throw( ) = 0;
+ virtual bool impl_supportsMixedCaseQuotedIdentifiers_throw( ) = 0;
+ virtual bool impl_supportsAlterTableWithAddColumn_throw( ) = 0;
+ virtual bool impl_supportsAlterTableWithDropColumn_throw( ) = 0;
+ virtual sal_Int32 impl_getMaxStatements_throw( ) = 0;
+ virtual sal_Int32 impl_getMaxTablesInSelect_throw( ) = 0;
+ virtual bool impl_storesMixedCaseQuotedIdentifiers_throw( ) = 0;
+
+
+ public:
+
+ ODatabaseMetaDataBase(const css::uno::Reference< css::sdbc::XConnection >& _rxConnection,const css::uno::Sequence< css::beans::PropertyValue >& _rInfo);
+
+ // XDatabaseMetaData2
+ virtual css::uno::Sequence< css::beans::PropertyValue > SAL_CALL getConnectionInfo( ) override;
+
+ // XEventListener
+ virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override;
+
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getTypeInfo( ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getProcedures( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& procedureNamePattern ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getProcedureColumns( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& procedureNamePattern, const OUString& columnNamePattern ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getSchemas( ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getCatalogs( ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getColumnPrivileges( const css::uno::Any& catalog, const OUString& schema, const OUString& table, const OUString& columnNamePattern ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getTablePrivileges( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& tableNamePattern ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getBestRowIdentifier( const css::uno::Any& catalog, const OUString& schema, const OUString& table, sal_Int32 scope, sal_Bool nullable ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getVersionColumns( const css::uno::Any& catalog, const OUString& schema, const OUString& table ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getPrimaryKeys( const css::uno::Any& catalog, const OUString& schema, const OUString& table ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getImportedKeys( const css::uno::Any& catalog, const OUString& schema, const OUString& table ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getExportedKeys( const css::uno::Any& catalog, const OUString& schema, const OUString& table ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getCrossReference( const css::uno::Any& primaryCatalog, const OUString& primarySchema, const OUString& primaryTable, const css::uno::Any& foreignCatalog, const OUString& foreignSchema, const OUString& foreignTable ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getIndexInfo( const css::uno::Any& catalog, const OUString& schema, const OUString& table, sal_Bool unique, sal_Bool approximate ) override;
+
+ virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL getConnection( ) override;
+ // cached database information
+ virtual OUString SAL_CALL getIdentifierQuoteString( ) override;
+ virtual sal_Bool SAL_CALL isCatalogAtStart( ) override;
+ virtual OUString SAL_CALL getCatalogSeparator( ) override;
+ virtual sal_Bool SAL_CALL supportsCatalogsInTableDefinitions( ) override;
+ virtual sal_Bool SAL_CALL supportsSchemasInTableDefinitions( ) override;
+ virtual sal_Bool SAL_CALL supportsCatalogsInDataManipulation( ) override;
+ virtual sal_Bool SAL_CALL supportsSchemasInDataManipulation( ) override;
+ virtual sal_Bool SAL_CALL supportsMixedCaseQuotedIdentifiers( ) override;
+ virtual sal_Bool SAL_CALL supportsAlterTableWithAddColumn( ) override;
+ virtual sal_Bool SAL_CALL supportsAlterTableWithDropColumn( ) override;
+ virtual sal_Int32 SAL_CALL getMaxStatements( ) override;
+ virtual sal_Int32 SAL_CALL getMaxTablesInSelect( ) override;
+ virtual sal_Bool SAL_CALL storesMixedCaseQuotedIdentifiers( ) override;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/TKeyValue.hxx b/connectivity/source/inc/TKeyValue.hxx
new file mode 100644
index 0000000000..49d41e0144
--- /dev/null
+++ b/connectivity/source/inc/TKeyValue.hxx
@@ -0,0 +1,59 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <connectivity/FValue.hxx>
+#include <connectivity/dbtoolsdllapi.hxx>
+#include <osl/diagnose.h>
+
+namespace connectivity
+{
+ class OOO_DLLPUBLIC_DBTOOLS OKeyValue final
+ {
+ std::vector<ORowSetValueDecoratorRef> m_aKeys;
+ sal_Int32 m_nValue;
+
+ OKeyValue(sal_Int32 nVal);
+ public:
+
+ ~OKeyValue();
+
+ static std::unique_ptr<OKeyValue> createKeyValue(sal_Int32 nVal);
+
+ void pushKey(const ORowSetValueDecoratorRef& _aValueRef)
+ {
+ m_aKeys.push_back(_aValueRef);
+ }
+
+ OUString getKeyString(std::vector<ORowSetValueDecoratorRef>::size_type i) const
+ {
+ OSL_ENSURE(m_aKeys.size() > i,"Wrong index for KEyValue");
+ return m_aKeys[i]->getValue().getString();
+ }
+ double getKeyDouble(std::vector<ORowSetValueDecoratorRef>::size_type i) const
+ {
+ OSL_ENSURE(m_aKeys.size() > i,"Wrong index for KEyValue");
+ return m_aKeys[i]->getValue().getDouble();
+ }
+
+ sal_Int32 getValue() const { return m_nValue; }
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/TPrivilegesResultSet.hxx b/connectivity/source/inc/TPrivilegesResultSet.hxx
new file mode 100644
index 0000000000..b7206b7de4
--- /dev/null
+++ b/connectivity/source/inc/TPrivilegesResultSet.hxx
@@ -0,0 +1,46 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include "FDatabaseMetaDataResultSet.hxx"
+#include <com/sun/star/sdbc/XDatabaseMetaData.hpp>
+#include <connectivity/dbtoolsdllapi.hxx>
+
+namespace connectivity
+{
+ class OOO_DLLPUBLIC_DBTOOLS OResultSetPrivileges :
+ public ODatabaseMetaDataResultSet
+ {
+ css::uno::Reference< css::sdbc::XResultSet> m_xTables;
+ css::uno::Reference< css::sdbc::XRow> m_xRow;
+ bool m_bResetValues;
+ protected:
+ virtual const ORowSetValue& getValue(sal_Int32 columnIndex) override;
+ public:
+ OResultSetPrivileges(const css::uno::Reference< css::sdbc::XDatabaseMetaData>& _rxMeta
+ ,const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& tableNamePattern);
+
+ // ::cppu::OComponentHelper
+ virtual void SAL_CALL disposing() override;
+ // XResultSet
+ virtual sal_Bool SAL_CALL next( ) override;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/TResultSetHelper.hxx b/connectivity/source/inc/TResultSetHelper.hxx
new file mode 100644
index 0000000000..cedea10272
--- /dev/null
+++ b/connectivity/source/inc/TResultSetHelper.hxx
@@ -0,0 +1,51 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/types.h>
+#include <connectivity/dbtoolsdllapi.hxx>
+
+namespace connectivity
+{
+ class OOO_DLLPUBLIC_DBTOOLS SAL_NO_VTABLE IResultSetHelper
+ {
+ public:
+ enum Movement
+ {
+ NEXT = 0,
+ PRIOR,
+ FIRST,
+ LAST,
+ // Named like this to avoid conflict with a #define in the Windows system ODBC headers.
+ RELATIVE1,
+ ABSOLUTE1,
+ BOOKMARK,
+ };
+ public:
+ virtual bool move(Movement _eCursorPosition, sal_Int32 _nOffset, bool _bRetrieveData) = 0;
+ virtual sal_Int32 getDriverPos() const = 0;
+ virtual bool isRowDeleted() const = 0;
+
+ protected:
+ ~IResultSetHelper() {}
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/TSkipDeletedSet.hxx b/connectivity/source/inc/TSkipDeletedSet.hxx
new file mode 100644
index 0000000000..efe142af54
--- /dev/null
+++ b/connectivity/source/inc/TSkipDeletedSet.hxx
@@ -0,0 +1,80 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include "TResultSetHelper.hxx"
+#include <vector>
+#include <connectivity/dbtoolsdllapi.hxx>
+
+namespace connectivity
+{
+ /**
+ the class OSkipDeletedSet supports a general method to skip deleted rows
+ */
+ class OOO_DLLPUBLIC_DBTOOLS OSkipDeletedSet
+ {
+ std::vector<sal_Int32> m_aBookmarksPositions;// vector of iterators to position map, the order is the logical position
+ IResultSetHelper* m_pHelper; // used for moving in the resultset
+ bool m_bDeletedVisible;
+
+ bool moveAbsolute(sal_Int32 _nOffset,bool _bRetrieveData);
+ public:
+ OSkipDeletedSet(IResultSetHelper* _pHelper);
+ ~OSkipDeletedSet();
+
+ /**
+ skipDeleted moves the resultset to the position defined by the parameters
+ it guarantees that the row isn't deleted
+ @param
+ IResultSetHelper::Movement _eCursorPosition in which direction the resultset should be moved
+ sal_Int32 _nOffset the position relative to the movement
+ sal_Bool _bRetrieveData is true when the current row should be filled which data
+ @return
+ true when the movement was successful otherwise false
+ */
+ bool skipDeleted(IResultSetHelper::Movement _eCursorPosition, sal_Int32 _nOffset, bool _bRetrieveData);
+ /**
+ clear the map and the vector used in this class
+ */
+ void clear();
+ /**
+ getMappedPosition returns the mapped position of a logical position
+ @param
+ sal_Int32 _nBookmark the logical position
+
+ @return the mapped position
+ */
+ sal_Int32 getMappedPosition(sal_Int32 _nBookmark) const;
+ /**
+ insertNewPosition adds a new position to the map
+ @param
+ sal_Int32 _nPos the logical position
+ */
+ void insertNewPosition(sal_Int32 _nPos);
+ /**
+ deletePosition deletes this position from the map and decrement all following positions
+ @param
+ sal_Int32 _nPos the logical position
+ */
+ void deletePosition(sal_Int32 _nPos);
+ void SetDeletedVisible(bool _bDeletedVisible) { m_bDeletedVisible = _bDeletedVisible; }
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/TSortIndex.hxx b/connectivity/source/inc/TSortIndex.hxx
new file mode 100644
index 0000000000..3ac339f7e9
--- /dev/null
+++ b/connectivity/source/inc/TSortIndex.hxx
@@ -0,0 +1,110 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <connectivity/dbtoolsdllapi.hxx>
+#include "TKeyValue.hxx"
+
+namespace connectivity
+{
+ enum class OKeyType
+ {
+ NONE, // do not sort
+ Double, // numeric key
+ String // String Key
+ };
+
+ enum class TAscendingOrder
+ {
+ ASC = 1, // ascending
+ DESC = -1 // otherwise
+ };
+
+ class OKeySet;
+ class OKeyValue; // simple class which holds a sal_Int32 and a std::vector<ORowSetValueDecoratorRef>
+
+ /**
+ The class OSortIndex can be used to implement a sorted index.
+ This can depend on the fields which should be sorted.
+ */
+ class OOO_DLLPUBLIC_DBTOOLS OSortIndex
+ {
+ public:
+ typedef std::vector<std::pair<sal_Int32, std::unique_ptr<OKeyValue>>> TIntValuePairVector;
+ typedef std::vector<OKeyType> TKeyTypeVector;
+
+ private:
+ TIntValuePairVector m_aKeyValues;
+ TKeyTypeVector m_aKeyType;
+ std::vector<TAscendingOrder> m_aAscending;
+ bool m_bFrozen;
+
+ public:
+
+ OSortIndex( std::vector<OKeyType>&& _aKeyType,
+ std::vector<TAscendingOrder>&& _aAscending);
+ OSortIndex(OSortIndex const &) = delete; // MSVC2015 workaround
+ OSortIndex& operator=(OSortIndex const &) = delete; // MSVC2015 workaround
+
+ ~OSortIndex();
+
+ /**
+ AddKeyValue appends a new value.
+ @param
+ pKeyValue the keyvalue to be appended
+ ATTENTION: when the sortindex is already frozen the parameter will be deleted
+ */
+ void AddKeyValue(std::unique_ptr<OKeyValue> pKeyValue);
+
+ /**
+ Freeze freezes the sortindex so that new values could only be appended by their value
+ */
+ void Freeze();
+
+ /**
+ CreateKeySet creates the keyset which values could be used to travel in your table/result
+ The returned keyset is frozen.
+ */
+ ::rtl::Reference<OKeySet> CreateKeySet();
+
+ const std::vector<OKeyType>& getKeyType() const { return m_aKeyType; }
+ TAscendingOrder getAscending(std::vector<TAscendingOrder>::size_type _nPos) const { return m_aAscending[_nPos]; }
+
+ };
+
+ // MSVC hack to avoid multiply defined std::vector-related symbols:
+ class OKeySet_Base: public ORefVector<sal_Int32> {};
+
+ /**
+ The class OKeySet is a refcountable vector which also has a state.
+ This state gives information about if the keyset is fixed.
+ */
+ class OOO_DLLPUBLIC_DBTOOLS OKeySet : public OKeySet_Base
+ {
+ bool m_bFrozen;
+ public:
+ OKeySet()
+ : m_bFrozen(false){}
+
+ bool isFrozen() const { return m_bFrozen; }
+ void setFrozen() { m_bFrozen = true; }
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/ado/ACallableStatement.hxx b/connectivity/source/inc/ado/ACallableStatement.hxx
new file mode 100644
index 0000000000..e58617b3b0
--- /dev/null
+++ b/connectivity/source/inc/ado/ACallableStatement.hxx
@@ -0,0 +1,76 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <ado/APreparedStatement.hxx>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XOutParameters.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+
+namespace connectivity::ado
+{
+
+ //************ Class: java.sql.CallableStatement
+
+
+ class OCallableStatement : public OPreparedStatement,
+ public css::sdbc::XRow,
+ public css::sdbc::XOutParameters
+ {
+ OLEVariant m_aValue;
+ public:
+ DECLARE_SERVICE_INFO();
+
+ // a Constructor, that is needed for when Returning the Object is needed:
+ OCallableStatement( OConnection* _pConnection, const OUString& sql );
+
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+
+ // XRow
+ virtual sal_Bool SAL_CALL wasNull( ) override;
+ virtual OUString SAL_CALL getString( sal_Int32 columnIndex ) override;
+ virtual sal_Bool SAL_CALL getBoolean( sal_Int32 columnIndex ) override;
+ virtual sal_Int8 SAL_CALL getByte( sal_Int32 columnIndex ) override;
+ virtual sal_Int16 SAL_CALL getShort( sal_Int32 columnIndex ) override;
+ virtual sal_Int32 SAL_CALL getInt( sal_Int32 columnIndex ) override;
+ virtual sal_Int64 SAL_CALL getLong( sal_Int32 columnIndex ) override;
+ virtual float SAL_CALL getFloat( sal_Int32 columnIndex ) override;
+ virtual double SAL_CALL getDouble( sal_Int32 columnIndex ) override;
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getBytes( sal_Int32 columnIndex ) override;
+ virtual css::util::Date SAL_CALL getDate( sal_Int32 columnIndex ) override;
+ virtual css::util::Time SAL_CALL getTime( sal_Int32 columnIndex ) override;
+ virtual css::util::DateTime SAL_CALL getTimestamp( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getBinaryStream( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getCharacterStream( sal_Int32 columnIndex ) override;
+ virtual css::uno::Any SAL_CALL getObject( sal_Int32 columnIndex, const css::uno::Reference< css::container::XNameAccess >& typeMap ) override;
+ virtual css::uno::Reference< css::sdbc::XRef > SAL_CALL getRef( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XBlob > SAL_CALL getBlob( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XClob > SAL_CALL getClob( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XArray > SAL_CALL getArray( sal_Int32 columnIndex ) override;
+ // XOutParameters
+ virtual void SAL_CALL registerOutParameter( sal_Int32 parameterIndex, sal_Int32 sqlType, const OUString& typeName ) override;
+ virtual void SAL_CALL registerNumericOutParameter( sal_Int32 parameterIndex, sal_Int32 sqlType, sal_Int32 scale ) override;
+ };
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/ado/ACatalog.hxx b/connectivity/source/inc/ado/ACatalog.hxx
new file mode 100644
index 0000000000..fd09e9ad3c
--- /dev/null
+++ b/connectivity/source/inc/ado/ACatalog.hxx
@@ -0,0 +1,49 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <sdbcx/VCatalog.hxx>
+#include <ado/Awrapadox.hxx>
+
+namespace connectivity::ado
+{
+ class OConnection;
+
+ class OCatalog : public connectivity::sdbcx::OCatalog
+ {
+ WpADOCatalog m_aCatalog;
+ OConnection* m_pConnection;
+
+ public:
+ virtual void refreshTables() override;
+ virtual void refreshViews() override;
+ virtual void refreshGroups() override;
+ virtual void refreshUsers() override;
+
+ public:
+ OCatalog(_ADOCatalog* _pCatalog,OConnection* _pCon);
+ ~OCatalog() override;
+
+ OConnection* getConnection() const { return m_pConnection; }
+ sdbcx::OCollection* getPrivateTables() const { return m_pTables.get(); }
+ WpADOCatalog getCatalog() const { return m_aCatalog; }
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/ado/AColumn.hxx b/connectivity/source/inc/ado/AColumn.hxx
new file mode 100644
index 0000000000..f297964820
--- /dev/null
+++ b/connectivity/source/inc/ado/AColumn.hxx
@@ -0,0 +1,52 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <connectivity/sdbcx/VColumn.hxx>
+#include <ado/Awrapadox.hxx>
+
+namespace connectivity::ado
+{
+ class OConnection;
+ typedef sdbcx::OColumn OColumn_ADO;
+ class OAdoColumn : public OColumn_ADO
+ {
+ WpADOColumn m_aColumn;
+ OConnection* m_pConnection;
+ OUString m_ReferencedColumn;
+ bool m_IsAscending;
+
+ void fillPropertyValues();
+ protected:
+ virtual void SAL_CALL setFastPropertyValue_NoBroadcast(
+ sal_Int32 nHandle,
+ const css::uno::Any& rValue
+ ) override;
+ public:
+ OAdoColumn(bool _bCase,OConnection* _pConnection,_ADOColumn* _pColumn);
+ OAdoColumn(bool _bCase,OConnection* _pConnection);
+ // ODescriptor
+ virtual void construct() override;
+
+ WpADOColumn getColumnImpl() const;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/ado/AColumns.hxx b/connectivity/source/inc/ado/AColumns.hxx
new file mode 100644
index 0000000000..25decfa687
--- /dev/null
+++ b/connectivity/source/inc/ado/AColumns.hxx
@@ -0,0 +1,56 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <connectivity/sdbcx/VCollection.hxx>
+#include <com/sun/star/sdbc/XDatabaseMetaData.hpp>
+#include <connectivity/sdbcx/IRefreshable.hxx>
+#include <ado/Awrapadox.hxx>
+
+namespace connectivity::ado
+{
+ class OConnection;
+ class OColumns : public sdbcx::OCollection
+ {
+ protected:
+ WpADOColumns m_aCollection;
+ OConnection* m_pConnection;
+
+ virtual sdbcx::ObjectType createObject(const OUString& _rName) override;
+ virtual void impl_refresh() override;
+ virtual css::uno::Reference< css::beans::XPropertySet > createDescriptor() override;
+ virtual sdbcx::ObjectType appendObject( const OUString& _rForName, const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override;
+ virtual void dropObject(sal_Int32 _nPos,const OUString& _sElementName) override;
+ public:
+ OColumns( ::cppu::OWeakObject& _rParent,
+ ::osl::Mutex& _rMutex,
+ const ::std::vector< OUString> &_rVector,
+ const WpADOColumns& _rCollection,
+ bool _bCase,
+ OConnection* _pConnection) : sdbcx::OCollection(_rParent,_bCase,_rMutex,_rVector)
+ ,m_aCollection(_rCollection)
+ ,m_pConnection(_pConnection)
+ {
+ }
+
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/ado/AConnection.hxx b/connectivity/source/inc/ado/AConnection.hxx
new file mode 100644
index 0000000000..c2c8210036
--- /dev/null
+++ b/connectivity/source/inc/ado/AConnection.hxx
@@ -0,0 +1,134 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <com/sun/star/sdbc/SQLWarning.hpp>
+#include <com/sun/star/sdbcx/XTablesSupplier.hpp>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <map>
+#include <string_view>
+#include <connectivity/CommonTools.hxx>
+#include <OTypeInfo.hxx>
+#include <TConnection.hxx>
+#include <ado/Awrapado.hxx>
+
+namespace connectivity::ado
+{
+ struct OExtendedTypeInfo
+ {
+ ::connectivity::OTypeInfo aSimpleType; // the general type info
+ DataTypeEnum eType;
+
+ OUString getDBName() const { return aSimpleType.aTypeName; }
+ };
+
+ class WpADOConnection;
+ class ODriver;
+ class OCatalog;
+ typedef std::multimap<DataTypeEnum, OExtendedTypeInfo*> OTypeInfoMap;
+ typedef connectivity::OMetaConnection OConnection_BASE;
+
+
+ class OConnection : public OConnection_BASE
+ {
+ protected:
+
+ // Data attributes
+
+ OTypeInfoMap m_aTypeInfo; // vector containing an entry
+ // for each row returned by
+ // DatabaseMetaData.getTypeInfo.
+ css::uno::WeakReference< css::sdbcx::XTablesSupplier> m_xCatalog;
+ ODriver* m_pDriver;
+ private:
+ WpADOConnection m_aAdoConnection;
+ OCatalog* m_pCatalog;
+ sal_Int32 m_nEngineType;
+ bool m_bClosed;
+ bool m_bAutocommit;
+
+ protected:
+ /// @throws css::sdbc::SQLException
+ void buildTypeInfo();
+ public:
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ OConnection(ODriver* _pDriver);
+ // OConnection(const SQLHANDLE _pConnectionHandle);
+ ~OConnection() override;
+ void construct(std::u16string_view url,const css::uno::Sequence< css::beans::PropertyValue >& info);
+
+ //XUnoTunnel
+ virtual sal_Int64 SAL_CALL getSomething( const css::uno::Sequence< sal_Int8 >& aIdentifier ) override;
+ static css::uno::Sequence< sal_Int8 > getUnoTunnelId();
+ // XServiceInfo
+ DECLARE_SERVICE_INFO();
+ // OComponentHelper
+ virtual void SAL_CALL disposing() override;
+
+ // XConnection
+ virtual css::uno::Reference< css::sdbc::XStatement > SAL_CALL createStatement( ) override;
+ virtual css::uno::Reference< css::sdbc::XPreparedStatement > SAL_CALL prepareStatement( const OUString& sql ) override;
+ virtual css::uno::Reference< css::sdbc::XPreparedStatement > SAL_CALL prepareCall( const OUString& sql ) override;
+ virtual OUString SAL_CALL nativeSQL( const OUString& sql ) override;
+ virtual void SAL_CALL setAutoCommit( sal_Bool autoCommit ) override;
+ virtual sal_Bool SAL_CALL getAutoCommit( ) override;
+ virtual void SAL_CALL commit( ) override;
+ virtual void SAL_CALL rollback( ) override;
+ virtual sal_Bool SAL_CALL isClosed( ) override;
+ virtual css::uno::Reference< css::sdbc::XDatabaseMetaData > SAL_CALL getMetaData( ) override;
+ virtual void SAL_CALL setReadOnly( sal_Bool readOnly ) override;
+ virtual sal_Bool SAL_CALL isReadOnly( ) override;
+ virtual void SAL_CALL setCatalog( const OUString& catalog ) override;
+ virtual OUString SAL_CALL getCatalog( ) override;
+ virtual void SAL_CALL setTransactionIsolation( sal_Int32 level ) override;
+ virtual sal_Int32 SAL_CALL getTransactionIsolation( ) override;
+ virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getTypeMap( ) override;
+ virtual void SAL_CALL setTypeMap( const css::uno::Reference< css::container::XNameAccess >& typeMap ) override;
+ // XCloseable
+ virtual void SAL_CALL close( ) override;
+ // XWarningsSupplier
+ virtual css::uno::Any SAL_CALL getWarnings( ) override;
+ virtual void SAL_CALL clearWarnings( ) override;
+
+ WpADOConnection& getConnection() { return m_aAdoConnection; }
+ void setCatalog(const css::uno::WeakReference< css::sdbcx::XTablesSupplier>& _xCat) { m_xCatalog = _xCat; }
+ void setCatalog(OCatalog* _pCatalog) { m_pCatalog = _pCatalog; }
+
+ const OTypeInfoMap* getTypeInfo() const { return &m_aTypeInfo;}
+ OCatalog* getAdoCatalog() const
+ {
+ if ( m_xCatalog.get().is() )
+ return m_pCatalog;
+ return nullptr;
+ }
+
+ sal_Int32 getEngineType() const { return m_nEngineType; }
+ ODriver* getDriver() const { return m_pDriver; }
+
+ static const OExtendedTypeInfo* getTypeInfoFromType(const OTypeInfoMap& _rTypeInfo,
+ DataTypeEnum _nType,
+ const OUString& _sTypeName,
+ sal_Int32 _nPrecision,
+ sal_Int32 _nScale,
+ bool& _brForceToType);
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/ado/ADatabaseMetaData.hxx b/connectivity/source/inc/ado/ADatabaseMetaData.hxx
new file mode 100644
index 0000000000..1661ca4418
--- /dev/null
+++ b/connectivity/source/inc/ado/ADatabaseMetaData.hxx
@@ -0,0 +1,221 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <TDatabaseMetaDataBase.hxx>
+#include <map>
+
+namespace connectivity::ado
+{
+ class WpADOConnection;
+ class OConnection;
+
+ //************ Class: ODatabaseMetaData
+
+
+ class ODatabaseMetaData : public ODatabaseMetaDataBase
+ {
+ struct LiteralInfo
+ {
+ OUString pwszLiteralValue;
+ sal_uInt32 cchMaxLen;
+ bool fSupported;
+ };
+
+ std::map<sal_uInt32,LiteralInfo> m_aLiteralInfo;
+ WpADOConnection& m_rADOConnection;
+ OConnection* m_pConnection;
+
+ void fillLiterals();
+ // get information out of rowset
+ sal_Int32 getMaxSize(sal_uInt32 _nId);
+ bool isCapable(sal_uInt32 _nId);
+ OUString getLiteral(sal_uInt32 _nProperty);
+
+ // get info out of properties
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ OUString getStringProperty(const OUString& _aProperty);
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ sal_Int32 getInt32Property(const OUString& _aProperty);
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ bool getBoolProperty(const OUString& _aProperty);
+
+ virtual css::uno::Reference< css::sdbc::XResultSet > impl_getTypeInfo_throw() override;
+ // cached database information
+ virtual OUString impl_getIdentifierQuoteString_throw( ) override;
+ virtual bool impl_isCatalogAtStart_throw( ) override;
+ virtual OUString impl_getCatalogSeparator_throw( ) override;
+ virtual bool impl_supportsCatalogsInTableDefinitions_throw( ) override;
+ virtual bool impl_supportsSchemasInTableDefinitions_throw( ) override;
+ virtual bool impl_supportsCatalogsInDataManipulation_throw( ) override;
+ virtual bool impl_supportsSchemasInDataManipulation_throw( ) override;
+ virtual bool impl_supportsMixedCaseQuotedIdentifiers_throw( ) override;
+ virtual bool impl_supportsAlterTableWithAddColumn_throw( ) override;
+ virtual bool impl_supportsAlterTableWithDropColumn_throw( ) override;
+ virtual sal_Int32 impl_getMaxStatements_throw( ) override;
+ virtual sal_Int32 impl_getMaxTablesInSelect_throw( ) override;
+ virtual bool impl_storesMixedCaseQuotedIdentifiers_throw( ) override;
+ public:
+
+ ODatabaseMetaData(OConnection* _pCon);
+
+ // XDatabaseMetaData
+ virtual sal_Bool SAL_CALL allProceduresAreCallable( ) override;
+ virtual sal_Bool SAL_CALL allTablesAreSelectable( ) override;
+ virtual OUString SAL_CALL getURL( ) override;
+ virtual OUString SAL_CALL getUserName( ) override;
+ virtual sal_Bool SAL_CALL isReadOnly( ) override;
+ virtual sal_Bool SAL_CALL nullsAreSortedHigh( ) override;
+ virtual sal_Bool SAL_CALL nullsAreSortedLow( ) override;
+ virtual sal_Bool SAL_CALL nullsAreSortedAtStart( ) override;
+ virtual sal_Bool SAL_CALL nullsAreSortedAtEnd( ) override;
+ virtual OUString SAL_CALL getDatabaseProductName( ) override;
+ virtual OUString SAL_CALL getDatabaseProductVersion( ) override;
+ virtual OUString SAL_CALL getDriverName( ) override;
+ virtual OUString SAL_CALL getDriverVersion( ) override;
+ virtual sal_Int32 SAL_CALL getDriverMajorVersion( ) override;
+ virtual sal_Int32 SAL_CALL getDriverMinorVersion( ) override;
+ virtual sal_Bool SAL_CALL usesLocalFiles( ) override;
+ virtual sal_Bool SAL_CALL usesLocalFilePerTable( ) override;
+ virtual sal_Bool SAL_CALL supportsMixedCaseIdentifiers( ) override;
+ virtual sal_Bool SAL_CALL storesUpperCaseIdentifiers( ) override;
+ virtual sal_Bool SAL_CALL storesLowerCaseIdentifiers( ) override;
+ virtual sal_Bool SAL_CALL storesMixedCaseIdentifiers( ) override;
+
+ virtual sal_Bool SAL_CALL storesUpperCaseQuotedIdentifiers( ) override;
+ virtual sal_Bool SAL_CALL storesLowerCaseQuotedIdentifiers( ) override;
+
+ virtual OUString SAL_CALL getSQLKeywords( ) override;
+ virtual OUString SAL_CALL getNumericFunctions( ) override;
+ virtual OUString SAL_CALL getStringFunctions( ) override;
+ virtual OUString SAL_CALL getSystemFunctions( ) override;
+ virtual OUString SAL_CALL getTimeDateFunctions( ) override;
+ virtual OUString SAL_CALL getSearchStringEscape( ) override;
+ virtual OUString SAL_CALL getExtraNameCharacters( ) override;
+ virtual sal_Bool SAL_CALL supportsColumnAliasing( ) override;
+ virtual sal_Bool SAL_CALL nullPlusNonNullIsNull( ) override;
+ virtual sal_Bool SAL_CALL supportsTypeConversion( ) override;
+ virtual sal_Bool SAL_CALL supportsConvert( sal_Int32 fromType, sal_Int32 toType ) override;
+ virtual sal_Bool SAL_CALL supportsTableCorrelationNames( ) override;
+ virtual sal_Bool SAL_CALL supportsDifferentTableCorrelationNames( ) override;
+ virtual sal_Bool SAL_CALL supportsExpressionsInOrderBy( ) override;
+ virtual sal_Bool SAL_CALL supportsOrderByUnrelated( ) override;
+ virtual sal_Bool SAL_CALL supportsGroupBy( ) override;
+ virtual sal_Bool SAL_CALL supportsGroupByUnrelated( ) override;
+ virtual sal_Bool SAL_CALL supportsGroupByBeyondSelect( ) override;
+ virtual sal_Bool SAL_CALL supportsLikeEscapeClause( ) override;
+ virtual sal_Bool SAL_CALL supportsMultipleResultSets( ) override;
+ virtual sal_Bool SAL_CALL supportsMultipleTransactions( ) override;
+ virtual sal_Bool SAL_CALL supportsNonNullableColumns( ) override;
+ virtual sal_Bool SAL_CALL supportsMinimumSQLGrammar( ) override;
+ virtual sal_Bool SAL_CALL supportsCoreSQLGrammar( ) override;
+ virtual sal_Bool SAL_CALL supportsExtendedSQLGrammar( ) override;
+ virtual sal_Bool SAL_CALL supportsANSI92EntryLevelSQL( ) override;
+ virtual sal_Bool SAL_CALL supportsANSI92IntermediateSQL( ) override;
+ virtual sal_Bool SAL_CALL supportsANSI92FullSQL( ) override;
+ virtual sal_Bool SAL_CALL supportsIntegrityEnhancementFacility( ) override;
+ virtual sal_Bool SAL_CALL supportsOuterJoins( ) override;
+ virtual sal_Bool SAL_CALL supportsFullOuterJoins( ) override;
+ virtual sal_Bool SAL_CALL supportsLimitedOuterJoins( ) override;
+ virtual OUString SAL_CALL getSchemaTerm( ) override;
+ virtual OUString SAL_CALL getProcedureTerm( ) override;
+ virtual OUString SAL_CALL getCatalogTerm( ) override;
+ virtual sal_Bool SAL_CALL supportsSchemasInProcedureCalls( ) override;
+ virtual sal_Bool SAL_CALL supportsSchemasInIndexDefinitions( ) override;
+ virtual sal_Bool SAL_CALL supportsSchemasInPrivilegeDefinitions( ) override;
+ virtual sal_Bool SAL_CALL supportsCatalogsInProcedureCalls( ) override;
+ virtual sal_Bool SAL_CALL supportsCatalogsInIndexDefinitions( ) override;
+ virtual sal_Bool SAL_CALL supportsCatalogsInPrivilegeDefinitions( ) override;
+ virtual sal_Bool SAL_CALL supportsPositionedDelete( ) override;
+ virtual sal_Bool SAL_CALL supportsPositionedUpdate( ) override;
+ virtual sal_Bool SAL_CALL supportsSelectForUpdate( ) override;
+ virtual sal_Bool SAL_CALL supportsStoredProcedures( ) override;
+ virtual sal_Bool SAL_CALL supportsSubqueriesInComparisons( ) override;
+ virtual sal_Bool SAL_CALL supportsSubqueriesInExists( ) override;
+ virtual sal_Bool SAL_CALL supportsSubqueriesInIns( ) override;
+ virtual sal_Bool SAL_CALL supportsSubqueriesInQuantifieds( ) override;
+ virtual sal_Bool SAL_CALL supportsCorrelatedSubqueries( ) override;
+ virtual sal_Bool SAL_CALL supportsUnion( ) override;
+ virtual sal_Bool SAL_CALL supportsUnionAll( ) override;
+ virtual sal_Bool SAL_CALL supportsOpenCursorsAcrossCommit( ) override;
+ virtual sal_Bool SAL_CALL supportsOpenCursorsAcrossRollback( ) override;
+ virtual sal_Bool SAL_CALL supportsOpenStatementsAcrossCommit( ) override;
+ virtual sal_Bool SAL_CALL supportsOpenStatementsAcrossRollback( ) override;
+ virtual sal_Int32 SAL_CALL getMaxBinaryLiteralLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxCharLiteralLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxColumnNameLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxColumnsInGroupBy( ) override;
+ virtual sal_Int32 SAL_CALL getMaxColumnsInIndex( ) override;
+ virtual sal_Int32 SAL_CALL getMaxColumnsInOrderBy( ) override;
+ virtual sal_Int32 SAL_CALL getMaxColumnsInSelect( ) override;
+ virtual sal_Int32 SAL_CALL getMaxColumnsInTable( ) override;
+ virtual sal_Int32 SAL_CALL getMaxConnections( ) override;
+ virtual sal_Int32 SAL_CALL getMaxCursorNameLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxIndexLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxSchemaNameLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxProcedureNameLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxCatalogNameLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxRowSize( ) override;
+ virtual sal_Bool SAL_CALL doesMaxRowSizeIncludeBlobs( ) override;
+ virtual sal_Int32 SAL_CALL getMaxStatementLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxTableNameLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxUserNameLength( ) override;
+ virtual sal_Int32 SAL_CALL getDefaultTransactionIsolation( ) override;
+ virtual sal_Bool SAL_CALL supportsTransactions( ) override;
+ virtual sal_Bool SAL_CALL supportsTransactionIsolationLevel( sal_Int32 level ) override;
+ virtual sal_Bool SAL_CALL supportsDataDefinitionAndDataManipulationTransactions( ) override;
+ virtual sal_Bool SAL_CALL supportsDataManipulationTransactionsOnly( ) override;
+ virtual sal_Bool SAL_CALL dataDefinitionCausesTransactionCommit( ) override;
+ virtual sal_Bool SAL_CALL dataDefinitionIgnoredInTransactions( ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getProcedures( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& procedureNamePattern ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getProcedureColumns( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& procedureNamePattern, const OUString& columnNamePattern ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getTables( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& tableNamePattern, const css::uno::Sequence< OUString >& types ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getSchemas( ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getCatalogs( ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getTableTypes( ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getColumns( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& tableNamePattern, const OUString& columnNamePattern ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getColumnPrivileges( const css::uno::Any& catalog, const OUString& schema, const OUString& table, const OUString& columnNamePattern ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getTablePrivileges( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& tableNamePattern ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getPrimaryKeys( const css::uno::Any& catalog, const OUString& schema, const OUString& table ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getImportedKeys( const css::uno::Any& catalog, const OUString& schema, const OUString& table ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getExportedKeys( const css::uno::Any& catalog, const OUString& schema, const OUString& table ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getCrossReference( const css::uno::Any& primaryCatalog, const OUString& primarySchema, const OUString& primaryTable, const css::uno::Any& foreignCatalog, const OUString& foreignSchema, const OUString& foreignTable ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getIndexInfo( const css::uno::Any& catalog, const OUString& schema, const OUString& table, sal_Bool unique, sal_Bool approximate ) override;
+ virtual sal_Bool SAL_CALL supportsResultSetType( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL supportsResultSetConcurrency( sal_Int32 setType, sal_Int32 concurrency ) override;
+ virtual sal_Bool SAL_CALL ownUpdatesAreVisible( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL ownDeletesAreVisible( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL ownInsertsAreVisible( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL othersUpdatesAreVisible( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL othersDeletesAreVisible( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL othersInsertsAreVisible( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL updatesAreDetected( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL deletesAreDetected( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL insertsAreDetected( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL supportsBatchUpdates( ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getUDTs( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& typeNamePattern, const css::uno::Sequence< sal_Int32 >& types ) override;
+ };
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/ado/ADatabaseMetaDataResultSet.hxx b/connectivity/source/inc/ado/ADatabaseMetaDataResultSet.hxx
new file mode 100644
index 0000000000..dce6971658
--- /dev/null
+++ b/connectivity/source/inc/ado/ADatabaseMetaDataResultSet.hxx
@@ -0,0 +1,225 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/sdbc/XResultSet.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
+#include <com/sun/star/sdbc/XCloseable.hpp>
+#include <com/sun/star/sdbc/XColumnLocate.hpp>
+#include <com/sun/star/util/XCancellable.hpp>
+#include <com/sun/star/sdbc/XWarningsSupplier.hpp>
+#include <com/sun/star/sdbc/XResultSetUpdate.hpp>
+#include <com/sun/star/sdbc/XRowUpdate.hpp>
+#include <cppuhelper/compbase.hxx>
+#include <cppuhelper/basemutex.hxx>
+#include <comphelper/proparrhlp.hxx>
+#include <ado/AStatement.hxx>
+
+namespace connectivity::ado
+{
+ /*
+ ** java_sql_ResultSet
+ */
+ typedef ::cppu::WeakComponentImplHelper< css::sdbc::XResultSet,
+ css::sdbc::XRow,
+ css::sdbc::XResultSetMetaDataSupplier,
+ css::util::XCancellable,
+ css::sdbc::XWarningsSupplier,
+ css::sdbc::XCloseable,
+ css::sdbc::XColumnLocate> ODatabaseMetaDataResultSet_BASE;
+
+ class ODatabaseMetaDataResultSet : public cppu::BaseMutex,
+ public ODatabaseMetaDataResultSet_BASE,
+ public ::cppu::OPropertySetHelper,
+ public ::comphelper::OPropertyArrayUsageHelper<ODatabaseMetaDataResultSet>
+ {
+ std::vector<sal_Int32> m_aColMapping; // pos 0 is unused so we don't have to decrement 1 every time
+
+ std::map<sal_Int32, ::std::map<sal_Int32,sal_Int32> > m_aValueRange;
+ std::map<sal_Int32, ::std::map<sal_Int32,sal_Int32> >::iterator m_aValueRangeIter;
+
+ std::map<sal_Int32, std::map< OUString,sal_Int32> > m_aStrValueRange;
+ std::map<sal_Int32, std::map< OUString,sal_Int32> >::iterator m_aStrValueRangeIter;
+
+ std::map<sal_Int32, std::map< sal_Int32,OUString> > m_aIntValueRange;
+ std::map<sal_Int32, std::map< sal_Int32,OUString> >::iterator m_aIntValueRangeIter;
+
+ ADORecordset* m_pRecordSet;
+ css::uno::WeakReferenceHelper m_aStatement;
+ css::uno::Reference< css::sdbc::XResultSetMetaData> m_xMetaData;
+ OLEVariant m_aValue;
+ sal_Int32 m_nRowPos;
+ bool m_bWasNull;
+ bool m_bEOF;
+ bool m_bOnFirstAfterOpen;
+
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ static sal_Int32 getResultSetConcurrency();
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ static sal_Int32 getResultSetType();
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ static sal_Int32 getFetchDirection();
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ sal_Int32 getFetchSize() const;
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ static OUString getCursorName();
+
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void setFetchDirection(sal_Int32 _par0);
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void setFetchSize(sal_Int32 _par0);
+
+
+ inline sal_Int32 mapColumn (sal_Int32 column);
+ /// @throws css::sdbc::SQLException
+ void checkRecordSet();
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ OLEVariant getValue(sal_Int32 columnIndex );
+
+ protected:
+
+ // OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override;
+ // OPropertySetHelper
+ virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override;
+
+ virtual sal_Bool SAL_CALL convertFastPropertyValue(
+ css::uno::Any & rConvertedValue,
+ css::uno::Any & rOldValue,
+ sal_Int32 nHandle,
+ const css::uno::Any& rValue ) override;
+ virtual void SAL_CALL setFastPropertyValue_NoBroadcast(
+ sal_Int32 nHandle,
+ const css::uno::Any& rValue
+ ) override;
+ virtual void SAL_CALL getFastPropertyValue(
+ css::uno::Any& rValue,
+ sal_Int32 nHandle
+ ) const override;
+ public:
+ // a Constructor, that is needed for when Returning the Object is needed:
+ ODatabaseMetaDataResultSet( ADORecordset* _pRecordSet);
+ ~ODatabaseMetaDataResultSet() override;
+
+ // ::cppu::OComponentHelper
+ virtual void SAL_CALL disposing() override;
+ // XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+ //XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override;
+ // XPropertySet
+ virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override;
+ // XResultSet
+ virtual sal_Bool SAL_CALL next( ) override;
+ virtual sal_Bool SAL_CALL isBeforeFirst( ) override;
+ virtual sal_Bool SAL_CALL isAfterLast( ) override;
+ virtual sal_Bool SAL_CALL isFirst( ) override;
+ virtual sal_Bool SAL_CALL isLast( ) override;
+ virtual void SAL_CALL beforeFirst( ) override;
+ virtual void SAL_CALL afterLast( ) override;
+ virtual sal_Bool SAL_CALL first( ) override;
+ virtual sal_Bool SAL_CALL last( ) override;
+ virtual sal_Int32 SAL_CALL getRow( ) override;
+ virtual sal_Bool SAL_CALL absolute( sal_Int32 row ) override;
+ virtual sal_Bool SAL_CALL relative( sal_Int32 rows ) override;
+ virtual sal_Bool SAL_CALL previous( ) override;
+ virtual void SAL_CALL refreshRow( ) override;
+ virtual sal_Bool SAL_CALL rowUpdated( ) override;
+ virtual sal_Bool SAL_CALL rowInserted( ) override;
+ virtual sal_Bool SAL_CALL rowDeleted( ) override;
+ virtual css::uno::Reference< css::uno::XInterface > SAL_CALL getStatement( ) override;
+ // XRow
+ virtual sal_Bool SAL_CALL wasNull( ) override;
+ virtual OUString SAL_CALL getString( sal_Int32 columnIndex ) override;
+ virtual sal_Bool SAL_CALL getBoolean( sal_Int32 columnIndex ) override;
+ virtual sal_Int8 SAL_CALL getByte( sal_Int32 columnIndex ) override;
+ virtual sal_Int16 SAL_CALL getShort( sal_Int32 columnIndex ) override;
+ virtual sal_Int32 SAL_CALL getInt( sal_Int32 columnIndex ) override;
+ virtual sal_Int64 SAL_CALL getLong( sal_Int32 columnIndex ) override;
+ virtual float SAL_CALL getFloat( sal_Int32 columnIndex ) override;
+ virtual double SAL_CALL getDouble( sal_Int32 columnIndex ) override;
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getBytes( sal_Int32 columnIndex ) override;
+ virtual css::util::Date SAL_CALL getDate( sal_Int32 columnIndex ) override;
+ virtual css::util::Time SAL_CALL getTime( sal_Int32 columnIndex ) override;
+ virtual css::util::DateTime SAL_CALL getTimestamp( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getBinaryStream( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getCharacterStream( sal_Int32 columnIndex ) override;
+ virtual css::uno::Any SAL_CALL getObject( sal_Int32 columnIndex, const css::uno::Reference< css::container::XNameAccess >& typeMap ) override;
+ virtual css::uno::Reference< css::sdbc::XRef > SAL_CALL getRef( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XBlob > SAL_CALL getBlob( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XClob > SAL_CALL getClob( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XArray > SAL_CALL getArray( sal_Int32 columnIndex ) override;
+ // XResultSetMetaDataSupplier
+ virtual css::uno::Reference< css::sdbc::XResultSetMetaData > SAL_CALL getMetaData( ) override;
+ // XCancellable
+ virtual void SAL_CALL cancel( ) override;
+ // XCloseable
+ virtual void SAL_CALL close( ) override;
+ // XWarningsSupplier
+ virtual css::uno::Any SAL_CALL getWarnings( ) override;
+ virtual void SAL_CALL clearWarnings( ) override;
+ // XColumnLocate
+ virtual sal_Int32 SAL_CALL findColumn( const OUString& columnName ) override;
+
+ const std::vector<sal_Int32>& getColumnMapping() { return m_aColMapping; }
+
+ void setCatalogsMap();
+ void setSchemasMap();
+ void setColumnPrivilegesMap();
+ void setColumnsMap();
+ void setTablesMap();
+ void setProcedureColumnsMap();
+ void setProceduresMap();
+ void setExportedKeysMap();
+ void setImportedKeysMap();
+ void setPrimaryKeysMap();
+ void setIndexInfoMap();
+ void setTablePrivilegesMap();
+ void setCrossReferenceMap();
+ void setTypeInfoMap(bool _bJetEngine);
+ };
+
+ inline sal_Int32 ODatabaseMetaDataResultSet::mapColumn (sal_Int32 column)
+ {
+ sal_Int32 map = column;
+
+ if (!m_aColMapping.empty())
+ {
+ // Validate column number
+ map = m_aColMapping[column];
+ }
+
+ return map;
+ }
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/ado/ADatabaseMetaDataResultSetMetaData.hxx b/connectivity/source/inc/ado/ADatabaseMetaDataResultSetMetaData.hxx
new file mode 100644
index 0000000000..abac49ba1d
--- /dev/null
+++ b/connectivity/source/inc/ado/ADatabaseMetaDataResultSetMetaData.hxx
@@ -0,0 +1,102 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/sdbc/XResultSetMetaData.hpp>
+#include <cppuhelper/implbase.hxx>
+#include <vector>
+#include <ado/Awrapado.hxx>
+#include <ado/ADatabaseMetaDataResultSet.hxx>
+#include <OColumn.hxx>
+
+namespace connectivity::ado
+{
+
+ //************ Class: ResultSetMetaData
+
+ typedef ::cppu::WeakImplHelper< css::sdbc::XResultSetMetaData> ODatabaseMetaResultSetMetaData_BASE;
+
+ class ODatabaseMetaDataResultSetMetaData : public ODatabaseMetaResultSetMetaData_BASE
+ {
+ friend class ODatabaseMetaDataResultSet;
+
+ const std::vector<sal_Int32> &m_vMapping; // when not every column is needed
+ std::map<sal_Int32,connectivity::OColumn> m_mColumns;
+ std::map<sal_Int32,connectivity::OColumn>::const_iterator m_mColumnsIter;
+
+ ADORecordset* m_pRecordSet;
+ sal_Int32 m_nColCount;
+
+ private:
+ ODatabaseMetaDataResultSetMetaData( const ODatabaseMetaDataResultSetMetaData& ); // never implemented
+ ODatabaseMetaDataResultSetMetaData& operator=( const ODatabaseMetaDataResultSetMetaData& ); // never implemented
+
+ protected:
+ void setColumnPrivilegesMap();
+ void setColumnsMap();
+ void setTablesMap();
+ void setProcedureColumnsMap();
+ void setPrimaryKeysMap();
+ void setIndexInfoMap();
+ void setTablePrivilegesMap();
+ void setCrossReferenceMap();
+ void setTypeInfoMap();
+ void setProceduresMap();
+ public:
+ // a Constructor, that is needed for when Returning the Object is needed:
+ ODatabaseMetaDataResultSetMetaData( ADORecordset* _pRecordSet ,ODatabaseMetaDataResultSet* _pRes)
+ : m_vMapping(_pRes->getColumnMapping()),
+ m_pRecordSet(_pRecordSet),
+ m_nColCount(m_vMapping.size()-1)
+ {
+ if(m_pRecordSet)
+ m_pRecordSet->AddRef();
+ }
+ ~ODatabaseMetaDataResultSetMetaData() override;
+
+ /// Avoid ambiguous cast error from the compiler.
+ operator css::uno::Reference< css::sdbc::XResultSetMetaData > () noexcept
+ { return this; }
+
+ virtual sal_Int32 SAL_CALL getColumnCount( ) override;
+ virtual sal_Bool SAL_CALL isAutoIncrement( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isCaseSensitive( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isSearchable( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isCurrency( sal_Int32 column ) override;
+ virtual sal_Int32 SAL_CALL isNullable( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isSigned( sal_Int32 column ) override;
+ virtual sal_Int32 SAL_CALL getColumnDisplaySize( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getColumnLabel( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getColumnName( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getSchemaName( sal_Int32 column ) override;
+ virtual sal_Int32 SAL_CALL getPrecision( sal_Int32 column ) override;
+ virtual sal_Int32 SAL_CALL getScale( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getTableName( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getCatalogName( sal_Int32 column ) override;
+ virtual sal_Int32 SAL_CALL getColumnType( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getColumnTypeName( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isReadOnly( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isWritable( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isDefinitelyWritable( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getColumnServiceName( sal_Int32 column ) override;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/ado/ADriver.hxx b/connectivity/source/inc/ado/ADriver.hxx
new file mode 100644
index 0000000000..8542e03f6d
--- /dev/null
+++ b/connectivity/source/inc/ado/ADriver.hxx
@@ -0,0 +1,80 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/sdbc/XDriver.hpp>
+#include <com/sun/star/sdbcx/XDataDefinitionSupplier.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <cppuhelper/compbase.hxx>
+#include <connectivity/CommonTools.hxx>
+
+namespace com::sun::star::uno { class XComponentContext; }
+
+namespace connectivity::ado
+{
+ typedef ::cppu::WeakComponentImplHelper< css::sdbc::XDriver,
+ css::sdbcx::XDataDefinitionSupplier,
+ css::lang::XServiceInfo
+ > ODriver_BASE;
+ class ODriver : public ODriver_BASE
+ {
+ ::osl::Mutex m_aMutex;
+
+ connectivity::OWeakRefArray m_xConnections; // vector containing a list
+ // of all the Connection objects
+ // for this Driver
+ css::uno::Reference< css::uno::XComponentContext > m_xContext;
+
+ // to put back all the inits with COINIT_MULTITHREADED if needed
+ int mnNbCallCoInitializeExForReinit;
+
+ public:
+ ODriver(const css::uno::Reference< css::uno::XComponentContext >& xContext);
+ ~ODriver() override;
+
+ // OComponentHelper
+ virtual void SAL_CALL disposing() override;
+
+ css::uno::Reference< css::uno::XComponentContext > getContext() const { return m_xContext; }
+
+ private:
+ void impl_checkURL_throw(const OUString& _sUrl);
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+ // XDriver
+ virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL connect( const OUString& url, const css::uno::Sequence< css::beans::PropertyValue >& info ) override;
+ virtual sal_Bool SAL_CALL acceptsURL( const OUString& url ) override;
+ virtual css::uno::Sequence< css::sdbc::DriverPropertyInfo > SAL_CALL getPropertyInfo( const OUString& url, const css::uno::Sequence< css::beans::PropertyValue >& info ) override;
+ virtual sal_Int32 SAL_CALL getMajorVersion( ) override;
+ virtual sal_Int32 SAL_CALL getMinorVersion( ) override;
+
+ // XDataDefinitionSupplier
+ virtual css::uno::Reference< css::sdbcx::XTablesSupplier > SAL_CALL getDataDefinitionByConnection( const css::uno::Reference< css::sdbc::XConnection >& connection ) override;
+ virtual css::uno::Reference< css::sdbcx::XTablesSupplier > SAL_CALL getDataDefinitionByURL( const OUString& url, const css::uno::Sequence< css::beans::PropertyValue >& info ) override;
+ };
+
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/ado/AGroup.hxx b/connectivity/source/inc/ado/AGroup.hxx
new file mode 100644
index 0000000000..00207a5fa2
--- /dev/null
+++ b/connectivity/source/inc/ado/AGroup.hxx
@@ -0,0 +1,58 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sdbcx/VGroup.hxx>
+#include <ado/Awrapadox.hxx>
+
+namespace connectivity::ado
+{
+ typedef sdbcx::OGroup OGroup_ADO;
+ class OCatalog;
+
+ class OAdoGroup : public OGroup_ADO
+ {
+ WpADOGroup m_aGroup;
+ OCatalog* m_pCatalog;
+
+ static sal_Int32 MapRight(RightsEnum _eNum);
+ static RightsEnum Map2Right(sal_Int32 _eNum);
+ static ObjectTypeEnum MapObjectType(sal_Int32 ObjType);
+ protected:
+ virtual void SAL_CALL getFastPropertyValue(css::uno::Any& rValue,sal_Int32 nHandle) const override;
+ virtual void SAL_CALL setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,const css::uno::Any& rValue) override;
+
+ public:
+ virtual void refreshUsers() override;
+ public:
+ OAdoGroup(OCatalog* _pParent,bool _bCase, ADOGroup* _pGroup=nullptr);
+ OAdoGroup(OCatalog* _pParent,bool _bCase, const OUString& Name);
+
+ // XAuthorizable
+ virtual sal_Int32 SAL_CALL getPrivileges( const OUString& objName, sal_Int32 objType ) override;
+ virtual sal_Int32 SAL_CALL getGrantablePrivileges( const OUString& objName, sal_Int32 objType ) override;
+ virtual void SAL_CALL grantPrivileges( const OUString& objName, sal_Int32 objType, sal_Int32 objPrivileges ) override;
+ virtual void SAL_CALL revokePrivileges( const OUString& objName, sal_Int32 objType, sal_Int32 objPrivileges ) override;
+
+ WpADOGroup getImpl() const { return m_aGroup; }
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/ado/AGroups.hxx b/connectivity/source/inc/ado/AGroups.hxx
new file mode 100644
index 0000000000..85817cec84
--- /dev/null
+++ b/connectivity/source/inc/ado/AGroups.hxx
@@ -0,0 +1,51 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <connectivity/sdbcx/VCollection.hxx>
+#include <ado/Awrapadox.hxx>
+#include <ado/ACatalog.hxx>
+
+namespace connectivity::ado
+{
+ class OGroups : public sdbcx::OCollection
+ {
+ WpADOGroups m_aCollection;
+ OCatalog* m_pCatalog;
+ protected:
+
+ virtual sdbcx::ObjectType createObject(const OUString& _rName) override;
+ virtual void impl_refresh() override;
+ virtual css::uno::Reference< css::beans::XPropertySet > createDescriptor() override;
+ virtual sdbcx::ObjectType appendObject( const OUString& _rForName, const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override;
+ virtual void dropObject(sal_Int32 _nPos,const OUString& _sElementName) override;
+ public:
+ OGroups(OCatalog* _pParent,
+ ::osl::Mutex& _rMutex,
+ const ::std::vector< OUString> &_rVector,
+ const WpADOGroups& _rCollection,bool _bCase) : sdbcx::OCollection(*_pParent,_bCase,_rMutex,_rVector)
+ ,m_aCollection(_rCollection)
+ ,m_pCatalog(_pParent)
+ {
+ }
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/ado/AIndex.hxx b/connectivity/source/inc/ado/AIndex.hxx
new file mode 100644
index 0000000000..98c3a77d1c
--- /dev/null
+++ b/connectivity/source/inc/ado/AIndex.hxx
@@ -0,0 +1,46 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sdbcx/VIndex.hxx>
+#include <com/sun/star/sdbc/XDatabaseMetaData.hpp>
+#include <ado/Awrapadox.hxx>
+
+namespace connectivity::ado
+{
+ class OConnection;
+ class OAdoIndex : public sdbcx::OIndex
+ {
+ WpADOIndex m_aIndex;
+ OConnection* m_pConnection;
+ protected:
+ void fillPropertyValues();
+ virtual void SAL_CALL setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,const css::uno::Any& rValue) override;
+ public:
+ virtual void refreshColumns() override;
+ public:
+ OAdoIndex(bool _bCase, OConnection* _pConnection,ADOIndex* _pIndex);
+ OAdoIndex(bool _bCase, OConnection* _pConnection);
+
+ WpADOIndex getImpl() const { return m_aIndex;}
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/ado/AIndexes.hxx b/connectivity/source/inc/ado/AIndexes.hxx
new file mode 100644
index 0000000000..48c2d1abee
--- /dev/null
+++ b/connectivity/source/inc/ado/AIndexes.hxx
@@ -0,0 +1,53 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <connectivity/sdbcx/VCollection.hxx>
+#include <com/sun/star/sdbc/XDatabaseMetaData.hpp>
+#include <ado/Awrapadox.hxx>
+
+namespace connectivity::ado
+{
+ class OConnection;
+ class OIndexes : public sdbcx::OCollection
+ {
+ WpADOIndexes m_aCollection;
+ OConnection* m_pConnection;
+ protected:
+ virtual sdbcx::ObjectType createObject(const OUString& _rName) override;
+ virtual void impl_refresh() override;
+ virtual css::uno::Reference< css::beans::XPropertySet > createDescriptor() override;
+ virtual sdbcx::ObjectType appendObject( const OUString& _rForName, const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override;
+ virtual void dropObject(sal_Int32 _nPos,const OUString& _sElementName) override;
+ public:
+ OIndexes(::cppu::OWeakObject& _rParent,
+ ::osl::Mutex& _rMutex,
+ const ::std::vector< OUString> &_rVector,
+ const WpADOIndexes& _rCollection,
+ bool _bCase,
+ OConnection* _pConnection)
+ : sdbcx::OCollection(_rParent,_bCase,_rMutex,_rVector)
+ , m_aCollection(_rCollection)
+ , m_pConnection(_pConnection)
+ {
+ }
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/ado/AKey.hxx b/connectivity/source/inc/ado/AKey.hxx
new file mode 100644
index 0000000000..5ec3fa972b
--- /dev/null
+++ b/connectivity/source/inc/ado/AKey.hxx
@@ -0,0 +1,55 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sdbcx/VKey.hxx>
+#include <com/sun/star/sdbc/XDatabaseMetaData.hpp>
+#include <ado/Awrapadox.hxx>
+
+namespace connectivity::ado
+{
+ typedef sdbcx::OKey OKey_ADO;
+
+ class OConnection;
+ class OAdoKey : public OKey_ADO
+ {
+ WpADOKey m_aKey;
+ OConnection* m_pConnection;
+ protected:
+ void fillPropertyValues();
+ virtual void SAL_CALL setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,const css::uno::Any& rValue) override;
+ public:
+ virtual void refreshColumns() override;
+ public:
+ OAdoKey(bool _bCase,OConnection* _pConnection,ADOKey* _pKey);
+ OAdoKey(bool _bCase,OConnection* _pConnection);
+
+ WpADOKey getImpl() const { return m_aKey;}
+ // map the update/delete rules
+ static RuleEnum Map2Rule(sal_Int32 _eNum);
+ static sal_Int32 MapRule(const RuleEnum& _eNum);
+
+ // map the keytypes
+ static sal_Int32 MapKeyRule(const KeyTypeEnum& _eNum);
+ static KeyTypeEnum Map2KeyRule(sal_Int32 _eNum);
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/ado/AKeys.hxx b/connectivity/source/inc/ado/AKeys.hxx
new file mode 100644
index 0000000000..45e127e29b
--- /dev/null
+++ b/connectivity/source/inc/ado/AKeys.hxx
@@ -0,0 +1,53 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <connectivity/sdbcx/VCollection.hxx>
+#include <ado/Awrapadox.hxx>
+
+namespace connectivity::ado
+{
+ class OConnection;
+ class OKeys : public sdbcx::OCollection
+ {
+ WpADOKeys m_aCollection;
+ OConnection* m_pConnection;
+
+ protected:
+ virtual sdbcx::ObjectType createObject(const OUString& _rName) override;
+ virtual void impl_refresh() override;
+ virtual css::uno::Reference< css::beans::XPropertySet > createDescriptor() override;
+ virtual sdbcx::ObjectType appendObject( const OUString& _rForName, const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override;
+ virtual void dropObject(sal_Int32 _nPos,const OUString& _sElementName) override;
+ public:
+ OKeys(::cppu::OWeakObject& _rParent,
+ ::osl::Mutex& _rMutex,
+ const ::std::vector< OUString> &_rVector,
+ const WpADOKeys& _rCollection,
+ bool _bCase,
+ OConnection* _pConnection) : sdbcx::OCollection(_rParent,_bCase,_rMutex,_rVector)
+ ,m_aCollection(_rCollection)
+ ,m_pConnection(_pConnection)
+ {
+ }
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/ado/APreparedStatement.hxx b/connectivity/source/inc/ado/APreparedStatement.hxx
new file mode 100644
index 0000000000..2ce394dbde
--- /dev/null
+++ b/connectivity/source/inc/ado/APreparedStatement.hxx
@@ -0,0 +1,113 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <ado/AStatement.hxx>
+#include <com/sun/star/sdbc/XPreparedStatement.hpp>
+#include <com/sun/star/sdbc/XParameters.hpp>
+#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
+#include <com/sun/star/io/XInputStream.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+
+// TODO: implement css::sdbc::XPreparedBatchExecution
+// (empty implementations removed on 2014-06-16)
+
+namespace connectivity
+{
+ class OSQLParseNode;
+ namespace ado
+ {
+
+ class OPreparedStatement : public OStatement_Base,
+ public css::sdbc::XPreparedStatement,
+ public css::sdbc::XParameters,
+ public css::sdbc::XResultSetMetaDataSupplier,
+ public css::lang::XServiceInfo
+
+ {
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void setParameter(sal_Int32 parameterIndex, const DataTypeEnum& _eType, sal_Int32 _nSize,const OLEVariant& Val);
+ void replaceParameterNodeName( OSQLParseNode const * _pNode,
+ const OUString& _sDefaultName,
+ sal_Int32& _nParameterCount);
+ protected:
+
+ // Data attributes
+
+ css::uno::Reference< css::sdbc::XResultSetMetaData > m_xMetaData;
+ ADOParameters* m_pParameters;
+
+ virtual ~OPreparedStatement() override;
+
+ public:
+ DECLARE_SERVICE_INFO();
+ // a Constructor, that is needed for when Returning the Object is needed:
+ OPreparedStatement( OConnection* _pConnection, const OUString& sql);
+
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ //XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override;
+
+ // XPreparedStatement
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL executeQuery( ) override;
+ using OStatement_Base::executeQuery;
+ virtual sal_Int32 SAL_CALL executeUpdate( ) override;
+ using OStatement_Base::executeUpdate;
+ virtual sal_Bool SAL_CALL execute( ) override;
+ using OStatement_Base::execute;
+ virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL getConnection( ) override;
+ // XParameters
+ virtual void SAL_CALL setNull( sal_Int32 parameterIndex, sal_Int32 sqlType ) override;
+ virtual void SAL_CALL setObjectNull( sal_Int32 parameterIndex, sal_Int32 sqlType, const OUString& typeName ) override;
+ virtual void SAL_CALL setBoolean( sal_Int32 parameterIndex, sal_Bool x ) override;
+ virtual void SAL_CALL setByte( sal_Int32 parameterIndex, sal_Int8 x ) override;
+ virtual void SAL_CALL setShort( sal_Int32 parameterIndex, sal_Int16 x ) override;
+ virtual void SAL_CALL setInt( sal_Int32 parameterIndex, sal_Int32 x ) override;
+ virtual void SAL_CALL setLong( sal_Int32 parameterIndex, sal_Int64 x ) override;
+ virtual void SAL_CALL setFloat( sal_Int32 parameterIndex, float x ) override;
+ virtual void SAL_CALL setDouble( sal_Int32 parameterIndex, double x ) override;
+ virtual void SAL_CALL setString( sal_Int32 parameterIndex, const OUString& x ) override;
+ virtual void SAL_CALL setBytes( sal_Int32 parameterIndex, const css::uno::Sequence< sal_Int8 >& x ) override;
+ virtual void SAL_CALL setDate( sal_Int32 parameterIndex, const css::util::Date& x ) override;
+ virtual void SAL_CALL setTime( sal_Int32 parameterIndex, const css::util::Time& x ) override;
+ virtual void SAL_CALL setTimestamp( sal_Int32 parameterIndex, const css::util::DateTime& x ) override;
+ virtual void SAL_CALL setBinaryStream( sal_Int32 parameterIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override;
+ virtual void SAL_CALL setCharacterStream( sal_Int32 parameterIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override;
+ virtual void SAL_CALL setObject( sal_Int32 parameterIndex, const css::uno::Any& x ) override;
+ virtual void SAL_CALL setObjectWithInfo( sal_Int32 parameterIndex, const css::uno::Any& x, sal_Int32 targetSqlType, sal_Int32 scale ) override;
+ virtual void SAL_CALL setRef( sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XRef >& x ) override;
+ virtual void SAL_CALL setBlob( sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XBlob >& x ) override;
+ virtual void SAL_CALL setClob( sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XClob >& x ) override;
+ virtual void SAL_CALL setArray( sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XArray >& x ) override;
+ virtual void SAL_CALL clearParameters( ) override;
+ // XCloseable
+ virtual void SAL_CALL close( ) override;
+ // XResultSetMetaDataSupplier
+ virtual css::uno::Reference< css::sdbc::XResultSetMetaData > SAL_CALL getMetaData( ) override;
+ // OComponentHelper
+ virtual void SAL_CALL disposing() override;
+ };
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/ado/AResultSet.hxx b/connectivity/source/inc/ado/AResultSet.hxx
new file mode 100644
index 0000000000..58de2baeb5
--- /dev/null
+++ b/connectivity/source/inc/ado/AResultSet.hxx
@@ -0,0 +1,234 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/sdbc/XResultSet.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
+#include <com/sun/star/sdbc/XCloseable.hpp>
+#include <com/sun/star/sdbc/XColumnLocate.hpp>
+#include <com/sun/star/util/XCancellable.hpp>
+#include <com/sun/star/sdbc/XWarningsSupplier.hpp>
+#include <com/sun/star/sdbc/XResultSetUpdate.hpp>
+#include <com/sun/star/sdbcx/XRowLocate.hpp>
+#include <com/sun/star/sdbcx/XDeleteRows.hpp>
+#include <com/sun/star/sdbc/XRowUpdate.hpp>
+#include <cppuhelper/compbase.hxx>
+#include <comphelper/proparrhlp.hxx>
+#include <ado/AStatement.hxx>
+#include <cppuhelper/basemutex.hxx>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+
+namespace connectivity::ado
+{
+ /*
+ ** java_sql_ResultSet
+ */
+ typedef ::cppu::WeakComponentImplHelper< css::sdbc::XResultSet,
+ css::sdbc::XRow,
+ css::sdbc::XResultSetMetaDataSupplier,
+ css::util::XCancellable,
+ css::sdbc::XWarningsSupplier,
+ css::sdbc::XResultSetUpdate,
+ css::sdbc::XRowUpdate,
+ css::sdbc::XCloseable,
+ css::sdbc::XColumnLocate,
+ css::sdbcx::XRowLocate,
+ css::sdbcx::XDeleteRows,
+ css::lang::XServiceInfo> OResultSet_BASE;
+
+ class OResultSet : public cppu::BaseMutex,
+ public OResultSet_BASE,
+ public ::cppu::OPropertySetHelper,
+ public ::comphelper::OPropertyArrayUsageHelper<OResultSet>
+ {
+
+ ADORecordset* m_pRecordSet;
+ OStatement_Base* m_pStmt;
+ css::uno::Reference< css::uno::XInterface> m_xStatement;
+ css::uno::Reference< css::sdbc::XResultSetMetaData> m_xMetaData;
+ std::vector<OLEVariant> m_aBookmarks;
+ OLEVariant m_aValue;
+ ADO_LONGPTR m_nRowPos;
+ bool m_bEOF;
+ bool m_bOnFirstAfterOpen;
+
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ sal_Int32 getResultSetConcurrency() const;
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ sal_Int32 getResultSetType() const;
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ static sal_Int32 getFetchDirection();
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ sal_Int32 getFetchSize() const;
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ static OUString getCursorName();
+
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void setFetchDirection(sal_Int32 _par0);
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void setFetchSize(sal_Int32 _par0);
+ void updateValue(sal_Int32 columnIndex,const OLEVariant& x);
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ OLEVariant getValue(sal_Int32 columnIndex );
+
+ protected:
+
+ // OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override;
+ // OPropertySetHelper
+ virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override;
+ virtual sal_Bool SAL_CALL convertFastPropertyValue(
+ css::uno::Any & rConvertedValue,
+ css::uno::Any & rOldValue,
+ sal_Int32 nHandle,
+ const css::uno::Any& rValue ) override;
+ virtual void SAL_CALL setFastPropertyValue_NoBroadcast(
+ sal_Int32 nHandle,
+ const css::uno::Any& rValue
+ ) override;
+ virtual void SAL_CALL getFastPropertyValue(
+ css::uno::Any& rValue,
+ sal_Int32 nHandle
+ ) const override;
+ virtual ~OResultSet() override;
+ public:
+ // a Constructor, that is needed for when Returning the Object is needed:
+ OResultSet( ADORecordset* _pRecordSet,OStatement_Base* pStmt);
+ OResultSet( ADORecordset* _pRecordSet);
+
+ // late constructor
+ void construct();
+ void setMetaData(const css::uno::Reference< css::sdbc::XResultSetMetaData>& _xMetaData) { m_xMetaData = _xMetaData;}
+
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+ // ::cppu::OComponentHelper
+ virtual void SAL_CALL disposing() override;
+ // XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+ //XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override;
+ // XPropertySet
+ virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override;
+ // XResultSet
+ virtual sal_Bool SAL_CALL next( ) override;
+ virtual sal_Bool SAL_CALL isBeforeFirst( ) override;
+ virtual sal_Bool SAL_CALL isAfterLast( ) override;
+ virtual sal_Bool SAL_CALL isFirst( ) override;
+ virtual sal_Bool SAL_CALL isLast( ) override;
+ virtual void SAL_CALL beforeFirst( ) override;
+ virtual void SAL_CALL afterLast( ) override;
+ virtual sal_Bool SAL_CALL first( ) override;
+ virtual sal_Bool SAL_CALL last( ) override;
+ virtual sal_Int32 SAL_CALL getRow( ) override;
+ virtual sal_Bool SAL_CALL absolute( sal_Int32 row ) override;
+ virtual sal_Bool SAL_CALL relative( sal_Int32 rows ) override;
+ virtual sal_Bool SAL_CALL previous( ) override;
+ virtual void SAL_CALL refreshRow( ) override;
+ virtual sal_Bool SAL_CALL rowUpdated( ) override;
+ virtual sal_Bool SAL_CALL rowInserted( ) override;
+ virtual sal_Bool SAL_CALL rowDeleted( ) override;
+ virtual css::uno::Reference< css::uno::XInterface > SAL_CALL getStatement( ) override;
+ // XRow
+ virtual sal_Bool SAL_CALL wasNull( ) override;
+ virtual OUString SAL_CALL getString( sal_Int32 columnIndex ) override;
+ virtual sal_Bool SAL_CALL getBoolean( sal_Int32 columnIndex ) override;
+ virtual sal_Int8 SAL_CALL getByte( sal_Int32 columnIndex ) override;
+ virtual sal_Int16 SAL_CALL getShort( sal_Int32 columnIndex ) override;
+ virtual sal_Int32 SAL_CALL getInt( sal_Int32 columnIndex ) override;
+ virtual sal_Int64 SAL_CALL getLong( sal_Int32 columnIndex ) override;
+ virtual float SAL_CALL getFloat( sal_Int32 columnIndex ) override;
+ virtual double SAL_CALL getDouble( sal_Int32 columnIndex ) override;
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getBytes( sal_Int32 columnIndex ) override;
+ virtual css::util::Date SAL_CALL getDate( sal_Int32 columnIndex ) override;
+ virtual css::util::Time SAL_CALL getTime( sal_Int32 columnIndex ) override;
+ virtual css::util::DateTime SAL_CALL getTimestamp( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getBinaryStream( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getCharacterStream( sal_Int32 columnIndex ) override;
+ virtual css::uno::Any SAL_CALL getObject( sal_Int32 columnIndex, const css::uno::Reference< css::container::XNameAccess >& typeMap ) override;
+ virtual css::uno::Reference< css::sdbc::XRef > SAL_CALL getRef( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XBlob > SAL_CALL getBlob( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XClob > SAL_CALL getClob( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XArray > SAL_CALL getArray( sal_Int32 columnIndex ) override;
+ // XResultSetMetaDataSupplier
+ virtual css::uno::Reference< css::sdbc::XResultSetMetaData > SAL_CALL getMetaData( ) override;
+ // XCancellable
+ virtual void SAL_CALL cancel( ) override;
+ // XCloseable
+ virtual void SAL_CALL close( ) override;
+ // XWarningsSupplier
+ virtual css::uno::Any SAL_CALL getWarnings( ) override;
+ virtual void SAL_CALL clearWarnings( ) override;
+ // XResultSetUpdate
+ virtual void SAL_CALL insertRow( ) override;
+ virtual void SAL_CALL updateRow( ) override;
+ virtual void SAL_CALL deleteRow( ) override;
+ virtual void SAL_CALL cancelRowUpdates( ) override;
+ virtual void SAL_CALL moveToInsertRow( ) override;
+ virtual void SAL_CALL moveToCurrentRow( ) override;
+ // XRowUpdate
+ virtual void SAL_CALL updateNull( sal_Int32 columnIndex ) override;
+ virtual void SAL_CALL updateBoolean( sal_Int32 columnIndex, sal_Bool x ) override;
+ virtual void SAL_CALL updateByte( sal_Int32 columnIndex, sal_Int8 x ) override;
+ virtual void SAL_CALL updateShort( sal_Int32 columnIndex, sal_Int16 x ) override;
+ virtual void SAL_CALL updateInt( sal_Int32 columnIndex, sal_Int32 x ) override;
+ virtual void SAL_CALL updateLong( sal_Int32 columnIndex, sal_Int64 x ) override;
+ virtual void SAL_CALL updateFloat( sal_Int32 columnIndex, float x ) override;
+ virtual void SAL_CALL updateDouble( sal_Int32 columnIndex, double x ) override;
+ virtual void SAL_CALL updateString( sal_Int32 columnIndex, const OUString& x ) override;
+ virtual void SAL_CALL updateBytes( sal_Int32 columnIndex, const css::uno::Sequence< sal_Int8 >& x ) override;
+ virtual void SAL_CALL updateDate( sal_Int32 columnIndex, const css::util::Date& x ) override;
+ virtual void SAL_CALL updateTime( sal_Int32 columnIndex, const css::util::Time& x ) override;
+ virtual void SAL_CALL updateTimestamp( sal_Int32 columnIndex, const css::util::DateTime& x ) override;
+ virtual void SAL_CALL updateBinaryStream( sal_Int32 columnIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override;
+ virtual void SAL_CALL updateCharacterStream( sal_Int32 columnIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override;
+ virtual void SAL_CALL updateObject( sal_Int32 columnIndex, const css::uno::Any& x ) override;
+ virtual void SAL_CALL updateNumericObject( sal_Int32 columnIndex, const css::uno::Any& x, sal_Int32 scale ) override;
+ // XColumnLocate
+ virtual sal_Int32 SAL_CALL findColumn( const OUString& columnName ) override;
+ // XRowLocate
+ virtual css::uno::Any SAL_CALL getBookmark( ) override;
+ virtual sal_Bool SAL_CALL moveToBookmark( const css::uno::Any& bookmark ) override;
+ virtual sal_Bool SAL_CALL moveRelativeToBookmark( const css::uno::Any& bookmark, sal_Int32 rows ) override;
+ virtual sal_Int32 SAL_CALL compareBookmarks( const css::uno::Any& first, const css::uno::Any& second ) override;
+ virtual sal_Bool SAL_CALL hasOrderedBookmarks( ) override;
+ virtual sal_Int32 SAL_CALL hashBookmark( const css::uno::Any& bookmark ) override;
+ // XDeleteRows
+ virtual css::uno::Sequence< sal_Int32 > SAL_CALL deleteRows( const css::uno::Sequence< css::uno::Any >& rows ) override;
+
+ };
+
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/ado/AResultSetMetaData.hxx b/connectivity/source/inc/ado/AResultSetMetaData.hxx
new file mode 100644
index 0000000000..1eeb226562
--- /dev/null
+++ b/connectivity/source/inc/ado/AResultSetMetaData.hxx
@@ -0,0 +1,79 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/sdbc/XResultSetMetaData.hpp>
+#include <cppuhelper/implbase.hxx>
+#include <vector>
+#include <ado/Awrapado.hxx>
+#include <ado/AResultSet.hxx>
+#include <OColumn.hxx>
+
+namespace connectivity::ado
+{
+
+
+ //************ Class: ResultSetMetaData
+
+ typedef ::cppu::WeakImplHelper<css::sdbc::XResultSetMetaData> OResultSetMetaData_BASE;
+
+ class OResultSetMetaData : public OResultSetMetaData_BASE
+ {
+ friend class OResultSet;
+
+ ADORecordset* m_pRecordSet;
+ sal_Int32 m_nColCount;
+
+ sal_Int32 MapADOType2Jdbc(DataTypeEnum eType);
+ private:
+ OResultSetMetaData( const OResultSetMetaData& ); // never implemented
+ OResultSetMetaData& operator=( const OResultSetMetaData& ); // never implemented
+
+ protected:
+ virtual ~OResultSetMetaData() override;
+ public:
+ // a Constructor, that is needed for when Returning the Object is needed:
+ OResultSetMetaData( ADORecordset* _pRecordSet);
+
+ virtual sal_Int32 SAL_CALL getColumnCount( ) override;
+ virtual sal_Bool SAL_CALL isAutoIncrement( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isCaseSensitive( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isSearchable( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isCurrency( sal_Int32 column ) override;
+ virtual sal_Int32 SAL_CALL isNullable( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isSigned( sal_Int32 column ) override;
+ virtual sal_Int32 SAL_CALL getColumnDisplaySize( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getColumnLabel( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getColumnName( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getSchemaName( sal_Int32 column ) override;
+ virtual sal_Int32 SAL_CALL getPrecision( sal_Int32 column ) override;
+ virtual sal_Int32 SAL_CALL getScale( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getTableName( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getCatalogName( sal_Int32 column ) override;
+ virtual sal_Int32 SAL_CALL getColumnType( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getColumnTypeName( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isReadOnly( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isWritable( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isDefinitelyWritable( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getColumnServiceName( sal_Int32 column ) override;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/ado/AStatement.hxx b/connectivity/source/inc/ado/AStatement.hxx
new file mode 100644
index 0000000000..6253399175
--- /dev/null
+++ b/connectivity/source/inc/ado/AStatement.hxx
@@ -0,0 +1,217 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/sdbc/XStatement.hpp>
+#include <com/sun/star/sdbc/XWarningsSupplier.hpp>
+#include <com/sun/star/sdbc/XMultipleResults.hpp>
+#include <com/sun/star/sdbc/XBatchExecution.hpp>
+#include <com/sun/star/sdbc/XCloseable.hpp>
+#include <com/sun/star/sdbc/SQLWarning.hpp>
+#include <com/sun/star/util/XCancellable.hpp>
+#include <cppuhelper/compbase.hxx>
+#include <cppuhelper/basemutex.hxx>
+#include <comphelper/proparrhlp.hxx>
+#include <ado/AConnection.hxx>
+#include <string_view>
+#include <vector>
+#include <ado/Awrapado.hxx>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+
+namespace connectivity::ado
+{
+ typedef ::cppu::WeakComponentImplHelper< css::sdbc::XStatement,
+ css::sdbc::XWarningsSupplier,
+ css::util::XCancellable,
+ css::sdbc::XCloseable,
+ css::sdbc::XMultipleResults> OStatement_BASE;
+
+
+ //************ Class: java.sql.Statement
+
+ class OStatement_Base : public cppu::BaseMutex,
+ public OStatement_BASE,
+ public ::cppu::OPropertySetHelper,
+ public ::comphelper::OPropertyArrayUsageHelper<OStatement_Base>
+
+ {
+ friend class OResultSet;
+
+ css::sdbc::SQLWarning m_aLastWarning;
+
+ protected:
+ std::vector< OUString> m_aBatchVector;
+
+ css::uno::WeakReference< css::sdbc::XResultSet> m_xResultSet; // The last ResultSet created
+ // for this Statement
+
+ OConnection* m_pConnection;// The owning Connection object
+ WpADOCommand m_Command;
+ WpADORecordset m_RecordSet;
+ OLEVariant m_RecordsAffected;
+ OLEVariant m_Parameters;
+ std::vector<connectivity::OTypeInfo> m_aTypeInfo; // Hashtable containing an entry
+ // for each row returned by
+ // DatabaseMetaData.getTypeInfo.
+ ADO_LONGPTR m_nMaxRows;
+ sal_Int32 m_nFetchSize;
+ LockTypeEnum m_eLockType;
+ CursorTypeEnum m_eCursorType;
+
+ using OStatement_BASE::rBHelper;
+ private:
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ sal_Int32 getQueryTimeOut() const;
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ static sal_Int32 getMaxFieldSize();
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ sal_Int32 getMaxRows() const;
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ sal_Int32 getResultSetConcurrency() const;
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ sal_Int32 getResultSetType() const;
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ static sal_Int32 getFetchDirection();
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ sal_Int32 getFetchSize() const;
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ OUString getCursorName() const;
+
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void setQueryTimeOut(sal_Int32 _par0);
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void setMaxFieldSize(sal_Int32 _par0);
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void setMaxRows(sal_Int32 _par0);
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void setResultSetConcurrency(sal_Int32 _par0);
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void setResultSetType(sal_Int32 _par0);
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void setFetchDirection(sal_Int32 _par0);
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void setFetchSize(sal_Int32 _par0);
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void setCursorName(std::u16string_view _par0);
+
+ protected:
+
+ void assignRecordSet( ADORecordset* _pRS );
+
+ /// @throws css::sdbc::SQLException
+ void reset ();
+ /// @throws css::sdbc::SQLException
+ void clearMyResultSet ();
+ /// @throws css::sdbc::SQLException
+ void setWarning (const css::sdbc::SQLWarning &ex);
+ /// @throws css::sdbc::SQLException
+ sal_Int32 getRowCount ();
+ sal_Int32 getPrecision ( sal_Int32 sqlType);
+
+ void disposeResultSet();
+
+ // OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override;
+ // OPropertySetHelper
+ virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override;
+ virtual sal_Bool SAL_CALL convertFastPropertyValue(
+ css::uno::Any & rConvertedValue,
+ css::uno::Any & rOldValue,
+ sal_Int32 nHandle,
+ const css::uno::Any& rValue ) override;
+ virtual void SAL_CALL setFastPropertyValue_NoBroadcast(
+ sal_Int32 nHandle,
+ const css::uno::Any& rValue
+ ) override;
+ virtual void SAL_CALL getFastPropertyValue(
+ css::uno::Any& rValue,
+ sal_Int32 nHandle
+ ) const override;
+ public:
+ OStatement_Base(OConnection* _pConnection );
+
+ using OStatement_BASE::operator css::uno::Reference< css::uno::XInterface >;
+ // OComponentHelper
+ virtual void SAL_CALL disposing() override;
+ // XInterface
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ //XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override;
+
+ // XPropertySet
+ virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override;
+ // XStatement
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL executeQuery( const OUString& sql ) override;
+ virtual sal_Int32 SAL_CALL executeUpdate( const OUString& sql ) override;
+ virtual sal_Bool SAL_CALL execute( const OUString& sql ) override;
+ virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL getConnection( ) override;
+ // XWarningsSupplier
+ virtual css::uno::Any SAL_CALL getWarnings( ) override;
+ virtual void SAL_CALL clearWarnings( ) override;
+ // XCancellable
+ virtual void SAL_CALL cancel( ) override;
+ // XCloseable
+ virtual void SAL_CALL close( ) override;
+ // XMultipleResults
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getResultSet( ) override;
+ virtual sal_Int32 SAL_CALL getUpdateCount( ) override;
+ virtual sal_Bool SAL_CALL getMoreResults( ) override;
+ };
+
+ class OStatement : public OStatement_Base,
+ public css::sdbc::XBatchExecution,
+ public css::lang::XServiceInfo
+ {
+ public:
+ // a Constructor, that is needed for when Returning the Object is needed:
+ OStatement( OConnection* _pConnection) : OStatement_Base( _pConnection){};
+ ~OStatement() override;
+
+ DECLARE_SERVICE_INFO();
+
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ // XBatchExecution
+ virtual void SAL_CALL addBatch( const OUString& sql ) override;
+ virtual void SAL_CALL clearBatch( ) override;
+ virtual css::uno::Sequence< sal_Int32 > SAL_CALL executeBatch( ) override;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/ado/ATable.hxx b/connectivity/source/inc/ado/ATable.hxx
new file mode 100644
index 0000000000..827485a6b4
--- /dev/null
+++ b/connectivity/source/inc/ado/ATable.hxx
@@ -0,0 +1,69 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <connectivity/sdbcx/VTable.hxx>
+#include <ado/Awrapadox.hxx>
+#include <ado/ACatalog.hxx>
+
+namespace connectivity::ado
+{
+ typedef connectivity::sdbcx::OTable OTable_TYPEDEF;
+ typedef connectivity::sdbcx::OTableDescriptor_BASE OTableDescriptor_BASE_TYPEDEF;
+
+ class OAdoTable : public OTable_TYPEDEF
+ {
+ WpADOTable m_aTable;
+ OCatalog* m_pCatalog;
+
+ protected:
+ void fillPropertyValues();
+ virtual void SAL_CALL setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,const css::uno::Any& rValue) override;
+
+ public:
+ virtual void refreshColumns() override;
+ virtual void refreshKeys() override;
+ virtual void refreshIndexes() override;
+
+ // ::cppu::OComponentHelper
+ virtual void SAL_CALL disposing() override;
+
+ public:
+ OAdoTable(sdbcx::OCollection* _pTables,bool _bCase,OCatalog* _pCatalog,_ADOTable* _pTable);
+ OAdoTable(sdbcx::OCollection* _pTables,bool _bCase,OCatalog* _pCatalog);
+
+
+ virtual OUString SAL_CALL getName() override;
+ OUString getSchema() const { return m_SchemaName; }
+ virtual css::uno::Reference< css::sdbc::XDatabaseMetaData> getMetaData() const override;
+
+ // XRename
+ virtual void SAL_CALL rename( const OUString& newName ) override;
+
+ // XAlterTable
+ virtual void SAL_CALL alterColumnByName( const OUString& colName, const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override;
+ virtual void SAL_CALL alterColumnByIndex( sal_Int32 index, const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override;
+
+ WpADOTable getImpl() const { return m_aTable;}
+ OCatalog* getCatalog() const { return m_pCatalog; }
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/ado/ATables.hxx b/connectivity/source/inc/ado/ATables.hxx
new file mode 100644
index 0000000000..4fff5b9795
--- /dev/null
+++ b/connectivity/source/inc/ado/ATables.hxx
@@ -0,0 +1,52 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <connectivity/sdbcx/VCollection.hxx>
+#include <ado/Awrapadox.hxx>
+#include <ado/ACatalog.hxx>
+
+namespace connectivity::ado
+{
+ class OCatalog;
+ class OTables : public sdbcx::OCollection
+ {
+ WpADOTables m_aCollection;
+ OCatalog* m_pCatalog;
+ protected:
+ virtual sdbcx::ObjectType createObject(const OUString& _rName) override;
+ virtual void impl_refresh() override;
+ virtual css::uno::Reference< css::beans::XPropertySet > createDescriptor() override;
+ virtual sdbcx::ObjectType appendObject( const OUString& _rForName, const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override;
+ virtual void dropObject(sal_Int32 _nPos,const OUString& _sElementName) override;
+ public:
+ OTables(OCatalog* _pParent, ::osl::Mutex& _rMutex,
+ const ::std::vector< OUString> &_rVector,
+ const WpADOTables& _rCollection,
+ bool _bCase) : sdbcx::OCollection(*_pParent,_bCase,_rMutex,_rVector)
+ ,m_aCollection(_rCollection)
+ ,m_pCatalog(_pParent)
+ {
+ OSL_ENSURE(m_aCollection.IsValid(),"Collection isn't valid");
+ }
+ void appendNew(const OUString& _rsNewTable);
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/ado/AUser.hxx b/connectivity/source/inc/ado/AUser.hxx
new file mode 100644
index 0000000000..8d0c0f7321
--- /dev/null
+++ b/connectivity/source/inc/ado/AUser.hxx
@@ -0,0 +1,83 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sdbcx/VUser.hxx>
+#include <ado/Awrapadox.hxx>
+
+namespace connectivity::ado
+{
+ class OCatalog;
+ typedef connectivity::sdbcx::OUser OUser_TYPEDEF;
+ typedef connectivity::sdbcx::OUser_BASE OUser_BASE_TYPEDEF;
+
+ class OAdoUser : public OUser_TYPEDEF
+ {
+ protected:
+ WpADOUser m_aUser;
+ OCatalog* m_pCatalog;
+
+ virtual void SAL_CALL setFastPropertyValue_NoBroadcast(
+ sal_Int32 nHandle,
+ const css::uno::Any& rValue
+ ) override;
+ virtual void SAL_CALL getFastPropertyValue(
+ css::uno::Any& rValue,
+ sal_Int32 nHandle
+ ) const override;
+ public:
+ virtual void refreshGroups() override;
+ public:
+ OAdoUser(OCatalog* _pParent,bool _bCase, ADOUser* _pUser=nullptr);
+ OAdoUser(OCatalog* _pParent,bool _bCase, const OUString& Name);
+
+ // XUser
+ virtual void SAL_CALL changePassword( const OUString& objPassword, const OUString& newPassword ) override;
+ // XAuthorizable
+ virtual sal_Int32 SAL_CALL getPrivileges( const OUString& objName, sal_Int32 objType ) override;
+ virtual sal_Int32 SAL_CALL getGrantablePrivileges( const OUString& objName, sal_Int32 objType ) override;
+ virtual void SAL_CALL grantPrivileges( const OUString& objName, sal_Int32 objType, sal_Int32 objPrivileges ) override;
+ virtual void SAL_CALL revokePrivileges( const OUString& objName, sal_Int32 objType, sal_Int32 objPrivileges ) override;
+
+ WpADOUser getImpl() const { return m_aUser;}
+ };
+
+ class OUserExtend;
+ typedef ::comphelper::OPropertyArrayUsageHelper<OUserExtend> OUserExtend_PROP;
+
+ class OUserExtend : public OAdoUser,
+ public OUserExtend_PROP
+ {
+ protected:
+ OUString m_Password;
+ // OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper() const override;
+ // OPropertySetHelper
+ virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override;
+ public:
+ OUserExtend(OCatalog* _pParent,bool _bCase,ADOUser* _pUser=nullptr);
+ OUserExtend(OCatalog* _pParent,bool _bCase,const OUString& Name);
+
+ virtual void construct() override;
+ OUString getPassword() const { return m_Password;}
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/ado/AUsers.hxx b/connectivity/source/inc/ado/AUsers.hxx
new file mode 100644
index 0000000000..1ec0bd5ad8
--- /dev/null
+++ b/connectivity/source/inc/ado/AUsers.hxx
@@ -0,0 +1,53 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <connectivity/sdbcx/VCollection.hxx>
+#include <ado/Awrapadox.hxx>
+#include <ado/ACatalog.hxx>
+
+namespace connectivity::ado
+{
+
+ class OUsers : public sdbcx::OCollection
+ {
+ WpADOUsers m_aCollection;
+ OCatalog* m_pCatalog;
+ public:
+ virtual sdbcx::ObjectType createObject(const OUString& _rName) override;
+ virtual css::uno::Reference< css::beans::XPropertySet > createDescriptor() override;
+ virtual void impl_refresh() override;
+ virtual sdbcx::ObjectType appendObject( const OUString& _rForName, const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override;
+ virtual void dropObject(sal_Int32 _nPos,const OUString& _sElementName) override;
+ public:
+ OUsers( OCatalog* _pParent,
+ ::osl::Mutex& _rMutex,
+ const ::std::vector< OUString> &_rVector,
+ const WpADOUsers& _rCollection,
+ bool _bCase)
+ :sdbcx::OCollection(*_pParent,_bCase,_rMutex,_rVector)
+ ,m_aCollection(_rCollection)
+ ,m_pCatalog(_pParent)
+ {
+ }
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/ado/AView.hxx b/connectivity/source/inc/ado/AView.hxx
new file mode 100644
index 0000000000..db81c4e70b
--- /dev/null
+++ b/connectivity/source/inc/ado/AView.hxx
@@ -0,0 +1,47 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <connectivity/sdbcx/VView.hxx>
+#include <ado/Awrapadox.hxx>
+
+namespace connectivity::ado
+{
+
+ typedef sdbcx::OView OView_ADO;
+
+ class OAdoView : public OView_ADO
+ {
+ WpADOView m_aView;
+
+ protected:
+ // OPropertySetHelper
+ virtual void SAL_CALL getFastPropertyValue(
+ css::uno::Any& rValue,
+ sal_Int32 nHandle
+ ) const override;
+ public:
+ OAdoView(bool _bCase, ADOView* _pView=nullptr);
+
+ WpADOView getImpl() const { return m_aView;}
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/ado/AViews.hxx b/connectivity/source/inc/ado/AViews.hxx
new file mode 100644
index 0000000000..ef0c692fdf
--- /dev/null
+++ b/connectivity/source/inc/ado/AViews.hxx
@@ -0,0 +1,51 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <connectivity/sdbcx/VCollection.hxx>
+#include <ado/Awrapadox.hxx>
+#include <ado/ACatalog.hxx>
+
+
+namespace connectivity::ado
+{
+
+ class OViews : public sdbcx::OCollection
+ {
+ WpADOViews m_aCollection;
+ OCatalog* m_pCatalog;
+ protected:
+ virtual sdbcx::ObjectType createObject(const OUString& _rName) override;
+ virtual void impl_refresh() override;
+ virtual css::uno::Reference< css::beans::XPropertySet > createDescriptor() override;
+ virtual sdbcx::ObjectType appendObject( const OUString& _rForName, const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override;
+ virtual void dropObject(sal_Int32 _nPos,const OUString& _sElementName) override;
+ public:
+ OViews(OCatalog* _pParent, ::osl::Mutex& _rMutex,
+ const ::std::vector< OUString> &_rVector,
+ WpADOViews const & _rCollection,bool _bCase) : sdbcx::OCollection(*_pParent,_bCase,_rMutex,_rVector)
+ ,m_aCollection(_rCollection)
+ ,m_pCatalog(_pParent)
+ {
+ }
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/ado/Aolevariant.hxx b/connectivity/source/inc/ado/Aolevariant.hxx
new file mode 100644
index 0000000000..ba0653156a
--- /dev/null
+++ b/connectivity/source/inc/ado/Aolevariant.hxx
@@ -0,0 +1,123 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <sal/types.h>
+#include <rtl/ustring.hxx>
+#include <com/sun/star/uno/Sequence.hxx>
+
+#include <oaidl.h>
+
+namespace com::sun::star::util
+{
+ struct Date;
+ struct Time;
+ struct DateTime;
+}
+
+namespace connectivity::ado
+{
+ class OLEVariant : public ::tagVARIANT
+ {
+ public:
+ OLEVariant();
+ OLEVariant(const VARIANT& varSrc);
+ OLEVariant(const OLEVariant& varSrc) ;
+ OLEVariant(bool x) ;
+ OLEVariant(sal_Bool) = delete;
+ OLEVariant(sal_Int8 n) ;
+ OLEVariant(sal_Int16 n) ;
+ OLEVariant(sal_Int32 n) ;
+ OLEVariant(sal_Int64 x) ;
+
+ OLEVariant(std::u16string_view us);
+ OLEVariant(const OUString& us)
+ : OLEVariant(std::u16string_view(us))
+ {
+ }
+ ~OLEVariant() ;
+ OLEVariant(const css::util::Date& x );
+ OLEVariant(const css::util::Time& x );
+ OLEVariant(const css::util::DateTime& x );
+ OLEVariant(float x);
+ OLEVariant(const double &x);
+ OLEVariant(IDispatch* pDispInterface);
+ OLEVariant(const css::uno::Sequence< sal_Int8 >& x);
+ OLEVariant& operator=(const OLEVariant& varSrc);
+ // Assign a const VARIANT& (::VariantCopy handles everything)
+
+ OLEVariant& operator=(const tagVARIANT& varSrc);
+ // Assign a const VARIANT* (::VariantCopy handles everything)
+
+ OLEVariant& operator=(const VARIANT* pSrc);
+ void setByte(sal_uInt8 n) ;
+ void setInt16(sal_Int16 n) ;
+ void setInt32(sal_Int32 n) ;
+ void setFloat(float f) ;
+ void setDouble(double d) ;
+ void setDate(DATE d) ;
+ void setChar(unsigned char a) ;
+ void setCurrency(double aCur) ;
+ void setBool(bool b) ;
+ void setString(std::u16string_view us);
+ void setNoArg() ;
+
+ void setIDispatch(IDispatch* pDispInterface);
+ void setNull() ;
+ void setEmpty() ;
+
+ void setUI1SAFEARRAYPtr(SAFEARRAY* pSafeAr);
+ void setArray(SAFEARRAY* pSafeArray, VARTYPE vtType);
+ bool isNull() const ;
+ bool isEmpty() const ;
+
+ VARTYPE getType() const ;
+ void ChangeType(VARTYPE vartype, const OLEVariant* pSrc);
+
+ OUString getString() const;
+ bool getBool() const;
+ IUnknown* getIUnknown() const;
+ IDispatch* getIDispatch() const;
+ sal_uInt8 getByte() const;
+ sal_Int16 getInt16() const;
+ sal_Int8 getInt8() const;
+ sal_Int32 getInt32() const;
+ sal_uInt32 getUInt32() const;
+ float getFloat() const;
+ double getDouble() const;
+ double getDateAsDouble() const;
+ CY getCurrency() const;
+ css::util::Date getDate() const;
+ css::util::Time getTime() const;
+ css::util::DateTime getDateTime() const;
+ css::uno::Sequence<sal_Int8> getByteSequence() const;
+ SAFEARRAY* getUI1SAFEARRAYPtr() const;
+ css::uno::Any makeAny() const;
+
+ static VARIANT_BOOL VariantBool(bool bEinBoolean);
+
+ private:
+ void CHS();
+
+ void set(double n);
+
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/ado/Aolewrap.hxx b/connectivity/source/inc/ado/Aolewrap.hxx
new file mode 100644
index 0000000000..9d402fcf21
--- /dev/null
+++ b/connectivity/source/inc/ado/Aolewrap.hxx
@@ -0,0 +1,174 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <osl/diagnose.h>
+#include <osl/thread.h>
+#include <systools/win32/comtools.hxx>
+
+#include <map>
+#include <vector>
+
+#include "Aolevariant.hxx"
+
+namespace rtl
+{
+ class OUString;
+}
+namespace connectivity::ado
+{
+ // Template class WpOLEBase<class T>
+ // ==================================
+ //
+ // Objects of this class contain a pointer to an interface of the type T.
+
+ template<class T> class WpOLEBase
+ {
+ protected:
+ sal::systools::COMReference<T> pInterface;
+
+ public:
+ WpOLEBase(T* pInt = nullptr) : pInterface(pInt){}
+
+ WpOLEBase(const WpOLEBase<T>& aWrapper)
+ : pInterface( aWrapper.pInterface )
+ {
+ }
+
+ //inline
+ WpOLEBase<T>& operator=(const WpOLEBase<T>& rhs)
+ {
+ pInterface = rhs.pInterface;
+ return *this;
+ };
+
+ operator T*() const { return pInterface.get(); }
+ T** operator&() { return &pInterface; }
+ bool IsValid() const { return pInterface.is(); }
+ void set(T* p) { pInterface = p; }
+ void clear() { pInterface.clear(); }
+ };
+
+
+ // Template class WpOLECollection<class Ts, class WrapT>
+ // ===============================================================
+ //
+ // This class (derived from WpOLEBase<Ts>), abstracts away the properties
+ // common to DAO collections:
+ //
+ // They are accessed via an interface Ts (e.g. DAOFields) and can return
+ // Items of the type wrapped by WrapT (actually: with the interface, e.g.
+ // DAOField) via get_Item (here GetItem).
+ //
+ // This wrapper class exposes an object of the class WrapT.
+
+ template<class Ts, class WrapT> class WpOLECollection : public WpOLEBase<Ts>
+ {
+ public:
+ using WpOLEBase<Ts>::pInterface;
+ using WpOLEBase<Ts>::IsValid;
+ // Ctors, operator=
+ // They only call the superclass
+ WpOLECollection() = default;
+ WpOLECollection(const WpOLECollection& rhs) : WpOLEBase<Ts>(rhs) {}
+ WpOLECollection& operator=(const WpOLECollection& rhs)
+ {WpOLEBase<Ts>::operator=(rhs); return *this;};
+
+
+ void Refresh(){pInterface->Refresh();}
+
+ sal_Int32 GetItemCount() const
+ {
+ sal_Int32 nCount = 0;
+ return pInterface ? (SUCCEEDED(pInterface->get_Count(&nCount)) ? nCount : sal_Int32(0)) : sal_Int32(0);
+ }
+
+ WrapT GetItem(sal_Int32 index) const
+ {
+ OSL_ENSURE(index >= 0 && index<GetItemCount(),"Wrong index for field!");
+ WrapT aRet;
+ pInterface->get_Item(OLEVariant(index), &aRet);
+ return aRet;
+ }
+
+ WrapT GetItem(const OLEVariant& index) const
+ {
+ WrapT aRet;
+ pInterface->get_Item(index, &aRet);
+ return aRet;
+ }
+
+ WrapT GetItem(const OUString& sStr) const
+ {
+ WrapT aRet;
+ if (FAILED(pInterface->get_Item(OLEVariant(sStr), &aRet)))
+ {
+#if OSL_DEBUG_LEVEL > 0
+ OString sTemp("Unknown Item: " + OString(sStr.getStr(),sStr.getLength(),osl_getThreadTextEncoding()));
+ OSL_FAIL(sTemp.getStr());
+#endif
+ }
+ return aRet;
+ }
+ void fillElementNames(::std::vector< OUString>& _rVector)
+ {
+ if(IsValid())
+ {
+ Refresh();
+ sal_Int32 nCount = GetItemCount();
+ _rVector.reserve(nCount);
+ for(sal_Int32 i=0;i< nCount;++i)
+ {
+ WrapT aElement = GetItem(i);
+ if(aElement.IsValid())
+ _rVector.push_back(aElement.get_Name());
+ }
+ }
+ }
+ };
+
+ template<class Ts, class WrapT> class WpOLEAppendCollection:
+ public WpOLECollection<Ts,WrapT>
+ {
+
+ public:
+ // Ctors, operator=
+ // They only call the superclass
+ using WpOLEBase<Ts>::pInterface;
+ WpOLEAppendCollection() = default;
+ WpOLEAppendCollection(const WpOLEAppendCollection& rhs) : WpOLECollection<Ts, WrapT>(rhs) {}
+ WpOLEAppendCollection& operator=(const WpOLEAppendCollection& rhs)
+ {WpOLEBase<Ts>::operator=(rhs); return *this;};
+
+
+ bool Append(const WrapT& aWrapT)
+ {
+ return SUCCEEDED(pInterface->Append(OLEVariant(aWrapT)));
+ };
+
+ bool Delete(const OUString& sName)
+ {
+ return SUCCEEDED(pInterface->Delete(OLEVariant(sName)));
+ };
+
+
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/ado/Awrapado.hxx b/connectivity/source/inc/ado/Awrapado.hxx
new file mode 100644
index 0000000000..507b855226
--- /dev/null
+++ b/connectivity/source/inc/ado/Awrapado.hxx
@@ -0,0 +1,372 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <sal/config.h>
+
+#include <string_view>
+
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+
+// Includes for ADO
+#include <oledb.h>
+#include <ocidl.h>
+#include <adoint.h>
+#include <ado/adoimp.hxx>
+#include <ado/Aolewrap.hxx>
+#include <ado/Aolevariant.hxx>
+
+namespace connectivity::ado
+{
+ class WpADOConnection;
+ class WpADOCommand;
+ class WpADORecordset;
+ class WpADOField;
+ class WpADOParameter;
+ class WpADOError;
+ class WpADOProperty;
+
+ typedef WpOLEAppendCollection< ADOFields, WpADOField> WpADOFields;
+ typedef WpOLECollection< ADOProperties, WpADOProperty> WpADOProperties;
+
+
+ class WpADOConnection : public WpOLEBase<ADOConnection>
+ {
+ public:
+
+ WpADOConnection() = default;
+
+ WpADOConnection(const WpADOConnection& rhs) : WpOLEBase<ADOConnection>(rhs) {}
+
+ WpADOConnection& operator=(const WpADOConnection& rhs)
+ {WpOLEBase<ADOConnection>::operator=(rhs); return *this;}
+
+
+ WpADOProperties get_Properties() const;
+
+ OUString GetConnectionString() const;
+ bool PutConnectionString(std::u16string_view aCon) const;
+ sal_Int32 GetCommandTimeout() const;
+ void PutCommandTimeout(sal_Int32 nRet);
+ sal_Int32 GetConnectionTimeout() const ;
+ void PutConnectionTimeout(sal_Int32 nRet);
+
+ bool Close( ) ;
+ bool Execute(std::u16string_view CommandText,OLEVariant& RecordsAffected,long Options, WpADORecordset** ppiRset);
+ bool BeginTrans();
+ bool CommitTrans( ) ;
+ bool RollbackTrans( );
+ bool Open(std::u16string_view ConnectionString, std::u16string_view UserID,std::u16string_view Password,long Options);
+ bool GetErrors(ADOErrors** pErrors);
+
+ OUString GetDefaultDatabase() const;
+ bool PutDefaultDatabase(std::u16string_view _bstr);
+
+ IsolationLevelEnum get_IsolationLevel() const ;
+ bool put_IsolationLevel(const IsolationLevelEnum& eNum) ;
+
+ sal_Int32 get_Attributes() const;
+ bool put_Attributes(sal_Int32 nRet);
+
+ CursorLocationEnum get_CursorLocation() const;
+ bool put_CursorLocation(const CursorLocationEnum &eNum) ;
+
+ ConnectModeEnum get_Mode() const;
+ bool put_Mode(const ConnectModeEnum &eNum) ;
+
+ OUString get_Provider() const;
+ bool put_Provider(std::u16string_view _bstr);
+
+ sal_Int32 get_State() const;
+
+ bool OpenSchema(SchemaEnum eNum,OLEVariant const & Restrictions,OLEVariant const & SchemaID,ADORecordset**pprset);
+
+ OUString get_Version() const;
+
+ // special methods
+ ADORecordset* getExportedKeys( const css::uno::Any& catalog, const OUString& schema, std::u16string_view table );
+ ADORecordset* getImportedKeys( const css::uno::Any& catalog, const OUString& schema, std::u16string_view table );
+ ADORecordset* getPrimaryKeys( const css::uno::Any& catalog, const OUString& schema, std::u16string_view table );
+ ADORecordset* getIndexInfo( const css::uno::Any& catalog, const OUString& schema, std::u16string_view table, bool unique, bool approximate );
+ ADORecordset* getTablePrivileges( const css::uno::Any& catalog,
+ const OUString& schemaPattern,
+ std::u16string_view tableNamePattern );
+ ADORecordset* getCrossReference( const css::uno::Any& primaryCatalog,
+ const OUString& primarySchema,
+ std::u16string_view primaryTable,
+ const css::uno::Any& foreignCatalog,
+ const OUString& foreignSchema,
+ std::u16string_view foreignTable);
+ ADORecordset* getProcedures( const css::uno::Any& catalog,
+ const OUString& schemaPattern,
+ std::u16string_view procedureNamePattern );
+ ADORecordset* getProcedureColumns( const css::uno::Any& catalog,
+ const OUString& schemaPattern,
+ std::u16string_view procedureNamePattern,
+ std::u16string_view columnNamePattern );
+ ADORecordset* getTables( const css::uno::Any& catalog,
+ const OUString& schemaPattern,
+ std::u16string_view tableNamePattern,
+ const css::uno::Sequence< OUString >& types );
+ ADORecordset* getColumns( const css::uno::Any& catalog,
+ const OUString& schemaPattern,
+ std::u16string_view tableNamePattern,
+ std::u16string_view columnNamePattern );
+ ADORecordset* getColumnPrivileges( const css::uno::Any& catalog,
+ const OUString& schemaPattern,
+ std::u16string_view table,
+ std::u16string_view columnNamePattern );
+ ADORecordset* getTypeInfo(DataTypeEnum _eType = adEmpty );
+ };
+
+
+ class WpADOCommand : public WpOLEBase<ADOCommand>
+ {
+ public:
+ WpADOCommand() = default;
+ // Ctors, operator=
+ // They only call the superclass
+ WpADOCommand(const WpADOCommand& rhs) : WpOLEBase<ADOCommand>(rhs) {}
+
+ WpADOCommand& operator=(const WpADOCommand& rhs)
+ {
+ WpOLEBase<ADOCommand>::operator=(rhs); return *this;}
+
+
+ bool putref_ActiveConnection(const WpADOConnection& rCon);
+
+ void put_ActiveConnection(/* [in] */ const OLEVariant& vConn);
+ void Create();
+ sal_Int32 get_State() const;
+ OUString get_CommandText() const;
+ bool put_CommandText(std::u16string_view aCon) ;
+ sal_Int32 get_CommandTimeout() const;
+ void put_CommandTimeout(sal_Int32 nRet);
+ bool get_Prepared() const;
+ bool put_Prepared(VARIANT_BOOL bPrepared) const;
+ bool Execute(OLEVariant& RecordsAffected,OLEVariant& Parameters,long Options, ADORecordset** ppiRset);
+ ADOParameter* CreateParameter(std::u16string_view _bstr,DataTypeEnum Type,ParameterDirectionEnum Direction,long nSize,const OLEVariant &Value);
+
+ ADOParameters* get_Parameters() const;
+ bool put_CommandType( /* [in] */ CommandTypeEnum lCmdType);
+ CommandTypeEnum get_CommandType( ) const ;
+ // Returns the field's name
+ OUString GetName() const ;
+ bool put_Name(std::u16string_view Name);
+ bool Cancel();
+ };
+
+ class WpADOError : public WpOLEBase<ADOError>
+ {
+ public:
+
+ // Ctors, operator=
+ // They only call the superclass
+ WpADOError() = default;
+
+ WpADOError(const WpADOError& rhs) : WpOLEBase<ADOError>(rhs) {}
+
+ WpADOError& operator=(const WpADOError& rhs)
+ {WpOLEBase<ADOError>::operator=(rhs); return *this;}
+
+
+ OUString GetDescription() const;
+ OUString GetSource() const ;
+ sal_Int32 GetNumber() const ;
+ OUString GetSQLState() const ;
+ sal_Int32 GetNativeError() const ;
+ };
+
+
+ class WpADOField : public WpOLEBase<ADOField>
+ {
+ // friend class WpADOFields;
+ public:
+
+ // Ctors, operator=
+ // They only call the superclass
+ WpADOField() = default;
+ WpADOField(const WpADOField& rhs) : WpOLEBase<ADOField>(rhs) {}
+
+ WpADOField& operator=(const WpADOField& rhs)
+ {WpOLEBase<ADOField>::operator=(rhs); return *this;}
+
+
+ WpADOProperties get_Properties();
+ sal_Int32 GetActualSize() const ;
+ sal_Int32 GetAttributes() const ;
+ sal_Int32 GetStatus() const ;
+ sal_Int32 GetDefinedSize() const ;
+ // Returns the field's name
+ OUString GetName() const ;
+ DataTypeEnum GetADOType() const ;
+ void get_Value(OLEVariant& aValVar) const ;
+ OLEVariant get_Value() const;
+ bool PutValue(const OLEVariant& aVariant);
+ sal_Int32 GetPrecision() const ;
+ sal_Int32 GetNumericScale() const ;
+ bool AppendChunk(const OLEVariant& Variant);
+ OLEVariant GetChunk(long Length) const;
+ void GetChunk(long Length,OLEVariant &aValVar) const;
+ OLEVariant GetOriginalValue() const;
+ void GetOriginalValue(OLEVariant &aValVar) const;
+ OLEVariant GetUnderlyingValue() const;
+
+ void GetUnderlyingValue(OLEVariant &aValVar) const;
+
+ bool PutPrecision(sal_Int8 _prec);
+
+ bool PutNumericScale(sal_Int8 _prec);
+
+ void PutADOType(DataTypeEnum eType) ;
+
+ bool PutDefinedSize(sal_Int32 _nDefSize);
+
+ bool PutAttributes(sal_Int32 _nDefSize);
+ };
+
+
+ class WpADOProperty: public WpOLEBase<ADOProperty>
+ {
+ public:
+ // Ctors, operator=
+ // They only call the superclass
+ WpADOProperty() = default;
+ WpADOProperty(const WpADOProperty& rhs) : WpOLEBase<ADOProperty>(rhs) {}
+ WpADOProperty& operator=(const WpADOProperty& rhs)
+ {WpOLEBase<ADOProperty>::operator=(rhs); return *this;}
+
+
+ OLEVariant GetValue() const;
+ void GetValue(OLEVariant &aValVar) const;
+ bool PutValue(const OLEVariant &aValVar) ;
+ OUString GetName() const ;
+ DataTypeEnum GetADOType() const ;
+ sal_Int32 GetAttributes() const ;
+ bool PutAttributes(sal_Int32 _nDefSize);
+ };
+
+
+ class WpADORecordset : public WpOLEBase<ADORecordset>
+ {
+
+ public:
+ // Ctors, operator=
+ // They only call the superclass
+ WpADORecordset() = default;
+ WpADORecordset(const WpADORecordset& rhs) : WpOLEBase<ADORecordset>() {operator=(rhs);}
+ WpADORecordset& operator=(const WpADORecordset& rhs)
+ {
+ WpOLEBase<ADORecordset>::operator=(rhs);
+ return *this;
+ }
+
+ void Create();
+ bool Open(
+ /* [optional][in] */ VARIANT Source,
+ /* [optional][in] */ VARIANT ActiveConnection,
+ /* [defaultvalue][in] */ CursorTypeEnum CursorType,
+ /* [defaultvalue][in] */ LockTypeEnum LockType,
+ /* [defaultvalue][in] */ sal_Int32 Options);
+ LockTypeEnum GetLockType();
+ void Close();
+ bool Cancel() const;
+ sal_Int32 get_State( );
+ bool Supports( /* [in] */ CursorOptionEnum CursorOptions);
+ PositionEnum_Param get_AbsolutePosition();
+ void GetDataSource(IUnknown** pIUnknown) const ;
+ void PutRefDataSource(IUnknown* pIUnknown);
+ void GetBookmark(VARIANT& var);
+ OLEVariant GetBookmark();
+ CompareEnum CompareBookmarks(const OLEVariant& left,const OLEVariant& right);
+ bool SetBookmark(const OLEVariant &pSafeAr);
+ WpADOFields GetFields() const;
+ bool Move(sal_Int32 nRows, VARIANT aBmk);
+ bool MoveNext();
+ bool MovePrevious();
+ bool MoveFirst();
+ bool MoveLast();
+
+ bool IsAtBOF() const;
+ bool IsAtEOF() const;
+ bool Delete(AffectEnum eNum);
+ bool AddNew(const OLEVariant &FieldList,const OLEVariant &Values);
+ bool Update(const OLEVariant &FieldList,const OLEVariant &Values);
+ bool CancelUpdate();
+ WpADOProperties get_Properties() const;
+ bool NextRecordset(OLEVariant& RecordsAffected,ADORecordset** ppiRset);
+ bool get_RecordCount(ADO_LONGPTR &_nRet) const;
+ bool get_MaxRecords(ADO_LONGPTR &_nRet) const;
+ bool put_MaxRecords(ADO_LONGPTR _nRet);
+ bool get_CursorType(CursorTypeEnum &_nRet) const;
+ bool put_CursorType(CursorTypeEnum _nRet);
+ bool get_LockType(LockTypeEnum &_nRet) const;
+ bool put_LockType(LockTypeEnum _nRet);
+ bool get_CacheSize(sal_Int32 &_nRet) const;
+ bool put_CacheSize(sal_Int32 _nRet);
+ bool UpdateBatch(AffectEnum AffectRecords);
+ };
+
+
+ class WpADOParameter:public WpOLEBase<ADOParameter>
+ {
+ public:
+ // Ctors, operator=
+ // They only call the superclass
+ WpADOParameter() = default;
+ WpADOParameter(const WpADOParameter& rhs):WpOLEBase<ADOParameter>(rhs){}
+ WpADOParameter& operator=(const WpADOParameter& rhs)
+ {WpOLEBase<ADOParameter>::operator=(rhs); return *this;}
+
+
+ OUString GetName() const ;
+ DataTypeEnum GetADOType() const ;
+ void put_Type(const DataTypeEnum& _eType);
+ bool put_Size(sal_Int32 _nSize);
+ sal_Int32 GetAttributes() const ;
+ sal_Int32 GetPrecision() const ;
+ sal_Int32 GetNumericScale() const ;
+ ParameterDirectionEnum get_Direction() const;
+ void GetValue(OLEVariant& aValVar) const ;
+ OLEVariant GetValue() const;
+ bool PutValue(const OLEVariant& aVariant);
+ bool AppendChunk(const OLEVariant& aVariant);
+ };
+
+ class OTools
+ {
+ public:
+ /** putValue set the property value at the ado column
+ @param _rProps the properties where to set
+ @param _aPosition which property to set
+ @param _aValVar the value to set
+ */
+ static void putValue(const WpADOProperties& _rProps,const OLEVariant &_aPosition,const OLEVariant &_aValVar);
+
+ /** getValue returns a specific property value
+ @param _rProps the properties where to set
+ @param _aPosition the property
+
+ @return the property value
+ */
+ static OLEVariant getValue(const WpADOProperties& _rProps,const OLEVariant &_aPosition);
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/ado/Awrapadox.hxx b/connectivity/source/inc/ado/Awrapadox.hxx
new file mode 100644
index 0000000000..ba91422a1d
--- /dev/null
+++ b/connectivity/source/inc/ado/Awrapadox.hxx
@@ -0,0 +1,139 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <string_view>
+
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+
+#ifndef __User_FWD_DEFINED__
+#define __User_FWD_DEFINED__
+typedef struct _ADOUser User;
+#endif
+
+#ifndef __Group_FWD_DEFINED__
+#define __Group_FWD_DEFINED__
+typedef struct _ADOGroup Group;
+#endif
+
+#ifndef __Column_FWD_DEFINED__
+#define __Column_FWD_DEFINED__
+typedef struct _ADOColumn Column;
+#endif
+
+#ifndef __Index_FWD_DEFINED__
+#define __Index_FWD_DEFINED__
+typedef struct _ADOIndex Index;
+#endif
+
+#ifndef __Key_FWD_DEFINED__
+#define __Key_FWD_DEFINED__
+typedef struct _ADOKey Key;
+#endif
+
+#ifndef __Table_FWD_DEFINED__
+#define __Table_FWD_DEFINED__
+typedef struct _ADOTable Table;
+#endif
+
+
+#include <adoint.h>
+#include <adoctint.h>
+
+
+#include <ado/Aolewrap.hxx>
+#include <ado/Aolevariant.hxx>
+#include <ado/adoimp.hxx>
+#include <ado/Awrapado.hxx>
+#include <ado/WrapColumn.hxx>
+#include <ado/WrapIndex.hxx>
+#include <ado/WrapKey.hxx>
+#include <ado/WrapTable.hxx>
+#include <ado/WrapCatalog.hxx>
+
+namespace connectivity::ado
+{
+ class WpADOView : public WpOLEBase<ADOView>
+ {
+ public:
+ WpADOView(ADOView* pInt=nullptr) : WpOLEBase<ADOView>(pInt){}
+ WpADOView(const WpADOView& rhs) : WpOLEBase<ADOView>(rhs) {}
+
+ WpADOView& operator=(const WpADOView& rhs)
+ {WpOLEBase<ADOView>::operator=(rhs); return *this;}
+
+ OUString get_Name() const;
+ void get_Command(OLEVariant& _rVar) const;
+ void put_Command(OLEVariant const & _rVar);
+ };
+
+ class WpADOGroup : public WpOLEBase<ADOGroup>
+ {
+ public:
+ WpADOGroup() = default;
+ WpADOGroup(const WpADOGroup& rhs) : WpOLEBase<ADOGroup>(rhs) {}
+
+ WpADOGroup& operator=(const WpADOGroup& rhs)
+ {WpOLEBase<ADOGroup>::operator=(rhs); return *this;}
+
+ void Create();
+
+ OUString get_Name() const;
+ void put_Name(std::u16string_view _rName);
+ RightsEnum GetPermissions(
+ /* [in] */ const OLEVariant& Name,
+ /* [in] */ ObjectTypeEnum ObjectType);
+ bool SetPermissions(
+ /* [in] */ const OLEVariant& Name,
+ /* [in] */ ObjectTypeEnum ObjectType,
+ /* [in] */ ActionEnum Action,
+ /* [in] */ RightsEnum Rights);
+ WpADOUsers get_Users( );
+ };
+
+ class WpADOUser : public WpOLEBase<_ADOUser>
+ {
+ public:
+ WpADOUser() = default;
+ WpADOUser(const WpADOUser& rhs) : WpOLEBase<_ADOUser>(rhs) {}
+
+ WpADOUser& operator=(const WpADOUser& rhs)
+ {WpOLEBase<_ADOUser>::operator=(rhs); return *this;}
+
+ void Create();
+
+ OUString get_Name() const;
+ void put_Name(std::u16string_view _rName);
+ bool ChangePassword(std::u16string_view _rPwd,std::u16string_view _rNewPwd);
+ WpADOGroups get_Groups();
+ RightsEnum GetPermissions(
+ /* [in] */ const OLEVariant& Name,
+ /* [in] */ ObjectTypeEnum ObjectType);
+ bool SetPermissions(
+ /* [in] */ const OLEVariant& Name,
+ /* [in] */ ObjectTypeEnum ObjectType,
+ /* [in] */ ActionEnum Action,
+ /* [in] */ RightsEnum Rights);
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/ado/WrapCatalog.hxx b/connectivity/source/inc/ado/WrapCatalog.hxx
new file mode 100644
index 0000000000..0bcff441c2
--- /dev/null
+++ b/connectivity/source/inc/ado/WrapCatalog.hxx
@@ -0,0 +1,50 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <sal/config.h>
+
+#include <string_view>
+
+#include <ado/WrapTypeDefs.hxx>
+
+namespace connectivity::ado
+{
+ class WpADOCatalog : public WpOLEBase<_ADOCatalog>
+ {
+ public:
+ WpADOCatalog(_ADOCatalog* pInt = nullptr) : WpOLEBase<_ADOCatalog>(pInt){}
+ WpADOCatalog(const WpADOCatalog& rhs) : WpOLEBase<_ADOCatalog>(rhs) {}
+
+ WpADOCatalog& operator=(const WpADOCatalog& rhs)
+ {WpOLEBase<_ADOCatalog>::operator=(rhs); return *this;}
+
+ OUString GetObjectOwner(std::u16string_view _rName, ObjectTypeEnum _eNum);
+
+ void putref_ActiveConnection(IDispatch* pCon);
+ WpADOTables get_Tables();
+ WpADOViews get_Views();
+ WpADOGroups get_Groups();
+ WpADOUsers get_Users();
+ ADOProcedures* get_Procedures();
+ void Create();
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/ado/WrapColumn.hxx b/connectivity/source/inc/ado/WrapColumn.hxx
new file mode 100644
index 0000000000..f1b73585fb
--- /dev/null
+++ b/connectivity/source/inc/ado/WrapColumn.hxx
@@ -0,0 +1,62 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <sal/config.h>
+
+#include <string_view>
+
+#include <ado/Aolewrap.hxx>
+
+#include <adoint.h>
+
+namespace connectivity::ado
+{
+ class WpADOColumn : public WpOLEBase<_ADOColumn>
+ {
+ public:
+ WpADOColumn() = default;
+ WpADOColumn(const WpADOColumn& rhs) : WpOLEBase<_ADOColumn>(rhs) {}
+
+ void Create();
+
+ WpADOColumn& operator=(const WpADOColumn& rhs)
+ {WpOLEBase<_ADOColumn>::operator=(rhs); return *this;}
+
+ OUString get_Name() const;
+ OUString get_RelatedColumn() const;
+ void put_Name(std::u16string_view _rName);
+ void put_RelatedColumn(std::u16string_view _rName);
+ DataTypeEnum get_Type() const;
+ void put_Type(const DataTypeEnum& _eNum) ;
+ sal_Int32 get_Precision() const;
+ void put_Precision(sal_Int32 _nPre) ;
+ sal_uInt8 get_NumericScale() const;
+ void put_NumericScale(sal_Int8 _nScale);
+ SortOrderEnum get_SortOrder() const;
+ void put_SortOrder(SortOrderEnum _nScale);
+ sal_Int32 get_DefinedSize() const;
+ ColumnAttributesEnum get_Attributes() const;
+ bool put_Attributes(const ColumnAttributesEnum& _eNum);
+ WpADOProperties get_Properties() const;
+ void put_ParentCatalog(/* [in] */ _ADOCatalog __RPC_FAR *ppvObject);
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/ado/WrapIndex.hxx b/connectivity/source/inc/ado/WrapIndex.hxx
new file mode 100644
index 0000000000..4444bb340a
--- /dev/null
+++ b/connectivity/source/inc/ado/WrapIndex.hxx
@@ -0,0 +1,52 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <sal/config.h>
+
+#include <string_view>
+
+#include <ado/WrapTypeDefs.hxx>
+
+namespace connectivity::ado
+{
+ class WpADOIndex : public WpOLEBase<_ADOIndex>
+ {
+ public:
+ WpADOIndex() = default;
+ WpADOIndex(const WpADOIndex& rhs) : WpOLEBase<_ADOIndex>(rhs) {}
+
+ WpADOIndex& operator=(const WpADOIndex& rhs)
+ {WpOLEBase<_ADOIndex>::operator=(rhs); return *this;}
+
+ void Create();
+
+ OUString get_Name() const;
+ void put_Name(std::u16string_view _rName);
+ bool get_Clustered() const;
+ void put_Clustered(bool _b);
+ bool get_Unique() const;
+ void put_Unique(bool _b);
+ bool get_PrimaryKey() const;
+ void put_PrimaryKey(bool _b);
+ WpADOColumns get_Columns() const;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/ado/WrapKey.hxx b/connectivity/source/inc/ado/WrapKey.hxx
new file mode 100644
index 0000000000..1f984445b8
--- /dev/null
+++ b/connectivity/source/inc/ado/WrapKey.hxx
@@ -0,0 +1,54 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <sal/config.h>
+
+#include <string_view>
+
+#include <ado/WrapTypeDefs.hxx>
+
+namespace connectivity::ado
+{
+ class WpADOKey : public WpOLEBase<ADOKey>
+ {
+ public:
+ WpADOKey() = default;
+ WpADOKey(const WpADOKey& rhs) : WpOLEBase<ADOKey>(rhs) {}
+
+ WpADOKey& operator=(const WpADOKey& rhs)
+ {WpOLEBase<ADOKey>::operator=(rhs); return *this;}
+
+ void Create();
+
+ OUString get_Name() const;
+ void put_Name(std::u16string_view _rName);
+ KeyTypeEnum get_Type() const;
+ void put_Type(const KeyTypeEnum& _eNum) ;
+ OUString get_RelatedTable() const;
+ void put_RelatedTable(std::u16string_view _rName);
+ RuleEnum get_DeleteRule() const;
+ void put_DeleteRule(const RuleEnum& _eNum) ;
+ RuleEnum get_UpdateRule() const;
+ void put_UpdateRule(const RuleEnum& _eNum) ;
+ WpADOColumns get_Columns() const;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/ado/WrapTable.hxx b/connectivity/source/inc/ado/WrapTable.hxx
new file mode 100644
index 0000000000..dc06dbc03a
--- /dev/null
+++ b/connectivity/source/inc/ado/WrapTable.hxx
@@ -0,0 +1,57 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <sal/config.h>
+
+#include <string_view>
+
+#include <ado/WrapTypeDefs.hxx>
+
+namespace connectivity::ado
+{
+ class WpADOCatalog;
+
+ class WpADOTable : public WpOLEBase<_ADOTable>
+ {
+ public:
+ WpADOTable() = default;
+ WpADOTable(const WpADOTable& rhs) : WpOLEBase<_ADOTable>(rhs) {}
+
+ WpADOTable& operator=(const WpADOTable& rhs)
+ {WpOLEBase<_ADOTable>::operator=(rhs); return *this;}
+
+ void Create();
+
+ OUString get_Name() const;
+ void put_Name(std::u16string_view _rName);
+ OUString get_Type() const;
+ WpADOColumns get_Columns() const;
+ WpADOIndexes get_Indexes() const;
+ WpADOKeys get_Keys() const;
+ WpADOCatalog get_ParentCatalog() const;
+ WpADOProperties get_Properties() const;
+ void putref_ParentCatalog(/* [in] */ _ADOCatalog __RPC_FAR *ppvObject);
+ };
+
+
+ typedef WpOLEAppendCollection<ADOTables, WpADOTable> WpADOTables;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/ado/WrapTypeDefs.hxx b/connectivity/source/inc/ado/WrapTypeDefs.hxx
new file mode 100644
index 0000000000..91bea84534
--- /dev/null
+++ b/connectivity/source/inc/ado/WrapTypeDefs.hxx
@@ -0,0 +1,41 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+
+namespace connectivity::ado
+{
+ class WpADOTable;
+ class WpADOKey;
+ class WpADOIndex;
+ class WpADOColumn;
+ class WpADOGroup;
+ class WpADOView;
+ class WpADOUser;
+
+ typedef WpOLEAppendCollection<ADOTables, WpADOTable> WpADOTables;
+ typedef WpOLEAppendCollection<ADOKeys, WpADOKey> WpADOKeys;
+ typedef WpOLEAppendCollection<ADOIndexes, WpADOIndex> WpADOIndexes;
+ typedef WpOLEAppendCollection<ADOColumns, WpADOColumn> WpADOColumns;
+ typedef WpOLEAppendCollection<ADOGroups, WpADOGroup> WpADOGroups;
+ typedef WpOLEAppendCollection<ADOViews, WpADOView> WpADOViews;
+ typedef WpOLEAppendCollection<ADOUsers, WpADOUser> WpADOUsers;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/ado/adoimp.hxx b/connectivity/source/inc/ado/adoimp.hxx
new file mode 100644
index 0000000000..60c6fd313d
--- /dev/null
+++ b/connectivity/source/inc/ado/adoimp.hxx
@@ -0,0 +1,103 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <com/sun/star/sdbc/SQLException.hpp>
+
+#include <adoctint.h>
+
+struct ADOConnection;
+
+namespace sal::systools { class BStr; };
+
+namespace connectivity::ado
+{
+
+ class WpADOField;
+ class ADOS
+ {
+ public:
+ // Also here: Free BSTR with SysFreeString()!
+ static sal::systools::BStr& GetKeyStr();
+
+ static const CLSID CLSID_ADOCATALOG_25;
+ static const IID IID_ADOCATALOG_25;
+
+ static const CLSID CLSID_ADOCONNECTION_21;
+ static const IID IID_ADOCONNECTION_21;
+
+ static const CLSID CLSID_ADOCOMMAND_21;
+ static const IID IID_ADOCOMMAND_21;
+
+ static const CLSID CLSID_ADORECORDSET_21;
+ static const IID IID_ADORECORDSET_21;
+
+ static const CLSID CLSID_ADOINDEX_25;
+ static const IID IID_ADOINDEX_25;
+
+ static const CLSID CLSID_ADOCOLUMN_25;
+ static const IID IID_ADOCOLUMN_25;
+
+ static const CLSID CLSID_ADOKEY_25;
+ static const IID IID_ADOKEY_25;
+
+ static const CLSID CLSID_ADOTABLE_25;
+ static const IID IID_ADOTABLE_25;
+
+ static const CLSID CLSID_ADOGROUP_25;
+ static const IID IID_ADOGROUP_25;
+
+ static const CLSID CLSID_ADOUSER_25;
+ static const IID IID_ADOUSER_25;
+
+ static const CLSID CLSID_ADOVIEW_25;
+ static const IID IID_ADOVIEW_25;
+
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ static void ThrowException(ADOConnection* _pAdoCon,const css::uno::Reference< css::uno::XInterface >& _xInterface);
+ static sal_Int32 MapADOType2Jdbc(DataTypeEnum eType);
+ static DataTypeEnum MapJdbc2ADOType(sal_Int32 _nType,sal_Int32 _nJetEngine);
+ static bool isJetEngine(sal_Int32 _nEngineType);
+
+ static ObjectTypeEnum mapObjectType2Ado(sal_Int32 objType);
+ static sal_Int32 mapAdoType2Object(ObjectTypeEnum objType);
+ static sal_Int32 mapAdoRights2Sdbc(RightsEnum eRights);
+ static sal_Int32 mapRights2Ado(sal_Int32 nRights);
+
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ static WpADOField getField(ADORecordset* _pRecordSet,sal_Int32 _nColumnIndex);
+ };
+
+
+}
+
+
+#define ADO_PROP(ItemName) \
+ WpADOProperty aProp(aProps.GetItem(ItemName)); \
+ OLEVariant aVar; \
+ if(aProp.IsValid()) \
+ aVar = aProp.GetValue(); \
+ else \
+ ADOS::ThrowException(m_rADOConnection,*this);
+
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/calc/CCatalog.hxx b/connectivity/source/inc/calc/CCatalog.hxx
new file mode 100644
index 0000000000..466e96ece8
--- /dev/null
+++ b/connectivity/source/inc/calc/CCatalog.hxx
@@ -0,0 +1,38 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <file/FCatalog.hxx>
+
+namespace connectivity::calc
+{
+ class OCalcConnection;
+ class OCalcCatalog : public file::OFileCatalog
+ {
+ public:
+ virtual void refreshTables() override;
+
+ public:
+ OCalcCatalog(OCalcConnection* _pCon);
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/calc/CConnection.hxx b/connectivity/source/inc/calc/CConnection.hxx
new file mode 100644
index 0000000000..6eabeccef5
--- /dev/null
+++ b/connectivity/source/inc/calc/CConnection.hxx
@@ -0,0 +1,149 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <memory>
+#include <file/FConnection.hxx>
+#include <com/sun/star/frame/XDesktop2.hpp>
+#include <com/sun/star/frame/XTerminateListener.hpp>
+#include <rtl/ref.hxx>
+#include <unotools/closeveto.hxx>
+
+namespace com::sun::star {
+ namespace sheet { class XSpreadsheetDocument; }
+}
+
+namespace utl { class CloseVeto; }
+
+
+namespace connectivity::calc
+ {
+ class ODriver;
+ class OCalcConnection : public file::OConnection
+ {
+ // the spreadsheet document:
+ css::uno::Reference< css::sheet::XSpreadsheetDocument > m_xDoc;
+ OUString m_sPassword;
+ OUString m_aFileName;
+ oslInterlockedCount m_nDocCount;
+
+ class CloseVetoButTerminateListener : public cppu::WeakComponentImplHelper<css::frame::XTerminateListener>
+ {
+ private:
+ /// close listener that vetoes so nobody else disposes m_xDoc
+ std::unique_ptr<utl::CloseVeto> m_pCloseListener;
+ /// but also listen to XDesktop and if app is terminating anyway, dispose m_xDoc while
+ /// its still possible to do so properly
+ css::uno::Reference<css::frame::XDesktop2> m_xDesktop;
+ osl::Mutex m_aMutex;
+ public:
+ CloseVetoButTerminateListener()
+ : cppu::WeakComponentImplHelper<css::frame::XTerminateListener>(m_aMutex)
+ {
+ }
+
+ void start(const css::uno::Reference<css::uno::XInterface>& rCloseable,
+ const css::uno::Reference<css::frame::XDesktop2>& rDesktop)
+ {
+ m_xDesktop = rDesktop;
+ m_xDesktop->addTerminateListener(this);
+ m_pCloseListener.reset(new utl::CloseVeto(rCloseable, true));
+ }
+
+ void stop()
+ {
+ m_pCloseListener.reset();
+ if (!m_xDesktop.is())
+ return;
+ m_xDesktop->removeTerminateListener(this);
+ m_xDesktop.clear();
+ }
+
+ // XTerminateListener
+ virtual void SAL_CALL queryTermination(const css::lang::EventObject& /*rEvent*/) override
+ {
+ }
+
+ virtual void SAL_CALL notifyTermination(const css::lang::EventObject& /*rEvent*/) override
+ {
+ stop();
+ }
+
+ virtual void SAL_CALL disposing() override
+ {
+ stop();
+ cppu::WeakComponentImplHelperBase::disposing();
+ }
+
+ virtual void SAL_CALL disposing(const css::lang::EventObject& rEvent) override
+ {
+ const bool bShutDown = (rEvent.Source == m_xDesktop);
+ if (bShutDown)
+ stop();
+ }
+ };
+
+ rtl::Reference<CloseVetoButTerminateListener> m_xCloseVetoButTerminateListener;
+
+ public:
+ OCalcConnection(ODriver* _pDriver);
+ virtual ~OCalcConnection() override;
+
+ virtual void construct(const OUString& _rUrl,
+ const css::uno::Sequence< css::beans::PropertyValue >& _rInfo ) override;
+
+ // XServiceInfo
+ DECLARE_SERVICE_INFO();
+
+ // OComponentHelper
+ virtual void SAL_CALL disposing() override;
+
+ // XConnection
+ virtual css::uno::Reference< css::sdbc::XDatabaseMetaData > SAL_CALL getMetaData( ) override;
+ virtual css::uno::Reference< css::sdbcx::XTablesSupplier > createCatalog() override;
+ virtual css::uno::Reference< css::sdbc::XStatement > SAL_CALL createStatement( ) override;
+ virtual css::uno::Reference< css::sdbc::XPreparedStatement > SAL_CALL prepareStatement( const OUString& sql ) override;
+ virtual css::uno::Reference< css::sdbc::XPreparedStatement > SAL_CALL prepareCall( const OUString& sql ) override;
+
+ // no interface methods
+ css::uno::Reference< css::sheet::XSpreadsheetDocument> const & acquireDoc();
+ void releaseDoc();
+
+ class ODocHolder
+ {
+ OCalcConnection* m_pConnection;
+ css::uno::Reference< css::sheet::XSpreadsheetDocument> m_xDoc;
+ public:
+ ODocHolder(OCalcConnection* _pConnection) : m_pConnection(_pConnection)
+ {
+ m_xDoc = m_pConnection->acquireDoc();
+ }
+ ~ODocHolder()
+ {
+ m_xDoc.clear();
+ m_pConnection->releaseDoc();
+ }
+ const css::uno::Reference< css::sheet::XSpreadsheetDocument>& getDoc() const { return m_xDoc; }
+ };
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/calc/CDatabaseMetaData.hxx b/connectivity/source/inc/calc/CDatabaseMetaData.hxx
new file mode 100644
index 0000000000..61f9f6aa7e
--- /dev/null
+++ b/connectivity/source/inc/calc/CDatabaseMetaData.hxx
@@ -0,0 +1,42 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <component/CDatabaseMetaData.hxx>
+
+namespace connectivity::calc
+ {
+
+ //************ Class: java.sql.DatabaseMetaDataDate
+
+
+ class OCalcDatabaseMetaData : public component::OComponentDatabaseMetaData
+ {
+ virtual OUString SAL_CALL getURL( ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getTables( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& tableNamePattern, const css::uno::Sequence< OUString >& types ) override;
+ protected:
+ virtual ~OCalcDatabaseMetaData() override;
+ public:
+ OCalcDatabaseMetaData(file::OConnection* _pCon);
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/calc/CDriver.hxx b/connectivity/source/inc/calc/CDriver.hxx
new file mode 100644
index 0000000000..99200d23ee
--- /dev/null
+++ b/connectivity/source/inc/calc/CDriver.hxx
@@ -0,0 +1,51 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <file/FDriver.hxx>
+
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+
+namespace connectivity::calc
+ {
+ /// @throws css::uno::Exception
+ css::uno::Reference< css::uno::XInterface >
+ ODriver_CreateInstance(const css::uno::Reference< css::lang::XMultiServiceFactory >& _rxFactory);
+
+ class ODriver : public file::OFileDriver
+ {
+ public:
+ ODriver(const css::uno::Reference<
+ css::uno::XComponentContext >& _rxContext) :
+ file::OFileDriver(_rxContext) {}
+
+ OUString SAL_CALL getImplementationName( ) override;
+
+ // XDriver
+ virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL
+ connect( const OUString& url, const css::uno::Sequence<
+ css::beans::PropertyValue >& info ) override;
+ virtual sal_Bool SAL_CALL acceptsURL( const OUString& url ) override;
+ virtual css::uno::Sequence< css::sdbc::DriverPropertyInfo > SAL_CALL getPropertyInfo( const OUString& url, const css::uno::Sequence< css::beans::PropertyValue >& info ) override;
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/calc/CTable.hxx b/connectivity/source/inc/calc/CTable.hxx
new file mode 100644
index 0000000000..b4751fd876
--- /dev/null
+++ b/connectivity/source/inc/calc/CTable.hxx
@@ -0,0 +1,72 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <component/CTable.hxx>
+#include <tools/date.hxx>
+
+namespace com::sun::star::sheet {
+ class XSpreadsheet;
+}
+
+namespace com::sun::star::util {
+ class XNumberFormats;
+}
+
+
+namespace connectivity::calc
+ {
+ typedef component::OComponentTable OCalcTable_BASE;
+ class OCalcConnection;
+
+ class OCalcTable : public OCalcTable_BASE
+ {
+ private:
+ std::vector<sal_Int32> m_aTypes; // holds all type for columns just to avoid to ask the propertyset
+ css::uno::Reference< css::sheet::XSpreadsheet > m_xSheet;
+ OCalcConnection* m_pCalcConnection;
+ sal_Int32 m_nStartCol;
+ sal_Int32 m_nStartRow;
+ sal_Int32 m_nDataCols;
+ bool m_bHasHeaders;
+ css::uno::Reference< css::util::XNumberFormats > m_xFormats;
+ ::Date m_aNullDate;
+
+ void fillColumns();
+
+ public:
+ OCalcTable( sdbcx::OCollection* _pTables,OCalcConnection* _pConnection,
+ const OUString& Name,
+ const OUString& Type,
+ const OUString& Description = OUString(),
+ const OUString& SchemaName = OUString(),
+ const OUString& CatalogName = OUString()
+ );
+
+ virtual bool fetchRow(OValueRefRow& _rRow, const OSQLColumns& _rCols, bool bRetrieveData) override;
+
+ virtual void SAL_CALL disposing() override;
+
+ void construct() override;
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/calc/CTables.hxx b/connectivity/source/inc/calc/CTables.hxx
new file mode 100644
index 0000000000..0b88592a2e
--- /dev/null
+++ b/connectivity/source/inc/calc/CTables.hxx
@@ -0,0 +1,40 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <file/FTables.hxx>
+
+namespace connectivity::calc
+ {
+ typedef file::OTables OCalcTables_BASE;
+
+ class OCalcTables : public OCalcTables_BASE
+ {
+ protected:
+ virtual sdbcx::ObjectType createObject(const OUString& _rName) override;
+ public:
+ OCalcTables(const css::uno::Reference< css::sdbc::XDatabaseMetaData >& _rMetaData,::cppu::OWeakObject& _rParent, ::osl::Mutex& _rMutex,
+ const ::std::vector< OUString> &_rVector) : OCalcTables_BASE(_rMetaData,_rParent,_rMutex,_rVector)
+ {}
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/component/CColumns.hxx b/connectivity/source/inc/component/CColumns.hxx
new file mode 100644
index 0000000000..a63cae4bde
--- /dev/null
+++ b/connectivity/source/inc/component/CColumns.hxx
@@ -0,0 +1,42 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <file/FColumns.hxx>
+
+namespace connectivity::component
+ {
+ /// Columns implementation for Writer tables and Calc sheets.
+ class OComponentColumns : public file::OColumns
+ {
+ protected:
+ virtual sdbcx::ObjectType createObject(const OUString& _rName) override;
+ public:
+ OComponentColumns(file::OFileTable* _pTable,
+ ::osl::Mutex& _rMutex,
+ const ::std::vector< OUString> &_rVector
+ ) : file::OColumns(_pTable,_rMutex,_rVector)
+ {}
+
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/component/CDatabaseMetaData.hxx b/connectivity/source/inc/component/CDatabaseMetaData.hxx
new file mode 100644
index 0000000000..c4721ecadb
--- /dev/null
+++ b/connectivity/source/inc/component/CDatabaseMetaData.hxx
@@ -0,0 +1,47 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <file/FDatabaseMetaData.hxx>
+
+namespace connectivity::component
+ {
+
+ //************ Class: java.sql.DatabaseMetaDataDate
+
+
+ class OOO_DLLPUBLIC_FILE OComponentDatabaseMetaData : public file::ODatabaseMetaData
+ {
+ virtual css::uno::Reference< css::sdbc::XResultSet > impl_getTypeInfo_throw() override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getColumns( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& tableNamePattern, const OUString& columnNamePattern ) override;
+ virtual sal_Int32 SAL_CALL getMaxBinaryLiteralLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxCharLiteralLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxColumnNameLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxColumnsInIndex( ) override;
+ virtual sal_Int32 SAL_CALL getMaxColumnsInTable( ) override;
+ protected:
+ virtual ~OComponentDatabaseMetaData() override;
+ public:
+ OComponentDatabaseMetaData(file::OConnection* _pCon);
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/component/CPreparedStatement.hxx b/connectivity/source/inc/component/CPreparedStatement.hxx
new file mode 100644
index 0000000000..d39a3edad1
--- /dev/null
+++ b/connectivity/source/inc/component/CPreparedStatement.hxx
@@ -0,0 +1,39 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <file/FPreparedStatement.hxx>
+
+namespace connectivity::component
+ {
+ class OConnection;
+ /// Prepared statement implementation for Writer tables and Calc sheets.
+ class OOO_DLLPUBLIC_FILE OComponentPreparedStatement : public file::OPreparedStatement
+ {
+ protected:
+ virtual rtl::Reference<file::OResultSet> createResultSet() override;
+ public:
+ OComponentPreparedStatement( file::OConnection* _pConnection) : file::OPreparedStatement( _pConnection){}
+ DECLARE_SERVICE_INFO();
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/component/CResultSet.hxx b/connectivity/source/inc/component/CResultSet.hxx
new file mode 100644
index 0000000000..4874f22151
--- /dev/null
+++ b/connectivity/source/inc/component/CResultSet.hxx
@@ -0,0 +1,79 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <file/FResultSet.hxx>
+#include <com/sun/star/sdbcx/XRowLocate.hpp>
+#include <com/sun/star/sdbcx/XDeleteRows.hpp>
+#include <cppuhelper/implbase2.hxx>
+
+namespace connectivity::component
+ {
+ class OComponentResultSet;
+ // these typedef's are only necessary for the compiler
+ typedef ::cppu::ImplHelper2< css::sdbcx::XRowLocate,
+ css::sdbcx::XDeleteRows> OComponentResultSet_BASE;
+ typedef file::OResultSet OComponentResultSet_BASE2;
+ typedef ::comphelper::OPropertyArrayUsageHelper<OComponentResultSet> OComponentResultSet_BASE3;
+
+
+ /// ResultSet implementation for Writer tables and Calc sheets.
+ class OComponentResultSet : public OComponentResultSet_BASE2,
+ public OComponentResultSet_BASE,
+ public OComponentResultSet_BASE3
+ {
+ bool m_bBookmarkable;
+ protected:
+ // OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper() const override;
+ // OPropertySetHelper
+ virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override;
+ virtual bool fillIndexValues(const css::uno::Reference< css::sdbcx::XColumnsSupplier> &_xIndex) override;
+ public:
+ DECLARE_SERVICE_INFO();
+
+ OComponentResultSet( file::OStatement_Base* pStmt,connectivity::OSQLParseTreeIterator& _aSQLIterator);
+
+ private:
+ // XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+ //XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override;
+ // XPropertySet
+ virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override;
+
+ // XRowLocate
+ virtual css::uno::Any SAL_CALL getBookmark( ) override;
+ virtual sal_Bool SAL_CALL moveToBookmark( const css::uno::Any& bookmark ) override;
+ virtual sal_Bool SAL_CALL moveRelativeToBookmark( const css::uno::Any& bookmark, sal_Int32 rows ) override;
+ virtual sal_Int32 SAL_CALL compareBookmarks( const css::uno::Any& first, const css::uno::Any& second ) override;
+ virtual sal_Bool SAL_CALL hasOrderedBookmarks( ) override;
+ virtual sal_Int32 SAL_CALL hashBookmark( const css::uno::Any& bookmark ) override;
+ // XDeleteRows
+ virtual css::uno::Sequence< sal_Int32 > SAL_CALL deleteRows( const css::uno::Sequence< css::uno::Any >& rows ) override;
+
+ virtual bool isRowDeleted() const override { return false; }
+
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/component/CStatement.hxx b/connectivity/source/inc/component/CStatement.hxx
new file mode 100644
index 0000000000..10346e7c85
--- /dev/null
+++ b/connectivity/source/inc/component/CStatement.hxx
@@ -0,0 +1,39 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <file/FStatement.hxx>
+
+namespace connectivity::component
+ {
+ class OConnection;
+ /// Statement implementation for Writer tables and Calc sheets.
+ class OOO_DLLPUBLIC_FILE OComponentStatement : public file::OStatement
+ {
+ protected:
+ virtual rtl::Reference<file::OResultSet> createResultSet() override;
+ public:
+ OComponentStatement( file::OConnection* _pConnection) : file::OStatement( _pConnection){}
+ DECLARE_SERVICE_INFO();
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/component/CTable.hxx b/connectivity/source/inc/component/CTable.hxx
new file mode 100644
index 0000000000..3ace6f922a
--- /dev/null
+++ b/connectivity/source/inc/component/CTable.hxx
@@ -0,0 +1,66 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <file/FTable.hxx>
+
+namespace com::sun::star::sheet {
+ class XSpreadsheet;
+}
+
+namespace com::sun::star::util {
+ class XNumberFormats;
+}
+
+
+namespace connectivity::component
+ {
+ typedef file::OFileTable OComponentTable_BASE;
+
+ /// Shared Table base class for Writer tables and Calc sheets.
+ class OOO_DLLPUBLIC_FILE OComponentTable : public OComponentTable_BASE
+ {
+ protected:
+ sal_Int32 m_nDataRows;
+
+ virtual void FileClose() override;
+ public:
+ OComponentTable( sdbcx::OCollection* _pTables,file::OConnection* _pConnection,
+ const OUString& Name,
+ const OUString& Type,
+ const OUString& Description,
+ const OUString& SchemaName,
+ const OUString& CatalogName
+ );
+
+ virtual void refreshColumns() override;
+ virtual void refreshIndexes() override;
+
+ virtual sal_Int32 getCurrentLastPos() const override;
+ virtual bool seekRow(IResultSetHelper::Movement eCursorPosition, sal_Int32 nOffset, sal_Int32& nCurPos) override;
+
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ //XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override;
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/dbase/DCatalog.hxx b/connectivity/source/inc/dbase/DCatalog.hxx
new file mode 100644
index 0000000000..f8954d0122
--- /dev/null
+++ b/connectivity/source/inc/dbase/DCatalog.hxx
@@ -0,0 +1,38 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <file/FCatalog.hxx>
+
+namespace connectivity::dbase
+ {
+ class ODbaseConnection;
+ class ODbaseCatalog : public file::OFileCatalog
+ {
+ public:
+ virtual void refreshTables() override;
+
+ public:
+ ODbaseCatalog(ODbaseConnection* _pCon);
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/dbase/DColumns.hxx b/connectivity/source/inc/dbase/DColumns.hxx
new file mode 100644
index 0000000000..dbbbbec90a
--- /dev/null
+++ b/connectivity/source/inc/dbase/DColumns.hxx
@@ -0,0 +1,43 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <file/FColumns.hxx>
+
+namespace connectivity::dbase
+ {
+ class ODbaseColumns : public file::OColumns
+ {
+ protected:
+ virtual sdbcx::ObjectType createObject(const OUString& _rName) override;
+ virtual void impl_refresh() override;
+ virtual css::uno::Reference< css::beans::XPropertySet > createDescriptor() override;
+ virtual sdbcx::ObjectType appendObject( const OUString& _rForName, const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override;
+ virtual void dropObject(sal_Int32 _nPos, const OUString& _sElementName) override;
+ public:
+ ODbaseColumns(file::OFileTable* _pTable,
+ ::osl::Mutex& _rMutex,
+ const ::std::vector< OUString> &_rVector
+ ) : file::OColumns(_pTable,_rMutex,_rVector)
+ {}
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/dbase/DConnection.hxx b/connectivity/source/inc/dbase/DConnection.hxx
new file mode 100644
index 0000000000..864e9a22c8
--- /dev/null
+++ b/connectivity/source/inc/dbase/DConnection.hxx
@@ -0,0 +1,46 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <file/FConnection.hxx>
+
+namespace connectivity::dbase
+ {
+ class ODriver;
+ class ODbaseConnection : public file::OConnection
+ {
+ protected:
+ virtual ~ODbaseConnection() override;
+ public:
+ ODbaseConnection(ODriver* _pDriver);
+ // XServiceInfo
+ DECLARE_SERVICE_INFO();
+
+ // XConnection
+ virtual css::uno::Reference< css::sdbc::XDatabaseMetaData > SAL_CALL getMetaData( ) override;
+ virtual css::uno::Reference< css::sdbcx::XTablesSupplier > createCatalog() override;
+ virtual css::uno::Reference< css::sdbc::XStatement > SAL_CALL createStatement( ) override;
+ virtual css::uno::Reference< css::sdbc::XPreparedStatement > SAL_CALL prepareStatement( const OUString& sql ) override;
+ virtual css::uno::Reference< css::sdbc::XPreparedStatement > SAL_CALL prepareCall( const OUString& sql ) override;
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/dbase/DDatabaseMetaData.hxx b/connectivity/source/inc/dbase/DDatabaseMetaData.hxx
new file mode 100644
index 0000000000..fed3fcc70e
--- /dev/null
+++ b/connectivity/source/inc/dbase/DDatabaseMetaData.hxx
@@ -0,0 +1,57 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <file/FDatabaseMetaData.hxx>
+
+namespace connectivity::dbase
+ {
+
+ //************ Class: java.sql.DatabaseMetaDataDate
+
+
+ class ODbaseDatabaseMetaData : public file::ODatabaseMetaData
+ {
+ virtual css::uno::Reference< css::sdbc::XResultSet > impl_getTypeInfo_throw() override;
+ virtual sal_Bool SAL_CALL isReadOnly( ) override;
+ virtual OUString SAL_CALL getURL( ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getColumns( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& tableNamePattern, const OUString& columnNamePattern ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getIndexInfo( const css::uno::Any& catalog, const OUString& schema, const OUString& table, sal_Bool unique, sal_Bool approximate ) override;
+
+ virtual sal_Int32 SAL_CALL getMaxBinaryLiteralLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxCharLiteralLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxColumnNameLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxColumnsInIndex( ) override;
+ virtual sal_Int32 SAL_CALL getMaxColumnsInTable( ) override;
+
+ virtual sal_Bool SAL_CALL supportsAlterTableWithAddColumn( ) override;
+ virtual sal_Bool SAL_CALL supportsAlterTableWithDropColumn( ) override;
+
+ virtual bool impl_storesMixedCaseQuotedIdentifiers_throw( ) override;
+ virtual bool impl_supportsMixedCaseQuotedIdentifiers_throw( ) override;
+ protected:
+ virtual ~ODbaseDatabaseMetaData() override;
+ public:
+ ODbaseDatabaseMetaData(file::OConnection* _pCon);
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/dbase/DDriver.hxx b/connectivity/source/inc/dbase/DDriver.hxx
new file mode 100644
index 0000000000..310f9b1dc8
--- /dev/null
+++ b/connectivity/source/inc/dbase/DDriver.hxx
@@ -0,0 +1,46 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <connectivity/CommonTools.hxx>
+#include <file/FDriver.hxx>
+
+namespace connectivity::dbase
+ {
+ /// @throws css::uno::Exception
+ css::uno::Reference< css::uno::XInterface > ODriver_CreateInstance(const css::uno::Reference< css::lang::XMultiServiceFactory >& _rxFactory);
+
+ class ODriver : public file::OFileDriver
+ {
+ public:
+ ODriver(const css::uno::Reference< css::uno::XComponentContext >& _rxContext) : file::OFileDriver(_rxContext){}
+
+ OUString SAL_CALL getImplementationName( ) override;
+
+ // XDriver
+ virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL connect( const OUString& url, const css::uno::Sequence< css::beans::PropertyValue >& info ) override;
+ virtual sal_Bool SAL_CALL acceptsURL( const OUString& url ) override;
+ virtual css::uno::Sequence< css::sdbc::DriverPropertyInfo > SAL_CALL getPropertyInfo( const OUString& url, const css::uno::Sequence< css::beans::PropertyValue >& info ) override;
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/dbase/DIndex.hxx b/connectivity/source/inc/dbase/DIndex.hxx
new file mode 100644
index 0000000000..3cc7da9ad1
--- /dev/null
+++ b/connectivity/source/inc/dbase/DIndex.hxx
@@ -0,0 +1,135 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sdbcx/VIndex.hxx>
+#include <dbase/DTable.hxx>
+#include <dbase/dindexnode.hxx>
+
+inline constexpr OString dBASE_III_GROUP = "dBase III"_ostr;
+
+namespace connectivity::dbase
+ {
+ class OIndexIterator;
+ class ONDXKey;
+
+ typedef sdbcx::OIndex ODbaseIndex_BASE;
+
+ class ODbaseIndex : public ODbaseIndex_BASE
+ {
+ friend SvStream& WriteODbaseIndex(SvStream &rStream, const ODbaseIndex&);
+ friend SvStream& operator >> (SvStream &rStream, ODbaseIndex&);
+
+ friend class ONDXNode;
+ friend class ONDXPage;
+ friend class ONDXPagePtr;
+ friend class OIndexIterator;
+
+ public:
+
+ // Header struct - stays in memory
+
+ struct NDXHeader
+ {
+ sal_uInt32 db_rootpage; /* Rootpage position */
+ sal_uInt32 db_pagecount; /* Page count */
+ sal_uInt8 db_free[4]; /* Reserved */
+ sal_uInt16 db_keylen; /* Key length */
+ sal_uInt16 db_maxkeys; /* Maximum number of keys per page */
+ sal_uInt16 db_keytype; /* Type of key:
+ 0 = Text
+ 1 = Numerical */
+ sal_uInt16 db_keyrec; /* Length of an index record
+ RecordNumber + keylen */
+ sal_uInt8 db_free1[3]; /* Reserved */
+ sal_uInt8 db_unique; /* Unique */
+ char db_name[488]; /* index_name (field name) */
+ };
+
+ private:
+ std::unique_ptr<SvStream> m_pFileStream; // Stream to read/write the index
+ NDXHeader m_aHeader = {};
+ std::vector<ONDXPage*>
+ m_aCollector; // Pool of obsolete pages
+ ONDXPagePtr m_aRoot, // Root of the B+ tree
+ m_aCurLeaf; // Current leaf
+ sal_uInt16 m_nCurNode; // Position of the current node
+
+ sal_uInt32 m_nPageCount,
+ m_nRootPage;
+
+ ODbaseTable* m_pTable;
+ bool m_bUseCollector : 1; // Use the Garbage Collector
+
+ OUString getCompletePath() const;
+ void closeImpl();
+ // Closes and kills the index file and throws an error
+ void impl_killFileAndthrowError_throw(TranslateId pErrorId, const OUString& _sFile);
+ protected:
+ virtual ~ODbaseIndex() override;
+ public:
+ ODbaseIndex(ODbaseTable* _pTable);
+ ODbaseIndex(ODbaseTable* _pTable,const NDXHeader& _aHeader,const OUString& Name);
+
+ void openIndexFile();
+ virtual void refreshColumns() override;
+
+ const ODbaseTable* getTable() const { return m_pTable; }
+ const NDXHeader& getHeader() const { return m_aHeader; }
+ std::unique_ptr<OIndexIterator> createIterator();
+
+ void SetRootPos(sal_uInt32 nPos) {m_nRootPage = nPos;}
+ void SetPageCount(sal_uInt32 nCount) {m_nPageCount = nCount;}
+
+ sal_uInt32 GetPageCount() const {return m_nPageCount;}
+
+ sal_uInt16 GetMaxNodes() const {return m_aHeader.db_maxkeys;}
+
+ bool Insert(sal_uInt32 nRec, const ORowSetValue& rValue);
+ bool Update(sal_uInt32 nRec, const ORowSetValue&, const ORowSetValue&);
+ bool Delete(sal_uInt32 nRec, const ORowSetValue& rValue);
+ bool Find(sal_uInt32 nRec, const ORowSetValue& rValue);
+
+ void createINFEntry();
+ void CreateImpl();
+ void DropImpl();
+
+ DECLARE_SERVICE_INFO();
+ protected:
+
+ ONDXPage* CreatePage(sal_uInt32 nPagePos, ONDXPage* pParent = nullptr, bool bLoad = false);
+ void Collect(ONDXPage*);
+ ONDXPagePtr const & getRoot();
+
+ bool isUnique() const { return m_IsUnique; }
+ bool UseCollector() const {return m_bUseCollector;}
+ // Tree operations
+ void Release(bool bSave = true);
+ bool ConvertToKey(ONDXKey* rKey, sal_uInt32 nRec, const ORowSetValue& rValue);
+ };
+
+ SvStream& WriteODbaseIndex(SvStream &rStream, const ODbaseIndex&);
+ SvStream& operator >> (SvStream &rStream, ODbaseIndex&);
+
+ void ReadHeader(SvStream & rStream, ODbaseIndex::NDXHeader & rHeader);
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/dbase/DIndexColumns.hxx b/connectivity/source/inc/dbase/DIndexColumns.hxx
new file mode 100644
index 0000000000..8f7a895b95
--- /dev/null
+++ b/connectivity/source/inc/dbase/DIndexColumns.hxx
@@ -0,0 +1,49 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <connectivity/sdbcx/VCollection.hxx>
+#include <dbase/DIndex.hxx>
+#include <dbase/DTable.hxx>
+
+namespace connectivity::dbase
+ {
+ class ODbaseIndexColumns : public sdbcx::OCollection
+ {
+ ODbaseIndex* m_pIndex;
+ protected:
+ virtual sdbcx::ObjectType createObject(const OUString& _rName) override;
+ virtual void impl_refresh() override;
+ virtual css::uno::Reference< css::beans::XPropertySet > createDescriptor() override;
+ virtual sdbcx::ObjectType appendObject( const OUString& _rForName, const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override;
+ public:
+ ODbaseIndexColumns( ODbaseIndex* _pIndex,
+ ::osl::Mutex& _rMutex,
+ const ::std::vector< OUString> &_rVector)
+ : sdbcx::OCollection(*_pIndex,_pIndex->getTable()->getConnection()->getMetaData()->supportsMixedCaseQuotedIdentifiers(),_rMutex,_rVector)
+ , m_pIndex(_pIndex)
+ {}
+
+ };
+
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/dbase/DIndexIter.hxx b/connectivity/source/inc/dbase/DIndexIter.hxx
new file mode 100644
index 0000000000..2de327be11
--- /dev/null
+++ b/connectivity/source/inc/dbase/DIndexIter.hxx
@@ -0,0 +1,67 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <file/fcode.hxx>
+#include <dbase/DIndex.hxx>
+#include <dbase/dindexnode.hxx>
+
+namespace connectivity::dbase
+ {
+
+ // IndexIterator
+
+ class OIndexIterator final
+ {
+ file::OBoolOperator* m_pOperator;
+ const file::OOperand* m_pOperand;
+ rtl::Reference<ODbaseIndex> m_xIndex;
+ ONDXPagePtr m_aRoot,
+ m_aCurLeaf;
+ sal_uInt16 m_nCurNode;
+
+ sal_uInt32 Find(bool bFirst);
+ sal_uInt32 GetCompare(bool bFirst);
+ sal_uInt32 GetLike(bool bFirst);
+ sal_uInt32 GetNull(bool bFirst);
+ sal_uInt32 GetNotNull(bool bFirst);
+
+ ONDXKey* GetFirstKey(ONDXPage* pPage,
+ const file::OOperand& rKey);
+ ONDXKey* GetNextKey();
+
+ public:
+ OIndexIterator(ODbaseIndex* pInd)
+ :m_pOperator(nullptr)
+ ,m_pOperand(nullptr)
+ ,m_xIndex(pInd)
+ ,m_nCurNode(NODE_NOTFOUND)
+ {
+ }
+
+ ~OIndexIterator();
+ sal_uInt32 First();
+ sal_uInt32 Next();
+
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/dbase/DIndexes.hxx b/connectivity/source/inc/dbase/DIndexes.hxx
new file mode 100644
index 0000000000..a5b1c27e67
--- /dev/null
+++ b/connectivity/source/inc/dbase/DIndexes.hxx
@@ -0,0 +1,50 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <connectivity/sdbcx/VCollection.hxx>
+#include <dbase/DTable.hxx>
+
+namespace connectivity::dbase
+ {
+ class ODbaseTable;
+
+ typedef sdbcx::OCollection ODbaseIndexes_BASE;
+
+ class ODbaseIndexes : public ODbaseIndexes_BASE
+ {
+ ODbaseTable* m_pTable;
+ protected:
+ virtual sdbcx::ObjectType createObject(const OUString& _rName) override;
+ virtual void impl_refresh() override;
+ virtual css::uno::Reference< css::beans::XPropertySet > createDescriptor() override;
+ virtual sdbcx::ObjectType appendObject( const OUString& _rForName, const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override;
+ virtual void dropObject(sal_Int32 _nPos, const OUString& _sElementName) override;
+ public:
+ ODbaseIndexes(ODbaseTable* _pTable, ::osl::Mutex& _rMutex,
+ const ::std::vector< OUString> &_rVector) : ODbaseIndexes_BASE(*_pTable,_pTable->getConnection()->getMetaData()->supportsMixedCaseQuotedIdentifiers(),_rMutex,_rVector)
+ , m_pTable(_pTable)
+ {}
+
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/dbase/DPreparedStatement.hxx b/connectivity/source/inc/dbase/DPreparedStatement.hxx
new file mode 100644
index 0000000000..a2a792f623
--- /dev/null
+++ b/connectivity/source/inc/dbase/DPreparedStatement.hxx
@@ -0,0 +1,38 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <file/FPreparedStatement.hxx>
+
+namespace connectivity::dbase
+ {
+ class OConnection;
+ class ODbasePreparedStatement : public file::OPreparedStatement
+ {
+ protected:
+ virtual rtl::Reference<file::OResultSet> createResultSet() override;
+ public:
+ ODbasePreparedStatement( file::OConnection* _pConnection) : file::OPreparedStatement( _pConnection){}
+ DECLARE_SERVICE_INFO();
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/dbase/DResultSet.hxx b/connectivity/source/inc/dbase/DResultSet.hxx
new file mode 100644
index 0000000000..106a63cbb8
--- /dev/null
+++ b/connectivity/source/inc/dbase/DResultSet.hxx
@@ -0,0 +1,78 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <file/FResultSet.hxx>
+#include <com/sun/star/sdbcx/XRowLocate.hpp>
+#include <com/sun/star/sdbcx/XDeleteRows.hpp>
+#include <cppuhelper/implbase2.hxx>
+
+namespace connectivity::dbase
+ {
+ class ODbaseResultSet;
+ // these typedef's are only necessary for the compiler
+ typedef ::cppu::ImplHelper2< css::sdbcx::XRowLocate,
+ css::sdbcx::XDeleteRows> ODbaseResultSet_BASE;
+ typedef file::OResultSet ODbaseResultSet_BASE2;
+ typedef ::comphelper::OPropertyArrayUsageHelper<ODbaseResultSet> ODbaseResultSet_BASE3;
+
+
+ class ODbaseResultSet : public ODbaseResultSet_BASE2,
+ public ODbaseResultSet_BASE,
+ public ODbaseResultSet_BASE3
+ {
+ bool m_bBookmarkable;
+ protected:
+ // OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper() const override;
+ // OPropertySetHelper
+ virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override;
+ virtual bool fillIndexValues(const css::uno::Reference< css::sdbcx::XColumnsSupplier> &_xIndex) override;
+ public:
+ DECLARE_SERVICE_INFO();
+
+ ODbaseResultSet( file::OStatement_Base* pStmt,connectivity::OSQLParseTreeIterator& _aSQLIterator);
+
+ // XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+ //XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override;
+ // XPropertySet
+ virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override;
+
+ // XRowLocate
+ virtual css::uno::Any SAL_CALL getBookmark( ) override;
+ virtual sal_Bool SAL_CALL moveToBookmark( const css::uno::Any& bookmark ) override;
+ virtual sal_Bool SAL_CALL moveRelativeToBookmark( const css::uno::Any& bookmark, sal_Int32 rows ) override;
+ virtual sal_Int32 SAL_CALL compareBookmarks( const css::uno::Any& first, const css::uno::Any& second ) override;
+ virtual sal_Bool SAL_CALL hasOrderedBookmarks( ) override;
+ virtual sal_Int32 SAL_CALL hashBookmark( const css::uno::Any& bookmark ) override;
+ // XDeleteRows
+ virtual css::uno::Sequence< sal_Int32 > SAL_CALL deleteRows( const css::uno::Sequence< css::uno::Any >& rows ) override;
+
+ // own methods
+ sal_Int32 getCurrentFilePos() const;
+
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/dbase/DStatement.hxx b/connectivity/source/inc/dbase/DStatement.hxx
new file mode 100644
index 0000000000..cb4b1d8e4a
--- /dev/null
+++ b/connectivity/source/inc/dbase/DStatement.hxx
@@ -0,0 +1,38 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <file/FStatement.hxx>
+
+namespace connectivity::dbase
+ {
+ class OConnection;
+ class ODbaseStatement : public file::OStatement
+ {
+ protected:
+ virtual rtl::Reference<file::OResultSet> createResultSet() override;
+ public:
+ ODbaseStatement( file::OConnection* _pConnection) : file::OStatement( _pConnection){}
+ DECLARE_SERVICE_INFO();
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/dbase/DTable.hxx b/connectivity/source/inc/dbase/DTable.hxx
new file mode 100644
index 0000000000..bb0b6baa5f
--- /dev/null
+++ b/connectivity/source/inc/dbase/DTable.hxx
@@ -0,0 +1,191 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <file/FTable.hxx>
+#include <connectivity/CommonTools.hxx>
+#include <tools/urlobj.hxx>
+
+
+namespace connectivity::dbase
+ {
+ typedef file::OFileTable ODbaseTable_BASE;
+ class ODbaseConnection;
+
+ class ODbaseTable : public ODbaseTable_BASE
+ {
+ // The first byte of a dBase file specifies its type
+ public:
+ enum DBFType { dBaseIII = 0x03,
+ dBaseIV = 0x04,
+ dBaseV = 0x05,
+ VisualFoxPro = 0x30,
+ VisualFoxProAuto = 0x31, // Visual FoxPro with AutoIncrement field
+ dBaseFS = 0x43,
+ dBaseFSMemo = 0xB3,
+ dBaseIIIMemo = 0x83,
+ dBaseIVMemo = 0x8B,
+ dBaseIVMemoSQL = 0x8E,
+ FoxProMemo = 0xF5
+ };
+ enum DBFMemoType { MemodBaseIII = 0,
+ MemodBaseIV,
+ MemoFoxPro
+ };
+
+ private:
+ // sources: https://www.clicketyclick.dk/databases/xbase/format/dbf.html (dBASE III and 5)
+ // http://www.dbase.com/KnowledgeBase/int/db7_file_fmt.htm (dBASE 7) which is similar at least for this part
+ struct DBFHeader { // address/pos in trailer
+ DBFType type; // dBASE/xBASE type, see DBFType 00h
+ sal_uInt8 dateElems[3]; // Date of last change (YYMMDD) 01h
+ sal_uInt32 nbRecords; // Number of records 04h
+ sal_uInt16 headerLength; // 08h
+ sal_uInt16 recordLength; // Length of 1 record 10h
+ sal_uInt8 trailer[20];
+ // this last field contains these data:
+ // - reserved:2 bytes:should be filled with 0 12h/0
+ // - incomplete transaction:1 byte:dBASE IV 14h/2
+ // 00h Transaction ended (or rolled back)
+ // 01h Transaction started
+ // - encryptionFlag:1 byte: dBASE IV 15h/3
+ // 00h not encrypted
+ // 01h for encrypted
+ // - freeRecordThread:4 bytes:reserved for LAN only 16h/4
+ // - multiUserdBASE:8 bytes:reserved for multi-user dBASE (dBASE III+) 20h/8
+ // - MDXFlag:1 byte:dBASE IV 28h/16
+ // 0x01 if a production .MDX file exists for this table
+ // 0x00 if no .MDX file exists
+ // - languageDriver:1 byte:codepage (from Foxpro) 29h/17
+ // - reserved:2 bytes: should be filled with 0 30h/18
+ };
+ struct DBFColumn { /* Column descriptors */
+ sal_uInt8 db_fnm[11]; /* Field name */
+ sal_uInt8 db_typ; /* Field type */
+ sal_uInt32 db_adr; /* Field address */
+ sal_uInt8 db_flng; /* Field length */
+ sal_uInt8 db_dez; /* Decimal places for N */
+ sal_uInt8 db_free2[14]; /* Reserved */
+ };
+ struct DBFMemoHeader
+ {
+ DBFMemoType db_typ; /* File type */
+ sal_uInt32 db_next; /* Next free block */
+ sal_uInt16 db_size; /* Block size: dBase 3 fixed */
+ DBFMemoHeader()
+ : db_typ(MemodBaseIII)
+ , db_next(0)
+ , db_size(0)
+ {
+ }
+ };
+
+ std::vector<sal_Int32> m_aTypes; // holds all types for columns just to avoid to ask the propertyset
+ std::vector<sal_Int32> m_aPrecisions; // same as above
+ std::vector<sal_Int32> m_aScales;
+ std::vector<sal_Int32> m_aRealFieldLengths;
+ DBFHeader m_aHeader = {};
+ DBFMemoHeader m_aMemoHeader;
+ std::unique_ptr<SvStream> m_pMemoStream;
+ rtl_TextEncoding m_eEncoding;
+
+ void alterColumn(sal_Int32 index,
+ const css::uno::Reference< css::beans::XPropertySet>& descriptor ,
+ const css::uno::Reference< css::sdbcx::XDataDescriptorFactory>& xOldColumn );
+ void readHeader();
+ void fillColumns();
+ OUString createTempFile();
+ void copyData(ODbaseTable* _pNewTable,sal_Int32 _nPos);
+ bool CreateFile(const INetURLObject& aFile, bool& bCreateMemo);
+ bool CreateMemoFile(const INetURLObject& aFile);
+ bool HasMemoFields() const;
+ void ReadMemoHeader();
+ bool ReadMemo(std::size_t nBlockNo, ORowSetValue& aVariable);
+
+ void WriteMemo(const ORowSetValue& aVariable, std::size_t& rBlockNr);
+ bool WriteBuffer();
+ bool UpdateBuffer(OValueRefVector& rRow, const OValueRefRow& pOrgRow, const css::uno::Reference< css::container::XIndexAccess>& _xCols, bool bForceAllFields);
+ css::uno::Reference< css::beans::XPropertySet> isUniqueByColumnName(sal_Int32 _nColumnPos);
+ bool AllocBuffer();
+
+ void throwInvalidDbaseFormat();
+ /// @throws css::sdbc::SQLException
+ /// @throws css::container::ElementExistException
+ /// @throws css::uno::RuntimeException
+ void renameImpl( const OUString& newName );
+ void throwInvalidColumnType(TranslateId pErrorId, const OUString& _sColumnName);
+
+ protected:
+ virtual void FileClose() override;
+// using ::connectivity::sdbcx::OTableDescriptor_BASE::rBHelper;
+
+ public:
+ virtual void refreshColumns() override;
+ virtual void refreshIndexes() override;
+
+ public:
+ ODbaseTable( sdbcx::OCollection* _pTables,ODbaseConnection* _pConnection);
+ ODbaseTable( sdbcx::OCollection* _pTables,ODbaseConnection* _pConnection,
+ const OUString& Name,
+ const OUString& Type,
+ const OUString& Description = OUString(),
+ const OUString& SchemaName = OUString(),
+ const OUString& CatalogName = OUString()
+ );
+
+ void construct() override; // can throw any exception
+
+ virtual sal_Int32 getCurrentLastPos() const override;
+ virtual bool seekRow(IResultSetHelper::Movement eCursorPosition, sal_Int32 nOffset, sal_Int32& nCurPos) override;
+ virtual bool fetchRow(OValueRefRow& _rRow,const OSQLColumns& _rCols, bool bRetrieveData) override;
+
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ //XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override;
+ virtual void SAL_CALL disposing() override;
+
+ // XAlterTable
+ virtual void SAL_CALL alterColumnByName( const OUString& colName, const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override;
+ virtual void SAL_CALL alterColumnByIndex( sal_Int32 index, const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override;
+ // XRename
+ virtual void SAL_CALL rename( const OUString& newName ) override;
+
+ bool DropImpl();
+ bool CreateImpl();
+
+
+ virtual bool InsertRow(OValueRefVector& rRow, const css::uno::Reference< css::container::XIndexAccess>& _xCols) override;
+ virtual bool DeleteRow(const OSQLColumns& _rCols) override;
+ virtual bool UpdateRow(OValueRefVector& rRow, OValueRefRow& pOrgRow,const css::uno::Reference< css::container::XIndexAccess>& _xCols) override;
+
+ virtual void addColumn(const css::uno::Reference< css::beans::XPropertySet>& descriptor) override;
+ virtual void dropColumn(sal_Int32 _nPos) override;
+
+ static OUString getEntry(file::OConnection const * _pConnection, std::u16string_view _sURL );
+ static bool Drop_Static(std::u16string_view _sUrl, bool _bHasMemoFields, sdbcx::OCollection* _pIndexes );
+
+ virtual void refreshHeader() override;
+
+ virtual css::uno::Reference< css::sdbc::XDatabaseMetaData> getMetaData() const override;
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/dbase/DTables.hxx b/connectivity/source/inc/dbase/DTables.hxx
new file mode 100644
index 0000000000..c85a1ab3cd
--- /dev/null
+++ b/connectivity/source/inc/dbase/DTables.hxx
@@ -0,0 +1,46 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <file/FTables.hxx>
+
+namespace connectivity::dbase
+ {
+ typedef file::OTables ODbaseTables_BASE;
+
+ class ODbaseTables : public ODbaseTables_BASE
+ {
+ protected:
+ virtual sdbcx::ObjectType createObject(const OUString& _rName) override;
+ virtual void impl_refresh() override;
+ virtual css::uno::Reference< css::beans::XPropertySet > createDescriptor() override;
+ virtual sdbcx::ObjectType appendObject( const OUString& _rForName, const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override;
+ virtual void dropObject(sal_Int32 _nPos, const OUString& _sElementName) override;
+ public:
+ ODbaseTables(const css::uno::Reference< css::sdbc::XDatabaseMetaData >& _rMetaData,::cppu::OWeakObject& _rParent, ::osl::Mutex& _rMutex,
+ const ::std::vector< OUString> &_rVector) : ODbaseTables_BASE(_rMetaData,_rParent,_rMutex,_rVector)
+ {}
+
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/dbase/dindexnode.hxx b/connectivity/source/inc/dbase/dindexnode.hxx
new file mode 100644
index 0000000000..85666f9e52
--- /dev/null
+++ b/connectivity/source/inc/dbase/dindexnode.hxx
@@ -0,0 +1,307 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <file/fcode.hxx>
+#include <connectivity/FValue.hxx>
+#include <memory>
+
+#define NODE_NOTFOUND 0xFFFF
+#define DINDEX_PAGE_SIZE 512
+
+class SvStream;
+
+namespace connectivity::dbase
+ {
+
+ class ONDXNode;
+ class ODbaseIndex;
+
+ // Index Key
+
+ typedef file::OOperand ONDXKey_BASE;
+ class ONDXKey : public ONDXKey_BASE
+ {
+ friend class ONDXNode;
+ sal_uInt32 nRecord; /* Record pointer */
+ ORowSetValue xValue; /* Key values */
+
+ public:
+ ONDXKey();
+ ONDXKey(ORowSetValue aVal, sal_Int32 eType, sal_uInt32 nRec);
+ ONDXKey(const OUString& aStr, sal_uInt32 nRec);
+ ONDXKey(double aVal, sal_uInt32 nRec);
+
+ inline ONDXKey(const ONDXKey& rKey);
+
+ inline ONDXKey& operator= (const ONDXKey& rKey);
+ virtual void setValue(const ORowSetValue& _rVal) override;
+
+ virtual const ORowSetValue& getValue() const override;
+
+ sal_uInt32 GetRecord() const { return nRecord; }
+ void setRecord(sal_uInt32 _nRec) { nRecord = _nRec; }
+ void ResetRecord() { nRecord = 0; }
+
+ bool operator == (const ONDXKey& rKey) const;
+ bool operator != (const ONDXKey& rKey) const;
+ bool operator < (const ONDXKey& rKey) const;
+ bool operator <= (const ONDXKey& rKey) const;
+ bool operator > (const ONDXKey& rKey) const;
+
+ static bool IsText(sal_Int32 eType);
+
+ private:
+ int Compare(const ONDXKey& rKey) const;
+ };
+
+
+ class ONDXPage;
+
+ // Index Page Pointer
+ // This is ref-count pointer class
+ class ONDXPagePtr
+ {
+ friend SvStream& WriteONDXPagePtr(SvStream &rStream, const ONDXPagePtr&);
+ friend SvStream& operator >> (SvStream &rStream, ONDXPagePtr&);
+
+ ONDXPage* mpPage;
+ sal_uInt32 nPagePos; // Position in the index file
+
+ public:
+ ONDXPagePtr();
+ ONDXPagePtr(ONDXPagePtr&& rObj) noexcept;
+ ONDXPagePtr(ONDXPagePtr const & rRef);
+ ONDXPagePtr(ONDXPage* pRefPage);
+ ~ONDXPagePtr();
+ void Clear();
+ ONDXPagePtr& operator=(ONDXPagePtr const & rRef);
+ ONDXPagePtr& operator=(ONDXPagePtr && rRef);
+ bool Is() const { return mpPage != nullptr; }
+
+ ONDXPage * operator ->() const { assert(mpPage != nullptr); return mpPage; }
+ operator ONDXPage *() const { return mpPage; }
+
+ sal_uInt32 GetPagePos() const {return nPagePos;}
+ bool HasPage() const {return nPagePos != 0;}
+ };
+
+ // Index Page
+ // This is a ref-counted class, with re-cycling
+ class ONDXPage
+ {
+ friend class ODbaseIndex;
+ friend class ONDXPagePtr;
+
+ friend SvStream& WriteONDXPage(SvStream &rStream, const ONDXPage&);
+ friend SvStream& operator >> (SvStream &rStream, ONDXPage&);
+
+ // work around a clang 3.5 optimization bug: if the bNoDelete is *first*
+ // it mis-compiles "if (--nRefCount == 0)" and never deletes any object
+ unsigned int nRefCount : 31;
+ // the only reason this is not bool is because MSVC cannot handle mixed type bitfields
+ unsigned int bNoDelete : 1;
+ sal_uInt32 nPagePos; // Position in the index file
+ bool bModified : 1;
+ sal_uInt16 nCount;
+
+ ONDXPagePtr aParent, // Parent page
+ aChild; // Pointer to the right child page
+ ODbaseIndex& rIndex;
+ std::unique_ptr<ONDXNode[]>
+ ppNodes; // Array of nodes
+
+ public:
+ // Node operations
+ sal_uInt16 Count() const {return nCount;}
+
+ bool Insert(ONDXNode& rNode, sal_uInt32 nRowsLeft = 0);
+ bool Insert(sal_uInt16 nIndex, ONDXNode& rNode);
+ bool Append(ONDXNode& rNode);
+ void Delete(sal_uInt16);
+ void Remove(sal_uInt16);
+ void Release(bool bSave = true);
+ void ReleaseFull();
+
+ // Split and merge
+ ONDXNode Split(ONDXPage& rPage);
+ void Merge(sal_uInt16 nParentNodePos, const ONDXPagePtr& xPage);
+
+ // Access operators
+ ONDXNode& operator[] (sal_uInt16 nPos);
+ const ONDXNode& operator[] (sal_uInt16 nPos) const;
+
+ bool IsRoot() const;
+ bool IsLeaf() const;
+ bool IsModified() const;
+ bool HasParent() const;
+
+ bool IsFull() const;
+
+ sal_uInt32 GetPagePos() const {return nPagePos;}
+ ONDXPagePtr& GetChild(ODbaseIndex const * pIndex = nullptr);
+
+ // Parent does not need to be reloaded
+ const ONDXPagePtr& GetParent() const;
+ ODbaseIndex& GetIndex() {return rIndex;}
+ const ODbaseIndex& GetIndex() const {return rIndex;}
+
+ // Setting the child, via reference to retain the PagePos
+ void SetChild(ONDXPagePtr aCh);
+ void SetParent(ONDXPagePtr aPa);
+
+ sal_uInt16 Search(const ONDXKey& rSearch);
+ sal_uInt16 Search(const ONDXPage* pPage);
+ void SearchAndReplace(const ONDXKey& rSearch, ONDXKey const & rReplace);
+
+ protected:
+ ONDXPage(ODbaseIndex& rIndex, sal_uInt32 nPos, ONDXPage*);
+ ~ONDXPage();
+
+ void ReleaseRef();
+ void QueryDelete();
+ void AddNextRef()
+ {
+ assert( nRefCount < (1 << 30) && "Do not add refs to dead objects" );
+ ++nRefCount;
+ }
+ void AddFirstRef()
+ {
+ assert( nRefCount < (1 << 30) && "Do not add refs to dead objects" );
+ if( bNoDelete )
+ bNoDelete = 0;
+ ++nRefCount;
+ }
+
+ void SetModified(bool bMod) {bModified = bMod;}
+ void SetPagePos(sal_uInt32 nPage) {nPagePos = nPage;}
+
+ bool Find(const ONDXKey&); // Descend recursively
+ sal_uInt16 FindPos(const ONDXKey& rKey) const;
+
+#if OSL_DEBUG_LEVEL > 1
+ void PrintPage();
+#endif
+ };
+
+ SvStream& WriteONDXPagePtr(SvStream &rStream, const ONDXPagePtr&);
+ SvStream& operator >> (SvStream &rStream, ONDXPagePtr&);
+
+ inline bool ONDXPage::IsRoot() const {return !aParent.Is();}
+ inline bool ONDXPage::IsLeaf() const {return !aChild.HasPage();}
+ inline bool ONDXPage::IsModified() const {return bModified;}
+ inline bool ONDXPage::HasParent() const {return aParent.Is();}
+ inline const ONDXPagePtr& ONDXPage::GetParent() const {return aParent;}
+
+ inline void ONDXPage::SetParent(ONDXPagePtr aPa = ONDXPagePtr())
+ {
+ aParent = aPa;
+ }
+
+ inline void ONDXPage::SetChild(ONDXPagePtr aCh = ONDXPagePtr())
+ {
+ aChild = aCh;
+ if (aChild.Is())
+ aChild->SetParent(this);
+ }
+ SvStream& operator >> (SvStream &rStream, ONDXPage& rPage);
+ SvStream& WriteONDXPage(SvStream &rStream, const ONDXPage& rPage);
+
+
+ // Index Node
+
+ class ONDXNode
+ {
+ friend class ONDXPage;
+ ONDXPagePtr aChild; /* Next page reference */
+ ONDXKey aKey;
+
+ public:
+ ONDXNode(){}
+ ONDXNode(const ONDXKey& rKey)
+ :aKey(rKey) {}
+
+ // Does the node point to a page?
+ bool HasChild() const {return aChild.HasPage();}
+ // If an index is provided, we may be able to retrieve the page
+ ONDXPagePtr& GetChild(ODbaseIndex* pIndex = nullptr, ONDXPage* = nullptr);
+
+ const ONDXKey& GetKey() const { return aKey;}
+ ONDXKey& GetKey() { return aKey;}
+
+ // Setting the child, via reference to retain the PagePos
+ void SetChild(ONDXPagePtr aCh = ONDXPagePtr(), ONDXPage* = nullptr);
+
+ void Write(SvStream &rStream, const ONDXPage& rPage) const;
+ void Read(SvStream &rStream, ODbaseIndex const &);
+ };
+
+ inline ONDXKey::ONDXKey(const ONDXKey& rKey)
+ : ONDXKey_BASE(rKey.getDBType())
+ ,nRecord(rKey.nRecord)
+ ,xValue(rKey.xValue)
+ {
+ }
+
+ inline ONDXKey& ONDXKey::operator=(const ONDXKey& rKey)
+ {
+ if(&rKey == this)
+ return *this;
+
+ xValue = rKey.xValue;
+ nRecord = rKey.nRecord;
+ m_eDBType = rKey.getDBType();
+ return *this;
+ }
+
+ inline bool ONDXKey::operator == (const ONDXKey& rKey) const
+ {
+ if(&rKey == this)
+ return true;
+ return Compare(rKey) == 0;
+ }
+ inline bool ONDXKey::operator != (const ONDXKey& rKey) const
+ {
+ return !operator== (rKey);
+ }
+ inline bool ONDXKey::operator < (const ONDXKey& rKey) const
+ {
+ return Compare(rKey) < 0;
+ }
+ inline bool ONDXKey::operator > (const ONDXKey& rKey) const
+ {
+ return Compare(rKey) > 0;
+ }
+ inline bool ONDXKey::operator <= (const ONDXKey& rKey) const
+ {
+ return !operator > (rKey);
+ }
+
+ inline void ONDXNode::SetChild(ONDXPagePtr aCh, ONDXPage* pParent)
+ {
+ aChild = aCh;
+ if (aChild.Is())
+ aChild->SetParent(pParent);
+ }
+
+}
+
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/file/FCatalog.hxx b/connectivity/source/inc/file/FCatalog.hxx
new file mode 100644
index 0000000000..2bcf82df2a
--- /dev/null
+++ b/connectivity/source/inc/file/FCatalog.hxx
@@ -0,0 +1,60 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sdbcx/VCatalog.hxx>
+
+#include <file/filedllapi.hxx>
+
+namespace connectivity::file
+ {
+ class OConnection;
+ class OOO_DLLPUBLIC_FILE SAL_NO_VTABLE OFileCatalog :
+ public connectivity::sdbcx::OCatalog
+ {
+ protected:
+ OConnection* m_pConnection;
+
+ /** builds the name which should be used to access the object later on in the collection.
+ Will only be called in fillNames.
+ @param _xRow
+ The current row from the resultset given to fillNames.
+ */
+ virtual OUString buildName( const css::uno::Reference< css::sdbc::XRow >& _xRow) override;
+
+ public:
+ virtual void refreshTables() override;
+ virtual void refreshViews() override;
+ virtual void refreshGroups() override;
+ virtual void refreshUsers() override;
+
+ public:
+ OFileCatalog(OConnection* _pCon);
+ OConnection* getConnection() { return m_pConnection; }
+
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ // ::cppu::OComponentHelper
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override;
+ virtual void SAL_CALL disposing() override;
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/file/FColumns.hxx b/connectivity/source/inc/file/FColumns.hxx
new file mode 100644
index 0000000000..f5fce16b6f
--- /dev/null
+++ b/connectivity/source/inc/file/FColumns.hxx
@@ -0,0 +1,47 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <connectivity/sdbcx/VCollection.hxx>
+#include <com/sun/star/sdbc/XDatabaseMetaData.hpp>
+#include <file/FTable.hxx>
+#include <file/filedllapi.hxx>
+
+namespace connectivity::file
+ {
+ class OOO_DLLPUBLIC_FILE OColumns : public sdbcx::OCollection
+ {
+ protected:
+ OFileTable* m_pTable;
+
+ virtual sdbcx::ObjectType createObject(const OUString& _rName) override;
+ virtual void impl_refresh() override;
+ public:
+ OColumns( OFileTable* _pTable,
+ ::osl::Mutex& _rMutex,
+ const ::std::vector< OUString> &_rVector
+ ) : sdbcx::OCollection(*_pTable,_pTable->getConnection()->getMetaData()->supportsMixedCaseQuotedIdentifiers(),_rMutex,_rVector)
+ ,m_pTable(_pTable)
+ {}
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/file/FConnection.hxx b/connectivity/source/inc/file/FConnection.hxx
new file mode 100644
index 0000000000..e6412992ab
--- /dev/null
+++ b/connectivity/source/inc/file/FConnection.hxx
@@ -0,0 +1,131 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <com/sun/star/ucb/XContent.hpp>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <connectivity/CommonTools.hxx>
+#include <rtl/ustring.hxx>
+#include <com/sun/star/sdbcx/XTablesSupplier.hpp>
+#include <com/sun/star/ucb/XDynamicResultSet.hpp>
+#include <TConnection.hxx>
+#include <file/filedllapi.hxx>
+
+namespace connectivity::file
+ {
+ class ODatabaseMetaData;
+ class OFileDriver;
+
+ class OOO_DLLPUBLIC_FILE OConnection : public connectivity::OMetaConnection
+ {
+ protected:
+
+ // Data attributes
+
+ css::uno::WeakReference< css::sdbcx::XTablesSupplier> m_xCatalog;
+
+ OUString m_aFilenameExtension;
+ OFileDriver* m_pDriver; // Pointer to the owning
+ // driver object
+ css::uno::Reference< css::ucb::XDynamicResultSet > m_xDir; // directory
+ css::uno::Reference< css::ucb::XContent> m_xContent;
+
+ bool m_bAutoCommit;
+ bool m_bReadOnly;
+ bool m_bShowDeleted;
+ bool m_bCaseSensitiveExtension;
+ bool m_bCheckSQL92;
+ bool m_bDefaultTextEncoding;
+
+
+ void throwUrlNotValid(const OUString & _rsUrl,const OUString & _rsMessage);
+
+ virtual ~OConnection() override;
+ public:
+
+ OConnection(OFileDriver* _pDriver);
+
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ /// @throws css::uno::DeploymentException
+ virtual void construct(const OUString& _rUrl, const css::uno::Sequence< css::beans::PropertyValue >& _rInfo );
+
+ // OComponentHelper
+ virtual void SAL_CALL disposing() override;
+
+ // XServiceInfo
+ DECLARE_SERVICE_INFO();
+
+ // XConnection
+ virtual css::uno::Reference< css::sdbc::XStatement > SAL_CALL createStatement( ) override;
+ virtual css::uno::Reference< css::sdbc::XPreparedStatement > SAL_CALL prepareStatement( const OUString& sql ) override;
+ virtual css::uno::Reference< css::sdbc::XPreparedStatement > SAL_CALL prepareCall( const OUString& sql ) override;
+ virtual OUString SAL_CALL nativeSQL( const OUString& sql ) override;
+ virtual void SAL_CALL setAutoCommit( sal_Bool autoCommit ) override;
+ virtual sal_Bool SAL_CALL getAutoCommit( ) override;
+ virtual void SAL_CALL commit( ) override;
+ virtual void SAL_CALL rollback( ) override;
+ virtual sal_Bool SAL_CALL isClosed( ) override final;
+ virtual css::uno::Reference< css::sdbc::XDatabaseMetaData > SAL_CALL getMetaData( ) override;
+ virtual void SAL_CALL setReadOnly( sal_Bool readOnly ) override;
+ virtual sal_Bool SAL_CALL isReadOnly( ) override;
+ virtual void SAL_CALL setCatalog( const OUString& catalog ) override;
+ virtual OUString SAL_CALL getCatalog( ) override;
+ virtual void SAL_CALL setTransactionIsolation( sal_Int32 level ) override;
+ virtual sal_Int32 SAL_CALL getTransactionIsolation( ) override;
+ virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getTypeMap( ) override;
+ virtual void SAL_CALL setTypeMap( const css::uno::Reference< css::container::XNameAccess >& typeMap ) override;
+ // XCloseable
+ virtual void SAL_CALL close( ) override final;
+ // XWarningsSupplier
+ virtual css::uno::Any SAL_CALL getWarnings( ) override;
+ virtual void SAL_CALL clearWarnings( ) override;
+ //XUnoTunnel
+ virtual sal_Int64 SAL_CALL getSomething( const css::uno::Sequence< sal_Int8 >& aIdentifier ) override;
+ static const css::uno::Sequence< sal_Int8 > & getUnoTunnelId();
+
+ // no interface methods
+ css::uno::Reference< css::ucb::XDynamicResultSet > getDir() const;
+ const css::uno::Reference< css::ucb::XContent>& getContent() const { return m_xContent; }
+ // create a catalog or return the catalog already created
+ virtual css::uno::Reference< css::sdbcx::XTablesSupplier > createCatalog();
+
+ bool matchesExtension( const OUString& _rExt ) const;
+
+ const OUString& getExtension() const { return m_aFilenameExtension; }
+ bool isCaseSensitiveExtension() const { return m_bCaseSensitiveExtension; }
+ OFileDriver* getDriver() const { return m_pDriver; }
+ bool showDeleted() const { return m_bShowDeleted; }
+ bool isCheckEnabled() const { return m_bCheckSQL92; }
+ bool isTextEncodingDefaulted() const { return m_bDefaultTextEncoding; }
+
+ public:
+ struct GrantAccess
+ {
+ friend class ODatabaseMetaData;
+ private:
+ GrantAccess() { }
+ };
+
+ void setCaseSensitiveExtension( bool _bIsCS, GrantAccess ) { m_bCaseSensitiveExtension = _bIsCS; }
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/file/FDatabaseMetaData.hxx b/connectivity/source/inc/file/FDatabaseMetaData.hxx
new file mode 100644
index 0000000000..5c766c31d1
--- /dev/null
+++ b/connectivity/source/inc/file/FDatabaseMetaData.hxx
@@ -0,0 +1,186 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <TDatabaseMetaDataBase.hxx>
+#include <file/FConnection.hxx>
+#include <file/filedllapi.hxx>
+
+namespace connectivity::file
+ {
+
+ //************ Class: ODatabaseMetaData
+
+
+ class OOO_DLLPUBLIC_FILE SAL_NO_VTABLE ODatabaseMetaData :
+ public ODatabaseMetaDataBase
+ {
+ virtual css::uno::Reference< css::sdbc::XResultSet > impl_getTypeInfo_throw() override;
+ // cached database information
+ virtual OUString impl_getIdentifierQuoteString_throw( ) override;
+ virtual bool impl_isCatalogAtStart_throw( ) override;
+ virtual OUString impl_getCatalogSeparator_throw( ) override;
+ virtual bool impl_supportsCatalogsInTableDefinitions_throw( ) override;
+ virtual bool impl_supportsSchemasInTableDefinitions_throw( ) override ;
+ virtual bool impl_supportsCatalogsInDataManipulation_throw( ) override;
+ virtual bool impl_supportsSchemasInDataManipulation_throw( ) override ;
+ virtual bool impl_supportsMixedCaseQuotedIdentifiers_throw( ) override;
+ virtual bool impl_supportsAlterTableWithAddColumn_throw( ) override;
+ virtual bool impl_supportsAlterTableWithDropColumn_throw( ) override;
+ virtual sal_Int32 impl_getMaxStatements_throw( ) override;
+ virtual sal_Int32 impl_getMaxTablesInSelect_throw( ) override;
+ virtual bool impl_storesMixedCaseQuotedIdentifiers_throw( ) override;
+ protected:
+ OConnection* m_pConnection; // I need the native class not only the interface
+ virtual ~ODatabaseMetaData() override;
+ public:
+
+ ODatabaseMetaData(OConnection* _pCon);
+ // XDatabaseMetaData
+ virtual sal_Bool SAL_CALL allProceduresAreCallable( ) override;
+ virtual sal_Bool SAL_CALL allTablesAreSelectable( ) override;
+ virtual OUString SAL_CALL getURL( ) override;
+ virtual OUString SAL_CALL getUserName( ) override;
+ virtual sal_Bool SAL_CALL isReadOnly( ) override;
+ virtual sal_Bool SAL_CALL nullsAreSortedHigh( ) override;
+ virtual sal_Bool SAL_CALL nullsAreSortedLow( ) override;
+ virtual sal_Bool SAL_CALL nullsAreSortedAtStart( ) override;
+ virtual sal_Bool SAL_CALL nullsAreSortedAtEnd( ) override;
+ virtual OUString SAL_CALL getDatabaseProductName( ) override;
+ virtual OUString SAL_CALL getDatabaseProductVersion( ) override;
+ virtual OUString SAL_CALL getDriverName( ) override;
+ virtual OUString SAL_CALL getDriverVersion( ) override;
+ virtual sal_Int32 SAL_CALL getDriverMajorVersion( ) override;
+ virtual sal_Int32 SAL_CALL getDriverMinorVersion( ) override;
+ virtual sal_Bool SAL_CALL usesLocalFiles( ) override;
+ virtual sal_Bool SAL_CALL usesLocalFilePerTable( ) override;
+ virtual sal_Bool SAL_CALL supportsMixedCaseIdentifiers( ) override;
+ virtual sal_Bool SAL_CALL storesUpperCaseIdentifiers( ) override;
+ virtual sal_Bool SAL_CALL storesLowerCaseIdentifiers( ) override;
+ virtual sal_Bool SAL_CALL storesMixedCaseIdentifiers( ) override;
+ virtual sal_Bool SAL_CALL storesUpperCaseQuotedIdentifiers( ) override;
+ virtual sal_Bool SAL_CALL storesLowerCaseQuotedIdentifiers( ) override;
+ virtual OUString SAL_CALL getSQLKeywords( ) override;
+ virtual OUString SAL_CALL getNumericFunctions( ) override;
+ virtual OUString SAL_CALL getStringFunctions( ) override;
+ virtual OUString SAL_CALL getSystemFunctions( ) override;
+ virtual OUString SAL_CALL getTimeDateFunctions( ) override;
+ virtual OUString SAL_CALL getSearchStringEscape( ) override;
+ virtual OUString SAL_CALL getExtraNameCharacters( ) override;
+ virtual sal_Bool SAL_CALL supportsColumnAliasing( ) override;
+ virtual sal_Bool SAL_CALL nullPlusNonNullIsNull( ) override;
+ virtual sal_Bool SAL_CALL supportsTypeConversion( ) override;
+ virtual sal_Bool SAL_CALL supportsConvert( sal_Int32 fromType, sal_Int32 toType ) override;
+ virtual sal_Bool SAL_CALL supportsTableCorrelationNames( ) override;
+ virtual sal_Bool SAL_CALL supportsDifferentTableCorrelationNames( ) override;
+ virtual sal_Bool SAL_CALL supportsExpressionsInOrderBy( ) override;
+ virtual sal_Bool SAL_CALL supportsOrderByUnrelated( ) override;
+ virtual sal_Bool SAL_CALL supportsGroupBy( ) override;
+ virtual sal_Bool SAL_CALL supportsGroupByUnrelated( ) override;
+ virtual sal_Bool SAL_CALL supportsGroupByBeyondSelect( ) override;
+ virtual sal_Bool SAL_CALL supportsLikeEscapeClause( ) override;
+ virtual sal_Bool SAL_CALL supportsMultipleResultSets( ) override;
+ virtual sal_Bool SAL_CALL supportsMultipleTransactions( ) override;
+ virtual sal_Bool SAL_CALL supportsNonNullableColumns( ) override;
+ virtual sal_Bool SAL_CALL supportsMinimumSQLGrammar( ) override;
+ virtual sal_Bool SAL_CALL supportsCoreSQLGrammar( ) override;
+ virtual sal_Bool SAL_CALL supportsExtendedSQLGrammar( ) override;
+ virtual sal_Bool SAL_CALL supportsANSI92EntryLevelSQL( ) override;
+ virtual sal_Bool SAL_CALL supportsANSI92IntermediateSQL( ) override;
+ virtual sal_Bool SAL_CALL supportsANSI92FullSQL( ) override;
+ virtual sal_Bool SAL_CALL supportsIntegrityEnhancementFacility( ) override;
+ virtual sal_Bool SAL_CALL supportsOuterJoins( ) override;
+ virtual sal_Bool SAL_CALL supportsFullOuterJoins( ) override;
+ virtual sal_Bool SAL_CALL supportsLimitedOuterJoins( ) override;
+ virtual OUString SAL_CALL getSchemaTerm( ) override;
+ virtual OUString SAL_CALL getProcedureTerm( ) override;
+ virtual OUString SAL_CALL getCatalogTerm( ) override;
+ virtual sal_Bool SAL_CALL supportsSchemasInProcedureCalls( ) override;
+ virtual sal_Bool SAL_CALL supportsSchemasInIndexDefinitions( ) override;
+ virtual sal_Bool SAL_CALL supportsSchemasInPrivilegeDefinitions( ) override;
+ virtual sal_Bool SAL_CALL supportsCatalogsInProcedureCalls( ) override;
+ virtual sal_Bool SAL_CALL supportsCatalogsInIndexDefinitions( ) override;
+ virtual sal_Bool SAL_CALL supportsCatalogsInPrivilegeDefinitions( ) override;
+ virtual sal_Bool SAL_CALL supportsPositionedDelete( ) override;
+ virtual sal_Bool SAL_CALL supportsPositionedUpdate( ) override;
+ virtual sal_Bool SAL_CALL supportsSelectForUpdate( ) override;
+ virtual sal_Bool SAL_CALL supportsStoredProcedures( ) override;
+ virtual sal_Bool SAL_CALL supportsSubqueriesInComparisons( ) override;
+ virtual sal_Bool SAL_CALL supportsSubqueriesInExists( ) override;
+ virtual sal_Bool SAL_CALL supportsSubqueriesInIns( ) override;
+ virtual sal_Bool SAL_CALL supportsSubqueriesInQuantifieds( ) override;
+ virtual sal_Bool SAL_CALL supportsCorrelatedSubqueries( ) override;
+ virtual sal_Bool SAL_CALL supportsUnion( ) override;
+ virtual sal_Bool SAL_CALL supportsUnionAll( ) override;
+ virtual sal_Bool SAL_CALL supportsOpenCursorsAcrossCommit( ) override;
+ virtual sal_Bool SAL_CALL supportsOpenCursorsAcrossRollback( ) override;
+ virtual sal_Bool SAL_CALL supportsOpenStatementsAcrossCommit( ) override;
+ virtual sal_Bool SAL_CALL supportsOpenStatementsAcrossRollback( ) override;
+ virtual sal_Int32 SAL_CALL getMaxBinaryLiteralLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxCharLiteralLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxColumnNameLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxColumnsInGroupBy( ) override;
+ virtual sal_Int32 SAL_CALL getMaxColumnsInIndex( ) override;
+ virtual sal_Int32 SAL_CALL getMaxColumnsInOrderBy( ) override;
+ virtual sal_Int32 SAL_CALL getMaxColumnsInSelect( ) override;
+ virtual sal_Int32 SAL_CALL getMaxColumnsInTable( ) override;
+ virtual sal_Int32 SAL_CALL getMaxConnections( ) override;
+ virtual sal_Int32 SAL_CALL getMaxCursorNameLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxIndexLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxSchemaNameLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxProcedureNameLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxCatalogNameLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxRowSize( ) override;
+ virtual sal_Bool SAL_CALL doesMaxRowSizeIncludeBlobs( ) override;
+ virtual sal_Int32 SAL_CALL getMaxStatementLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxTableNameLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxUserNameLength( ) override;
+ virtual sal_Int32 SAL_CALL getDefaultTransactionIsolation( ) override;
+ virtual sal_Bool SAL_CALL supportsTransactions( ) override;
+ virtual sal_Bool SAL_CALL supportsTransactionIsolationLevel( sal_Int32 level ) override;
+ virtual sal_Bool SAL_CALL supportsDataDefinitionAndDataManipulationTransactions( ) override;
+ virtual sal_Bool SAL_CALL supportsDataManipulationTransactionsOnly( ) override;
+ virtual sal_Bool SAL_CALL dataDefinitionCausesTransactionCommit( ) override;
+ virtual sal_Bool SAL_CALL dataDefinitionIgnoredInTransactions( ) override;
+
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getTables( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& tableNamePattern, const css::uno::Sequence< OUString >& types ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getTableTypes( ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getTablePrivileges( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& tableNamePattern ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getColumns( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& tableNamePattern, const OUString& columnNamePattern ) override;
+
+ virtual sal_Bool SAL_CALL supportsResultSetType( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL supportsResultSetConcurrency( sal_Int32 setType, sal_Int32 concurrency ) override;
+ virtual sal_Bool SAL_CALL ownUpdatesAreVisible( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL ownDeletesAreVisible( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL ownInsertsAreVisible( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL othersUpdatesAreVisible( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL othersDeletesAreVisible( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL othersInsertsAreVisible( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL updatesAreDetected( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL deletesAreDetected( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL insertsAreDetected( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL supportsBatchUpdates( ) override;
+
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getUDTs( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& typeNamePattern, const css::uno::Sequence< sal_Int32 >& types ) override;
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/file/FDateFunctions.hxx b/connectivity/source/inc/file/FDateFunctions.hxx
new file mode 100644
index 0000000000..e8eb12d0cf
--- /dev/null
+++ b/connectivity/source/inc/file/FDateFunctions.hxx
@@ -0,0 +1,228 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <file/fcode.hxx>
+
+namespace connectivity::file
+ {
+ /** DAYOFWEEK(date)
+ Returns the weekday index for date (1 = Sunday, 2 = Monday, ... 7 = Saturday). These index values correspond to the ODBC standard.
+
+ > SELECT DAYOFWEEK('1998-02-03');
+ -> 3
+ */
+ class OOp_DayOfWeek : public OUnaryOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const ORowSetValue& lhs) const override;
+ };
+
+ /** DAYOFMONTH(date)
+ Returns the day of the month for date, in the range 1 to 31:
+
+ > SELECT DAYOFMONTH('1998-02-03');
+ -> 3
+ */
+ class OOp_DayOfMonth : public OUnaryOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const ORowSetValue& lhs) const override;
+ };
+
+ /** DAYOFYEAR(date)
+ Returns the day of the year for date, in the range 1 to 366:
+
+ > SELECT DAYOFYEAR('1998-02-03');
+ -> 34
+
+ */
+ class OOp_DayOfYear : public OUnaryOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const ORowSetValue& lhs) const override;
+ };
+
+ /** MONTH(date)
+ Returns the month for date, in the range 1 to 12:
+
+ > SELECT MONTH('1998-02-03');
+ -> 2
+ */
+ class OOp_Month : public OUnaryOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const ORowSetValue& lhs) const override;
+ };
+
+ /** DAYNAME(date)
+ Returns the name of the weekday for date:
+
+ > SELECT DAYNAME('1998-02-05');
+ -> 'Thursday'
+
+ */
+ class OOp_DayName : public OUnaryOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const ORowSetValue& lhs) const override;
+ };
+
+ /** MONTHNAME(date)
+ Returns the name of the month for date:
+
+ > SELECT MONTHNAME('1998-02-05');
+ -> 'February'
+
+ */
+ class OOp_MonthName : public OUnaryOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const ORowSetValue& lhs) const override;
+ };
+
+ /** QUARTER(date)
+ Returns the quarter of the year for date, in the range 1 to 4:
+
+ > SELECT QUARTER('98-04-01');
+ -> 2
+
+ */
+ class OOp_Quarter : public OUnaryOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const ORowSetValue& lhs) const override;
+ };
+
+ /** WEEK(date)
+ WEEK(date,first)
+ With a single argument, returns the week for date, in the range 0 to 53 (yes, there may be the beginnings of a week 53), for locations where Sunday is the first day of the week. The two-argument form of WEEK() allows you to specify whether the week starts on Sunday or Monday and whether the return value should be in the range 0-53 or 1-52. Here is a table for how the second argument works:
+ Value Meaning
+ 0 Week starts on Sunday and return value is in range 0-53
+ 1 Week starts on Monday and return value is in range 0-53
+ 2 Week starts on Sunday and return value is in range 1-53
+ 3 Week starts on Monday and return value is in range 1-53 (ISO 8601)
+
+ > SELECT WEEK('1998-02-20');
+ -> 7
+ > SELECT WEEK('1998-02-20',0);
+ -> 7
+ > SELECT WEEK('1998-02-20',1);
+ -> 8
+ > SELECT WEEK('1998-12-31',1);
+ -> 53
+
+ */
+ class OOp_Week : public ONthOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const std::vector<ORowSetValue>& lhs) const override;
+ };
+
+ /** YEAR(date)
+ Returns the year for date, in the range 1000 to 9999:
+
+ > SELECT YEAR('98-02-03');
+ -> 1998
+ */
+ class OOp_Year : public OUnaryOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const ORowSetValue& lhs) const override;
+ };
+
+ /** HOUR(time)
+ Returns the hour for time, in the range 0 to 23:
+
+ > SELECT HOUR('10:05:03');
+ -> 10
+ */
+ class OOp_Hour : public OUnaryOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const ORowSetValue& lhs) const override;
+ };
+
+ /** MINUTE(time)
+ Returns the minute for time, in the range 0 to 59:
+
+ > SELECT MINUTE('98-02-03 10:05:03');
+ -> 5
+
+ */
+ class OOp_Minute : public OUnaryOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const ORowSetValue& lhs) const override;
+ };
+
+ /** SECOND(time)
+ Returns the second for time, in the range 0 to 59:
+
+ > SELECT SECOND('10:05:03');
+ -> 3
+ */
+ class OOp_Second : public OUnaryOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const ORowSetValue& lhs) const override;
+ };
+
+ /** CURDATE()
+ CURRENT_DATE
+ Returns today's date as a value in 'YYYY-MM-DD' or YYYYMMDD format, depending on whether the function is used in a string or numeric context:
+
+ > SELECT CURDATE();
+ -> '1997-12-15'
+ */
+ class OOp_CurDate : public ONthOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const std::vector<ORowSetValue>& lhs) const override;
+ };
+
+ /** CURTIME()
+ CURRENT_TIME
+ Returns the current time as a value in 'HH:MM:SS' or HHMMSS format, depending on whether the function is used in a string or numeric context:
+
+ > SELECT CURTIME();
+ -> '23:50:26'
+ */
+ class OOp_CurTime : public ONthOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const std::vector<ORowSetValue>& lhs) const override;
+ };
+
+ /** NOW()
+ Returns the current date and time as a value in 'YYYY-MM-DD HH:MM:SS' or YYYYMMDDHHMMSS format, depending on whether the function is used in a string or numeric context:
+
+ > SELECT NOW();
+ -> '1997-12-15 23:50:26'
+ */
+ class OOp_Now : public ONthOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const std::vector<ORowSetValue>& lhs) const override;
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/file/FDriver.hxx b/connectivity/source/inc/file/FDriver.hxx
new file mode 100644
index 0000000000..0351c59ca2
--- /dev/null
+++ b/connectivity/source/inc/file/FDriver.hxx
@@ -0,0 +1,72 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/sdbc/XDriver.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/sdbcx/XDataDefinitionSupplier.hpp>
+#include <cppuhelper/compbase.hxx>
+#include <connectivity/CommonTools.hxx>
+#include <file/filedllapi.hxx>
+
+namespace connectivity::file
+ {
+ typedef ::cppu::WeakComponentImplHelper< css::sdbc::XDriver,
+ css::lang::XServiceInfo,
+ css::sdbcx::XDataDefinitionSupplier> ODriver_BASE;
+
+ class OOO_DLLPUBLIC_FILE SAL_NO_VTABLE OFileDriver : public ODriver_BASE
+ {
+ protected:
+ ::osl::Mutex m_aMutex;
+
+ connectivity::OWeakRefArray m_xConnections; // vector containing a list
+ // of all the Connection objects
+ // for this Driver
+ css::uno::Reference< css::uno::XComponentContext > m_xContext;
+ public:
+ OFileDriver(css::uno::Reference< css::uno::XComponentContext > _xContext);
+
+ // OComponentHelper
+ virtual void SAL_CALL disposing() override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+ // XDriver
+ virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL connect( const OUString& url, const css::uno::Sequence< css::beans::PropertyValue >& info ) override;
+ virtual sal_Bool SAL_CALL acceptsURL( const OUString& url ) override;
+ virtual css::uno::Sequence< css::sdbc::DriverPropertyInfo > SAL_CALL getPropertyInfo( const OUString& url, const css::uno::Sequence< css::beans::PropertyValue >& info ) override;
+ virtual sal_Int32 SAL_CALL getMajorVersion( ) override;
+ virtual sal_Int32 SAL_CALL getMinorVersion( ) override;
+
+ // XDataDefinitionSupplier
+ virtual css::uno::Reference< css::sdbcx::XTablesSupplier > SAL_CALL getDataDefinitionByConnection( const css::uno::Reference< css::sdbc::XConnection >& connection ) override;
+ virtual css::uno::Reference< css::sdbcx::XTablesSupplier > SAL_CALL getDataDefinitionByURL( const OUString& url, const css::uno::Sequence< css::beans::PropertyValue >& info ) override;
+
+ const css::uno::Reference< css::uno::XComponentContext >& getComponentContext() const { return m_xContext; }
+ };
+
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/file/FNumericFunctions.hxx b/connectivity/source/inc/file/FNumericFunctions.hxx
new file mode 100644
index 0000000000..765f2cde82
--- /dev/null
+++ b/connectivity/source/inc/file/FNumericFunctions.hxx
@@ -0,0 +1,362 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <file/fcode.hxx>
+
+namespace connectivity::file
+ {
+ /** ABS(X)
+ Returns the absolute value of X:
+
+ > SELECT ABS(2);
+ -> 2
+ > SELECT ABS(-32);
+ -> 32
+
+ */
+ class OOp_Abs : public OUnaryOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const ORowSetValue& lhs) const override;
+ };
+
+ /** SIGN(X)
+ Returns the sign of the argument as -1, 0, or 1, depending on whether X is negative, zero, or positive:
+
+ > SELECT SIGN(-32);
+ -> -1
+ > SELECT SIGN(0);
+ -> 0
+ > SELECT SIGN(234);
+ -> 1
+
+ */
+ class OOp_Sign : public OUnaryOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const ORowSetValue& lhs) const override;
+ };
+
+ /** MOD(N,M)
+ %
+ Modulo (like the % operator in C). Returns the remainder of N divided by M:
+
+ > SELECT MOD(234, 10);
+ -> 4
+ > SELECT 253 % 7;
+ -> 1
+ > SELECT MOD(29,9);
+ -> 2
+ > SELECT 29 MOD 9;
+ -> 2
+ */
+ class OOp_Mod : public OBinaryOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const ORowSetValue& lhs,const ORowSetValue& rhs) const override;
+ };
+
+ /** FLOOR(X)
+ Returns the largest integer value not greater than X:
+
+ > SELECT FLOOR(1.23);
+ -> 1
+ > SELECT FLOOR(-1.23);
+ -> -2
+
+ */
+ class OOp_Floor : public OUnaryOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const ORowSetValue& lhs) const override;
+ };
+
+ /** CEILING(X)
+ Returns the smallest integer value not less than X:
+
+ > SELECT CEILING(1.23);
+ -> 2
+ > SELECT CEILING(-1.23);
+ -> -1
+
+ */
+ class OOp_Ceiling : public OUnaryOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const ORowSetValue& lhs) const override;
+ };
+
+ /** ROUND(X)
+ ROUND(X,D)
+ Returns the argument X, rounded to the nearest integer. With two arguments rounded to a number to D decimals.
+
+ > SELECT ROUND(-1.23);
+ -> -1
+ > SELECT ROUND(-1.58);
+ -> -2
+ > SELECT ROUND(1.58);
+ -> 2
+ > SELECT ROUND(1.298, 1);
+ -> 1.3
+ > SELECT ROUND(1.298, 0);
+ -> 1
+ > SELECT ROUND(23.298, -1);
+ -> 20
+ */
+ class OOp_Round : public ONthOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const std::vector<ORowSetValue>& lhs) const override;
+ };
+
+ /** EXP(X)
+ Returns the value of e (the base of natural logarithms) raised to the power of X:
+
+ > SELECT EXP(2);
+ -> 7.389056
+ > SELECT EXP(-2);
+ -> 0.135335
+ */
+ class OOp_Exp : public OUnaryOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const ORowSetValue& lhs) const override;
+ };
+
+ /** LN(X)
+ Returns the natural logarithm of X:
+
+ > SELECT LN(2);
+ -> 0.693147
+ > SELECT LN(-2);
+ -> NULL
+
+ */
+ class OOp_Ln : public OUnaryOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const ORowSetValue& lhs) const override;
+ };
+
+ /** LOG(X)
+ LOG(B,X)
+ If called with one parameter, this function returns the natural logarithm of X:
+
+ > SELECT LOG(2);
+ -> 0.693147
+ > SELECT LOG(-2);
+ -> NULL
+
+ If called with two parameters, this function returns the logarithm of X for an arbitrary base B:
+
+ > SELECT LOG(2,65536);
+ -> 16.000000
+ > SELECT LOG(1,100);
+ -> NULL
+ */
+ class OOp_Log : public ONthOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const std::vector<ORowSetValue>& lhs) const override;
+ };
+
+ /** LOG10(X)
+ Returns the base-10 logarithm of X:
+
+ > SELECT LOG10(2);
+ -> 0.301030
+ > SELECT LOG10(100);
+ -> 2.000000
+ > SELECT LOG10(-100);
+ -> NULL
+ */
+ class OOp_Log10 : public OUnaryOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const ORowSetValue& lhs) const override;
+ };
+
+ /** POWER(X,Y)
+ Returns the value of X raised to the power of Y:
+
+ > SELECT POW(2,2);
+ -> 4.000000
+ > SELECT POW(2,-2);
+ -> 0.250000
+ */
+ class OOp_Pow : public OBinaryOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const ORowSetValue& lhs,const ORowSetValue& rhs) const override;
+ };
+
+ /** SQRT(X)
+ Returns the non-negative square root of X:
+
+ > SELECT SQRT(4);
+ -> 2.000000
+ > SELECT SQRT(20);
+ -> 4.472136
+ */
+ class OOp_Sqrt : public OUnaryOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const ORowSetValue& lhs) const override;
+ };
+
+ /** PI()
+ Returns the value of PI. The default shown number of decimals is 5, but internally uses the full double precision for PI.
+
+ > SELECT PI();
+ -> 3.141593
+ > SELECT PI()+0.000000000000000000;
+ -> 3.141592653589793238
+
+ */
+ class OOp_Pi : public ONthOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const std::vector<ORowSetValue>& lhs) const override;
+ };
+
+ /** COS(X)
+ Returns the cosine of X, where X is given in radians:
+
+ > SELECT COS(PI());
+ -> -1.000000
+ */
+ class OOp_Cos : public OUnaryOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const ORowSetValue& lhs) const override;
+ };
+
+ /** SIN(X)
+ Returns the sine of X, where X is given in radians:
+
+ > SELECT SIN(PI());
+ -> 0.000000
+
+ */
+ class OOp_Sin : public OUnaryOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const ORowSetValue& lhs) const override;
+ };
+ /** TAN(X)
+ Returns the tangent of X, where X is given in radians:
+
+ > SELECT TAN(PI()+1);
+ -> 1.557408
+ */
+ class OOp_Tan : public OUnaryOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const ORowSetValue& lhs) const override;
+ };
+
+ /** ACOS(X)
+ Returns the arc cosine of X, that is, the value whose cosine is X. Returns NULL if X is not in the range -1 to 1:
+
+ > SELECT ACOS(1);
+ -> 0.000000
+ > SELECT ACOS(1.0001);
+ -> NULL
+ > SELECT ACOS(0);
+ -> 1.570796
+ */
+ class OOp_ACos : public OUnaryOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const ORowSetValue& lhs) const override;
+ };
+
+ /** ASIN(X)
+ Returns the arc sine of X, that is, the value whose sine is X. Returns NULL if X is not in the range -1 to 1:
+
+ > SELECT ASIN(0.2);
+ -> 0.201358
+ > SELECT ASIN('foo');
+ -> 0.000000
+ */
+ class OOp_ASin : public OUnaryOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const ORowSetValue& lhs) const override;
+ };
+
+ /** ATAN(X)
+ Returns the arc tangent of X, that is, the value whose tangent is X:
+
+ > SELECT ATAN(2);
+ -> 1.107149
+ > SELECT ATAN(-2);
+ -> -1.107149
+ */
+ class OOp_ATan : public OUnaryOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const ORowSetValue& lhs) const override;
+ };
+
+ /** ATAN2(Y,X)
+ Returns the arc tangent of the two variables X and Y. It is similar to calculating the arc tangent of Y / X, except that the signs of both arguments are used to determine the quadrant of the result:
+
+ > SELECT ATAN2(-2,2);
+ -> -0.785398
+ > SELECT ATAN2(PI(),0);
+ -> 1.570796
+
+ */
+ class OOp_ATan2 : public OBinaryOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const ORowSetValue& lhs,const ORowSetValue& rhs) const override;
+ };
+
+ /** DEGREES(X)
+ Returns the argument X, converted from radians to degrees:
+
+ > SELECT DEGREES(PI());
+ -> 180.000000
+ */
+ class OOp_Degrees : public OUnaryOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const ORowSetValue& lhs) const override;
+ };
+
+ /** RADIANS(X)
+ Returns the argument X, converted from degrees to radians:
+
+ > SELECT RADIANS(90);
+ -> 1.570796
+
+ */
+ class OOp_Radians : public OUnaryOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const ORowSetValue& lhs) const override;
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/file/FPreparedStatement.hxx b/connectivity/source/inc/file/FPreparedStatement.hxx
new file mode 100644
index 0000000000..f83d74a6d0
--- /dev/null
+++ b/connectivity/source/inc/file/FPreparedStatement.hxx
@@ -0,0 +1,121 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <file/filedllapi.hxx>
+#include <file/FStatement.hxx>
+#include <com/sun/star/sdbc/XPreparedStatement.hpp>
+#include <com/sun/star/sdbc/XParameters.hpp>
+#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
+#include <com/sun/star/io/XInputStream.hpp>
+#include <file/FResultSet.hxx>
+
+namespace connectivity::file
+ {
+
+ class OOO_DLLPUBLIC_FILE SAL_NO_VTABLE OPreparedStatement : public OStatement_BASE2,
+ public css::sdbc::XPreparedStatement,
+ public css::sdbc::XParameters,
+ public css::sdbc::XResultSetMetaDataSupplier,
+ public css::lang::XServiceInfo
+
+ {
+ protected:
+
+ // Data attributes
+
+ OValueRefRow m_aParameterRow;
+ css::uno::Reference< css::sdbc::XResultSetMetaData> m_xMetaData;
+
+ ::rtl::Reference<connectivity::OSQLColumns> m_xParamColumns; // the parameter columns
+
+ // factory method for resultset's
+ virtual rtl::Reference<OResultSet> createResultSet() override;
+ ::rtl::Reference< OResultSet > makeResultSet();
+ void initResultSet(OResultSet*);
+
+ void checkAndResizeParameters(sal_Int32 parameterIndex);
+ void setParameter(sal_Int32 parameterIndex, const ORowSetValue& x);
+
+ sal_uInt32 AddParameter(connectivity::OSQLParseNode const * pParameter,
+ const css::uno::Reference< css::beans::XPropertySet>& _xCol);
+ void scanParameter(OSQLParseNode* pParseNode,std::vector< OSQLParseNode*>& _rParaNodes);
+ void describeColumn(OSQLParseNode const * _pParameter, OSQLParseNode const * _pNode, const OSQLTable& _xTable);
+ void describeParameter();
+
+ virtual void parseParamterElem(const OUString& _sColumnName,OSQLParseNode* pRow_Value_Constructor_Elem) override;
+ virtual void initializeResultSet(OResultSet* _pResult) override;
+
+ virtual ~OPreparedStatement() override;
+ public:
+ DECLARE_SERVICE_INFO();
+ // a Constructor, that is needed for when Returning the Object is needed:
+ OPreparedStatement( OConnection* _pConnection);
+
+ virtual void construct(const OUString& sql) override;
+
+ // OComponentHelper
+ virtual void SAL_CALL disposing() override;
+ //XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+ //XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override;
+
+ // XPreparedStatement
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL executeQuery( ) override;
+ virtual sal_Int32 SAL_CALL executeUpdate( ) override;
+ virtual sal_Bool SAL_CALL execute( ) override;
+ virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL getConnection( ) override;
+ // XParameters
+ virtual void SAL_CALL setNull( sal_Int32 parameterIndex, sal_Int32 sqlType ) override;
+ virtual void SAL_CALL setObjectNull( sal_Int32 parameterIndex, sal_Int32 sqlType, const OUString& typeName ) override;
+ virtual void SAL_CALL setBoolean( sal_Int32 parameterIndex, sal_Bool x ) override;
+ virtual void SAL_CALL setByte( sal_Int32 parameterIndex, sal_Int8 x ) override;
+ virtual void SAL_CALL setShort( sal_Int32 parameterIndex, sal_Int16 x ) override;
+ virtual void SAL_CALL setInt( sal_Int32 parameterIndex, sal_Int32 x ) override;
+ virtual void SAL_CALL setLong( sal_Int32 parameterIndex, sal_Int64 x ) override;
+ virtual void SAL_CALL setFloat( sal_Int32 parameterIndex, float x ) override;
+ virtual void SAL_CALL setDouble( sal_Int32 parameterIndex, double x ) override;
+ virtual void SAL_CALL setString( sal_Int32 parameterIndex, const OUString& x ) override;
+ virtual void SAL_CALL setBytes( sal_Int32 parameterIndex, const css::uno::Sequence< sal_Int8 >& x ) override;
+ virtual void SAL_CALL setDate( sal_Int32 parameterIndex, const css::util::Date& x ) override;
+ virtual void SAL_CALL setTime( sal_Int32 parameterIndex, const css::util::Time& x ) override;
+ virtual void SAL_CALL setTimestamp( sal_Int32 parameterIndex, const css::util::DateTime& x ) override;
+ virtual void SAL_CALL setBinaryStream( sal_Int32 parameterIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override;
+ virtual void SAL_CALL setCharacterStream( sal_Int32 parameterIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override;
+ virtual void SAL_CALL setObject( sal_Int32 parameterIndex, const css::uno::Any& x ) override;
+ virtual void SAL_CALL setObjectWithInfo( sal_Int32 parameterIndex, const css::uno::Any& x, sal_Int32 targetSqlType, sal_Int32 scale ) override;
+ virtual void SAL_CALL setRef( sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XRef >& x ) override;
+ virtual void SAL_CALL setBlob( sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XBlob >& x ) override;
+ virtual void SAL_CALL setClob( sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XClob >& x ) override;
+ virtual void SAL_CALL setArray( sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XArray >& x ) override;
+ virtual void SAL_CALL clearParameters( ) override;
+ // XCloseable
+ virtual void SAL_CALL close( ) override;
+ // XResultSetMetaDataSupplier
+ virtual css::uno::Reference< css::sdbc::XResultSetMetaData > SAL_CALL getMetaData( ) override;
+ };
+
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/file/FResultSet.hxx b/connectivity/source/inc/file/FResultSet.hxx
new file mode 100644
index 0000000000..16371531fb
--- /dev/null
+++ b/connectivity/source/inc/file/FResultSet.hxx
@@ -0,0 +1,301 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/sdbc/XResultSet.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
+#include <com/sun/star/sdbc/XCloseable.hpp>
+#include <com/sun/star/sdbc/XColumnLocate.hpp>
+#include <com/sun/star/util/XCancellable.hpp>
+#include <com/sun/star/sdbc/XWarningsSupplier.hpp>
+#include <com/sun/star/sdbc/XResultSetUpdate.hpp>
+#include <com/sun/star/sdbc/XRowUpdate.hpp>
+#include <cppuhelper/compbase.hxx>
+#include <cppuhelper/basemutex.hxx>
+#include <comphelper/proparrhlp.hxx>
+#include <file/FStatement.hxx>
+#include <connectivity/CommonTools.hxx>
+#include <comphelper/propertycontainer.hxx>
+#include <file/fanalyzer.hxx>
+#include <file/FTable.hxx>
+#include <file/filedllapi.hxx>
+#include <TSortIndex.hxx>
+#include <TSkipDeletedSet.hxx>
+#include <com/sun/star/lang/XEventListener.hpp>
+#include <o3tl/safeint.hxx>
+
+namespace connectivity::file
+ {
+ typedef ::cppu::WeakComponentImplHelper< css::sdbc::XResultSet,
+ css::sdbc::XRow,
+ css::sdbc::XResultSetMetaDataSupplier,
+ css::util::XCancellable,
+ css::sdbc::XWarningsSupplier,
+ css::sdbc::XResultSetUpdate,
+ css::sdbc::XRowUpdate,
+ css::sdbc::XCloseable,
+ css::sdbc::XColumnLocate,
+ css::lang::XServiceInfo,
+ css::lang::XEventListener> OResultSet_BASE;
+
+ class OOO_DLLPUBLIC_FILE OResultSet :
+ public cppu::BaseMutex,
+ public ::connectivity::IResultSetHelper,
+ public OResultSet_BASE,
+ public ::comphelper::OPropertyContainer,
+ public ::comphelper::OPropertyArrayUsageHelper<OResultSet>
+ {
+
+ protected:
+ std::vector<sal_Int32> m_aColMapping; // pos 0 is unused so we don't have to decrement 1 every time
+
+ std::vector<sal_Int32> m_aOrderbyColumnNumber;
+ std::vector<TAscendingOrder> m_aOrderbyAscending;
+
+ OValueRefRow m_aSelectRow;
+ OValueRefRow m_aRow;
+ OValueRefRow m_aEvaluateRow; // contains all values of a row
+ OValueRefRow m_aInsertRow; // needed for insert by cursor
+ ORefAssignValues m_aAssignValues; // needed for insert,update and parameters
+ // to compare with the restrictions
+ OSkipDeletedSet m_aSkipDeletedSet;
+
+ ::rtl::Reference<OKeySet> m_pFileSet;
+ OKeySet::iterator m_aFileSetIter;
+
+
+ std::unique_ptr<OSortIndex> m_pSortIndex;
+ ::rtl::Reference<connectivity::OSQLColumns> m_xColumns; // this are the select columns
+ rtl::Reference<OFileTable> m_pTable;
+ connectivity::OSQLParseNode* m_pParseTree;
+
+ OSQLAnalyzer* m_pSQLAnalyzer;
+ connectivity::OSQLParseTreeIterator& m_aSQLIterator;
+
+ sal_Int32 m_nFetchSize;
+ sal_Int32 m_nResultSetType;
+ sal_Int32 m_nFetchDirection;
+ sal_Int32 m_nResultSetConcurrency;
+
+ css::uno::Reference< css::uno::XInterface> m_xStatement;
+ css::uno::Reference< css::sdbc::XResultSetMetaData> m_xMetaData;
+ css::uno::Reference< css::container::XNameAccess> m_xColNames; // table columns
+ css::uno::Reference< css::container::XIndexAccess> m_xColsIdx; // table columns
+
+
+ sal_Int32 m_nRowPos;
+ sal_Int32 m_nFilePos;
+ sal_Int32 m_nLastVisitedPos;
+ sal_Int32 m_nRowCountResult;
+ sal_Int32 m_nColumnCount;
+ bool m_bWasNull;
+ bool m_bInserted; // true when moveToInsertRow was called
+ // set to false when cursor moved or cancel
+ bool m_bRowUpdated;
+ bool m_bRowInserted;
+ bool m_bRowDeleted;
+ bool m_bShowDeleted;
+ bool m_bIsCount;
+
+ static void initializeRow(OValueRefRow& _rRow,sal_Int32 _nColumnCount);
+ void construct();
+ //sal_Bool evaluate();
+
+ bool ExecuteRow(IResultSetHelper::Movement eFirstCursorPosition,
+ sal_Int32 nOffset = 1,
+ bool bEvaluate = true,
+ bool bRetrieveData = true);
+
+ std::unique_ptr<OKeyValue> GetOrderbyKeyValue(OValueRefRow const & _rRow);
+ bool IsSorted() const { return !m_aOrderbyColumnNumber.empty() && m_aOrderbyColumnNumber[0] >= 0;}
+
+ // return true when the select statement is "select count(*) from table"
+ bool isCount() const { return m_bIsCount; }
+ /// @throws css::sdbc::SQLException
+ void checkIndex(sal_Int32 columnIndex );
+
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ const ORowSetValue& getValue(sal_Int32 columnIndex);
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void updateValue(sal_Int32 columnIndex,const ORowSetValue& x );
+ // clear insert row
+ void clearInsertRow();
+ void sortRows();
+ protected:
+
+ using OResultSet_BASE::rBHelper;
+
+ bool Move(IResultSetHelper::Movement eCursorPosition, sal_Int32 nOffset, bool bRetrieveData);
+ virtual bool fillIndexValues(const css::uno::Reference< css::sdbcx::XColumnsSupplier> &_xIndex);
+
+ // OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override;
+ // OPropertySetHelper
+ virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override;
+
+ virtual ~OResultSet() override;
+ public:
+ DECLARE_SERVICE_INFO();
+ // a Constructor, that is needed for when Returning the Object is needed:
+ OResultSet( OStatement_Base* pStmt,connectivity::OSQLParseTreeIterator& _aSQLIterator);
+
+ // ::cppu::OComponentHelper
+ virtual void SAL_CALL disposing() override final;
+ // XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+ //XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override;
+ // XPropertySet
+ virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override;
+ // XResultSet
+ virtual sal_Bool SAL_CALL next( ) override;
+ virtual sal_Bool SAL_CALL isBeforeFirst( ) override;
+ virtual sal_Bool SAL_CALL isAfterLast( ) override;
+ virtual sal_Bool SAL_CALL isFirst( ) override;
+ virtual sal_Bool SAL_CALL isLast( ) override;
+ virtual void SAL_CALL beforeFirst( ) override;
+ virtual void SAL_CALL afterLast( ) override;
+ virtual sal_Bool SAL_CALL first( ) override;
+ virtual sal_Bool SAL_CALL last( ) override;
+ virtual sal_Int32 SAL_CALL getRow( ) override;
+ virtual sal_Bool SAL_CALL absolute( sal_Int32 row ) override;
+ virtual sal_Bool SAL_CALL relative( sal_Int32 rows ) override;
+ virtual sal_Bool SAL_CALL previous( ) override;
+ virtual void SAL_CALL refreshRow( ) override;
+ virtual sal_Bool SAL_CALL rowUpdated( ) override;
+ virtual sal_Bool SAL_CALL rowInserted( ) override;
+ virtual sal_Bool SAL_CALL rowDeleted( ) override;
+ virtual css::uno::Reference< css::uno::XInterface > SAL_CALL getStatement( ) override;
+ // XRow
+ virtual sal_Bool SAL_CALL wasNull( ) override;
+ virtual OUString SAL_CALL getString( sal_Int32 columnIndex ) override;
+ virtual sal_Bool SAL_CALL getBoolean( sal_Int32 columnIndex ) override;
+ virtual sal_Int8 SAL_CALL getByte( sal_Int32 columnIndex ) override;
+ virtual sal_Int16 SAL_CALL getShort( sal_Int32 columnIndex ) override;
+ virtual sal_Int32 SAL_CALL getInt( sal_Int32 columnIndex ) override;
+ virtual sal_Int64 SAL_CALL getLong( sal_Int32 columnIndex ) override;
+ virtual float SAL_CALL getFloat( sal_Int32 columnIndex ) override;
+ virtual double SAL_CALL getDouble( sal_Int32 columnIndex ) override;
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getBytes( sal_Int32 columnIndex ) override;
+ virtual css::util::Date SAL_CALL getDate( sal_Int32 columnIndex ) override;
+ virtual css::util::Time SAL_CALL getTime( sal_Int32 columnIndex ) override;
+ virtual css::util::DateTime SAL_CALL getTimestamp( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getBinaryStream( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getCharacterStream( sal_Int32 columnIndex ) override;
+ virtual css::uno::Any SAL_CALL getObject( sal_Int32 columnIndex, const css::uno::Reference< css::container::XNameAccess >& typeMap ) override;
+ virtual css::uno::Reference< css::sdbc::XRef > SAL_CALL getRef( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XBlob > SAL_CALL getBlob( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XClob > SAL_CALL getClob( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XArray > SAL_CALL getArray( sal_Int32 columnIndex ) override;
+ // XResultSetMetaDataSupplier
+ virtual css::uno::Reference< css::sdbc::XResultSetMetaData > SAL_CALL getMetaData( ) override;
+ // XCancellable
+ virtual void SAL_CALL cancel( ) override;
+ // XCloseable
+ virtual void SAL_CALL close( ) override;
+ // XWarningsSupplier
+ virtual css::uno::Any SAL_CALL getWarnings( ) override;
+ virtual void SAL_CALL clearWarnings( ) override;
+ // XResultSetUpdate
+ virtual void SAL_CALL insertRow( ) override;
+ virtual void SAL_CALL updateRow( ) override;
+ virtual void SAL_CALL deleteRow( ) override;
+ virtual void SAL_CALL cancelRowUpdates( ) override;
+ virtual void SAL_CALL moveToInsertRow( ) override;
+ virtual void SAL_CALL moveToCurrentRow( ) override;
+ // XRowUpdate
+ virtual void SAL_CALL updateNull( sal_Int32 columnIndex ) override;
+ virtual void SAL_CALL updateBoolean( sal_Int32 columnIndex, sal_Bool x ) override;
+ virtual void SAL_CALL updateByte( sal_Int32 columnIndex, sal_Int8 x ) override;
+ virtual void SAL_CALL updateShort( sal_Int32 columnIndex, sal_Int16 x ) override;
+ virtual void SAL_CALL updateInt( sal_Int32 columnIndex, sal_Int32 x ) override;
+ virtual void SAL_CALL updateLong( sal_Int32 columnIndex, sal_Int64 x ) override;
+ virtual void SAL_CALL updateFloat( sal_Int32 columnIndex, float x ) override;
+ virtual void SAL_CALL updateDouble( sal_Int32 columnIndex, double x ) override;
+ virtual void SAL_CALL updateString( sal_Int32 columnIndex, const OUString& x ) override;
+ virtual void SAL_CALL updateBytes( sal_Int32 columnIndex, const css::uno::Sequence< sal_Int8 >& x ) override;
+ virtual void SAL_CALL updateDate( sal_Int32 columnIndex, const css::util::Date& x ) override;
+ virtual void SAL_CALL updateTime( sal_Int32 columnIndex, const css::util::Time& x ) override;
+ virtual void SAL_CALL updateTimestamp( sal_Int32 columnIndex, const css::util::DateTime& x ) override;
+ virtual void SAL_CALL updateBinaryStream( sal_Int32 columnIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override;
+ virtual void SAL_CALL updateCharacterStream( sal_Int32 columnIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override;
+ virtual void SAL_CALL updateObject( sal_Int32 columnIndex, const css::uno::Any& x ) override;
+ virtual void SAL_CALL updateNumericObject( sal_Int32 columnIndex, const css::uno::Any& x, sal_Int32 scale ) override;
+ // XColumnLocate
+ virtual sal_Int32 SAL_CALL findColumn( const OUString& columnName ) override;
+ //XEventlistener
+ virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override;
+
+ // special methods
+ inline sal_Int32 mapColumn(sal_Int32 column);
+ void OpenImpl();
+ void doTableSpecials(const OSQLTable& _xTable);
+
+ sal_Int32 getRowCountResult() const { return m_nRowCountResult; }
+ void setEvaluationRow(const OValueRefRow& _aRow) { m_aEvaluateRow = _aRow; }
+ void setAssignValues(const ORefAssignValues& _aAssignValues) { m_aAssignValues = _aAssignValues; }
+ void setBindingRow(const OValueRefRow& _aRow) { m_aRow = _aRow; }
+ void setSelectRow(const OValueRefRow& _rRow)
+ {
+ m_aSelectRow = _rRow;
+ m_nColumnCount = m_aSelectRow->size();
+ }
+ void setColumnMapping(std::vector<sal_Int32>&& _aColumnMapping) { m_aColMapping = std::move(_aColumnMapping); }
+ void setSqlAnalyzer(OSQLAnalyzer* _pSQLAnalyzer) { m_pSQLAnalyzer = _pSQLAnalyzer; }
+
+ void setOrderByColumns(std::vector<sal_Int32>&& _aColumnOrderBy) { m_aOrderbyColumnNumber = std::move(_aColumnOrderBy); }
+ void setOrderByAscending(std::vector<TAscendingOrder>&& _aOrderbyAsc) { m_aOrderbyAscending = std::move(_aOrderbyAsc); }
+ void setMetaData(const css::uno::Reference< css::sdbc::XResultSetMetaData>& _xMetaData) { m_xMetaData = _xMetaData;}
+
+ static void setBoundedColumns(const OValueRefRow& _rRow,
+ const OValueRefRow& _rSelectRow,
+ const ::rtl::Reference<connectivity::OSQLColumns>& _rxColumns,
+ const css::uno::Reference< css::container::XIndexAccess>& _xNames,
+ bool _bSetColumnMapping,
+ const css::uno::Reference< css::sdbc::XDatabaseMetaData>& _xMetaData,
+ std::vector<sal_Int32>& _rColMapping);
+
+ // IResultSetHelper
+ virtual bool move(IResultSetHelper::Movement _eCursorPosition, sal_Int32 _nOffset, bool _bRetrieveData) override;
+ virtual sal_Int32 getDriverPos() const override;
+ virtual bool isRowDeleted() const override;
+ };
+
+ inline sal_Int32 OResultSet::mapColumn(sal_Int32 column)
+ {
+ sal_Int32 map = column;
+
+ OSL_ENSURE(column > 0, "file::OResultSet::mapColumn: invalid column index!");
+ // the first column (index 0) is for convenience only. The first real select column is number 1.
+ if ((column > 0) && (o3tl::make_unsigned(column) < m_aColMapping.size()))
+ map = m_aColMapping[column];
+
+ return map;
+ }
+
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/file/FResultSetMetaData.hxx b/connectivity/source/inc/file/FResultSetMetaData.hxx
new file mode 100644
index 0000000000..dee656a915
--- /dev/null
+++ b/connectivity/source/inc/file/FResultSetMetaData.hxx
@@ -0,0 +1,77 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/sdbc/XResultSetMetaData.hpp>
+#include <cppuhelper/implbase.hxx>
+#include <connectivity/CommonTools.hxx>
+#include <rtl/ref.hxx>
+
+namespace connectivity::file
+ {
+ class OFileTable;
+
+ //************ Class: ResultSetMetaData
+
+ typedef ::cppu::WeakImplHelper< css::sdbc::XResultSetMetaData> OResultSetMetaData_BASE;
+
+ class OResultSetMetaData :
+ public OResultSetMetaData_BASE
+ {
+ OUString m_aTableName;
+ ::rtl::Reference<connectivity::OSQLColumns> m_xColumns;
+ OFileTable* m_pTable;
+
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void checkColumnIndex(sal_Int32 column);
+ protected:
+ virtual ~OResultSetMetaData() override;
+ public:
+ // a Constructor, that is needed for when Returning the Object is needed:
+ OResultSetMetaData(::rtl::Reference<connectivity::OSQLColumns> _xColumns, OUString _aTableName, OFileTable* _pTable);
+
+ virtual sal_Int32 SAL_CALL getColumnCount( ) override;
+ virtual sal_Bool SAL_CALL isAutoIncrement( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isCaseSensitive( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isSearchable( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isCurrency( sal_Int32 column ) override;
+ virtual sal_Int32 SAL_CALL isNullable( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isSigned( sal_Int32 column ) override;
+ virtual sal_Int32 SAL_CALL getColumnDisplaySize( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getColumnLabel( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getColumnName( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getSchemaName( sal_Int32 column ) override;
+ virtual sal_Int32 SAL_CALL getPrecision( sal_Int32 column ) override;
+ virtual sal_Int32 SAL_CALL getScale( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getTableName( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getCatalogName( sal_Int32 column ) override;
+ virtual sal_Int32 SAL_CALL getColumnType( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getColumnTypeName( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isReadOnly( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isWritable( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isDefinitelyWritable( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getColumnServiceName( sal_Int32 column ) override;
+ };
+
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/file/FStatement.hxx b/connectivity/source/inc/file/FStatement.hxx
new file mode 100644
index 0000000000..57ce0a2fc0
--- /dev/null
+++ b/connectivity/source/inc/file/FStatement.hxx
@@ -0,0 +1,196 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/sdbc/XStatement.hpp>
+#include <com/sun/star/sdbc/XWarningsSupplier.hpp>
+#include <com/sun/star/sdbc/XCloseable.hpp>
+#include <com/sun/star/sdbc/SQLWarning.hpp>
+#include <com/sun/star/util/XCancellable.hpp>
+#include <comphelper/proparrhlp.hxx>
+#include <cppuhelper/compbase.hxx>
+#include <cppuhelper/implbase2.hxx>
+#include <cppuhelper/basemutex.hxx>
+#include <connectivity/CommonTools.hxx>
+#include <connectivity/sqlparse.hxx>
+#include <file/FConnection.hxx>
+#include <file/filedllapi.hxx>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <comphelper/propertycontainer.hxx>
+#include <file/fanalyzer.hxx>
+#include <TSortIndex.hxx>
+
+namespace connectivity::file
+ {
+ class OResultSet;
+ class OFileTable;
+ typedef ::cppu::WeakComponentImplHelper< css::sdbc::XWarningsSupplier,
+ css::util::XCancellable,
+ css::sdbc::XCloseable> OStatement_BASE;
+
+
+ //************ Class: java.sql.Statement
+
+ class OOO_DLLPUBLIC_FILE OStatement_Base :
+ public cppu::BaseMutex,
+ public OStatement_BASE,
+ public ::comphelper::OPropertyContainer,
+ public ::comphelper::OPropertyArrayUsageHelper<OStatement_Base>
+
+ {
+ protected:
+ std::vector<sal_Int32> m_aColMapping; // pos 0 is unused so we don't have to decrement 1 every time
+ std::vector<sal_Int32> m_aParameterIndexes; // maps the parameter index to column index
+ std::vector<sal_Int32> m_aOrderbyColumnNumber;
+ std::vector<TAscendingOrder> m_aOrderbyAscending;
+
+ css::sdbc::SQLWarning m_aLastWarning;
+ css::uno::WeakReference< css::sdbc::XResultSet> m_xResultSet; // The last ResultSet created
+ css::uno::Reference< css::sdbc::XDatabaseMetaData> m_xDBMetaData;
+ css::uno::Reference< css::container::XNameAccess> m_xColNames; // table columns // for this Statement
+
+
+ connectivity::OSQLParser m_aParser;
+ connectivity::OSQLParseTreeIterator m_aSQLIterator;
+
+ rtl::Reference<OConnection> m_pConnection;// The owning Connection object
+ connectivity::OSQLParseNode* m_pParseTree;
+ std::unique_ptr<OSQLAnalyzer> m_pSQLAnalyzer; //the sql analyzer used by the resultset
+
+ rtl::Reference<OFileTable> m_pTable; // the current table
+ OValueRefRow m_aSelectRow;
+ OValueRefRow m_aRow;
+ OValueRefRow m_aEvaluateRow; // contains all values of a row
+ ORefAssignValues m_aAssignValues; // needed for insert,update and parameters
+ // to compare with the restrictions
+
+ OUString m_aCursorName;
+ sal_Int32 m_nMaxFieldSize;
+ sal_Int32 m_nMaxRows;
+ sal_Int32 m_nQueryTimeOut;
+ sal_Int32 m_nFetchSize;
+ sal_Int32 m_nResultSetType;
+ sal_Int32 m_nFetchDirection;
+ sal_Int32 m_nResultSetConcurrency;
+ bool m_bEscapeProcessing;
+
+ protected:
+ // initialize the column index map (mapping select columns to table columns)
+ void createColumnMapping();
+ // searches the statement for sort criteria
+ void analyzeSQL();
+ void setOrderbyColumn( connectivity::OSQLParseNode const * pColumnRef,
+ connectivity::OSQLParseNode const * pAscendingDescending);
+
+ virtual void initializeResultSet(OResultSet* _pResult);
+
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void closeResultSet();
+
+ void disposeResultSet();
+ void GetAssignValues();
+ void SetAssignValue(const OUString& aColumnName,
+ const OUString& aValue,
+ bool bSetNull = false,
+ sal_uInt32 nParameter=SQL_NO_PARAMETER);
+ void ParseAssignValues( const std::vector< OUString>& aColumnNameList,
+ connectivity::OSQLParseNode* pRow_Value_Constructor_Elem, sal_Int32 nIndex);
+
+ virtual void parseParamterElem(const OUString& _sColumnName,OSQLParseNode* pRow_Value_Constructor_Elem);
+ // factory method for resultset's
+ virtual rtl::Reference<OResultSet> createResultSet() = 0;
+ // OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override;
+ // OPropertySetHelper
+ virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override;
+ virtual ~OStatement_Base() override;
+ public:
+ connectivity::OSQLParseNode* getParseTree() const { return m_pParseTree;}
+
+ OStatement_Base(OConnection* _pConnection );
+
+ OConnection* getOwnConnection() const { return m_pConnection.get(); }
+
+ using OStatement_BASE::operator css::uno::Reference< css::uno::XInterface >;
+
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ virtual void construct(const OUString& sql);
+
+ // OComponentHelper
+ virtual void SAL_CALL disposing() override;
+ // XInterface
+ // virtual void SAL_CALL release() throw(css::uno::RuntimeException) = 0;
+ virtual void SAL_CALL acquire() noexcept override;
+ // XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ //XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override;
+
+ // XPropertySet
+ virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override;
+ // XWarningsSupplier
+ virtual css::uno::Any SAL_CALL getWarnings( ) override;
+ virtual void SAL_CALL clearWarnings( ) override;
+ // XCancellable
+ virtual void SAL_CALL cancel( ) override;
+ // XCloseable
+ virtual void SAL_CALL close( ) override;
+ };
+
+ class OOO_DLLPUBLIC_FILE OStatement_BASE2 : public OStatement_Base
+
+ {
+ public:
+ OStatement_BASE2(OConnection* _pConnection ) : OStatement_Base(_pConnection ) {}
+ // OComponentHelper
+ virtual void SAL_CALL disposing() override;
+ // XInterface
+ virtual void SAL_CALL release() noexcept override;
+ };
+
+ typedef ::cppu::ImplHelper2< css::sdbc::XStatement,css::lang::XServiceInfo > OStatement_XStatement;
+ class OOO_DLLPUBLIC_FILE OStatement :
+ public OStatement_BASE2,
+ public OStatement_XStatement
+ {
+ protected:
+ // factory method for resultset's
+ virtual rtl::Reference<OResultSet> createResultSet() override;
+ public:
+ // a Constructor, that is needed for when Returning the Object is needed:
+ OStatement( OConnection* _pConnection) : OStatement_BASE2( _pConnection){}
+ DECLARE_SERVICE_INFO();
+
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+
+ // XStatement
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL executeQuery( const OUString& sql ) override ;
+ virtual sal_Int32 SAL_CALL executeUpdate( const OUString& sql ) override ;
+ virtual sal_Bool SAL_CALL execute( const OUString& sql ) override ;
+ virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL getConnection( ) override ;
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/file/FStringFunctions.hxx b/connectivity/source/inc/file/FStringFunctions.hxx
new file mode 100644
index 0000000000..b3d72294fa
--- /dev/null
+++ b/connectivity/source/inc/file/FStringFunctions.hxx
@@ -0,0 +1,269 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <file/fcode.hxx>
+
+namespace connectivity::file
+ {
+ /** UCASE(str)
+ UPPER(str)
+ Returns the string str with all characters changed to uppercase according to the current character set mapping (the default is ISO-8859-1 Latin1):
+
+ > SELECT UCASE('Hej');
+ -> 'HEJ'
+
+ */
+ class OOp_Upper : public OUnaryOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const ORowSetValue& lhs) const override;
+ };
+
+ /** LCASE(str)
+ LOWER(str)
+ Returns the string str with all characters changed to lowercase according to the current character set mapping (the default is ISO-8859-1 Latin1):
+
+ > SELECT LCASE('QUADRATICALLY');
+ -> 'quadratically'
+
+ */
+ class OOp_Lower : public OUnaryOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const ORowSetValue& lhs) const override;
+ };
+
+ /** ASCII(str)
+ Returns the ASCII code value of the leftmost character of the string str. Returns 0 if str is the empty string. Returns NULL if str is NULL:
+
+ > SELECT ASCII('2');
+ -> 50
+ > SELECT ASCII(2);
+ -> 50
+ > SELECT ASCII('dx');
+ -> 100
+
+ */
+ class OOp_Ascii : public OUnaryOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const ORowSetValue& lhs) const override;
+ };
+
+ /** LENGTH(str)
+ OCTET_LENGTH(str)
+ CHAR_LENGTH(str)
+ CHARACTER_LENGTH(str)
+ Returns the length of the string str:
+
+ > SELECT LENGTH('text');
+ -> 4
+ > SELECT OCTET_LENGTH('text');
+ -> 4
+
+ */
+ class OOp_CharLength : public OUnaryOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const ORowSetValue& lhs) const override;
+ };
+
+ /** CHAR(N,...)
+ CHAR() interprets the arguments as integers and returns a string consisting of the characters given by the ASCII code values of those integers. NULL values are skipped:
+
+ > SELECT CHAR(ascii('t'),ascii('e'),ascii('s'),ascii('t'));
+ -> 'test'
+ > SELECT CHAR(77,77.3,'77.3');
+ -> 'MMM'
+
+ */
+ class OOp_Char : public ONthOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const std::vector<ORowSetValue>& lhs) const override;
+ };
+
+ /** CONCAT(str1,str2,...)
+ Returns the string that results from concatenating the arguments. Returns NULL if any argument is NULL. May have more than 2 arguments. A numeric argument is converted to the equivalent string form:
+
+ > SELECT CONCAT('OO', 'o', 'OO');
+ -> 'OOoOO'
+ > SELECT CONCAT('OO', NULL, 'OO');
+ -> NULL
+ > SELECT CONCAT(14.3);
+ -> '14.3'
+
+ */
+ class OOp_Concat : public ONthOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const std::vector<ORowSetValue>& lhs) const override;
+ };
+
+ /** LOCATE(substr,str)
+ POSITION(substr IN str)
+ Returns the position of the first occurrence of substring substr in string str. Returns 0 if substr is not in str:
+
+ > SELECT LOCATE('bar', 'foobarbar');
+ -> 4
+ > SELECT LOCATE('xbar', 'foobar');
+ -> 0
+ LOCATE(substr,str,pos)
+ Returns the position of the first occurrence of substring substr in string str, starting at position pos. Returns 0 if substr is not in str:
+
+ > SELECT LOCATE('bar', 'foobarbar',5);
+ -> 7
+
+ */
+ class OOp_Locate : public ONthOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const std::vector<ORowSetValue>& lhs) const override;
+ };
+
+ /** SUBSTRING(str,pos)
+ SUBSTRING(str FROM pos)
+ Returns a substring from string str starting at position pos:
+
+ > SELECT SUBSTRING('Quadratically',5);
+ -> 'ratically'
+ > SELECT SUBSTRING('foobarbar' FROM 4);
+ -> 'barbar'
+ SUBSTRING(str,pos,len)
+ SUBSTRING(str FROM pos FOR len)
+ Returns a substring len characters long from string str, starting at position pos. The variant form that uses FROM is SQL-92 syntax:
+
+ > SELECT SUBSTRING('Quadratically',5,6);
+ -> 'ratica'
+
+ */
+ class OOp_SubString : public ONthOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const std::vector<ORowSetValue>& lhs) const override;
+ };
+
+ /** LTRIM(str)
+ Returns the string str with leading space characters removed:
+
+ > SELECT LTRIM(' barbar');
+ -> 'barbar'
+
+ */
+ class OOp_LTrim : public OUnaryOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const ORowSetValue& lhs) const override;
+ };
+
+ /** RTRIM(str)
+ Returns the string str with trailing space characters removed:
+
+ > SELECT RTRIM('barbar ');
+ -> 'barbar'
+
+ */
+ class OOp_RTrim : public OUnaryOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const ORowSetValue& lhs) const override;
+ };
+
+ /** SPACE(N)
+ Returns a string consisting of N space characters:
+
+ > SELECT SPACE(6);
+ -> ' '
+
+ */
+ class OOp_Space : public OUnaryOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const ORowSetValue& lhs) const override;
+ };
+
+ /** REPLACE(str,from_str,to_str)
+ Returns the string str with all occurrences of the string from_str replaced by the string to_str:
+
+ > SELECT REPLACE('www.OOo.com', 'w', 'Ww');
+ -> 'WwWwWw.OOo.com'
+
+ */
+ class OOp_Replace : public ONthOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const std::vector<ORowSetValue>& lhs) const override;
+ };
+
+ /** REPEAT(str,count)
+ Returns a string consisting of the string str repeated count times. If count <= 0, returns an empty string. Returns NULL if str or count are NULL:
+
+ > SELECT REPEAT('OOo', 3);
+ -> 'OOoOOoOOo'
+
+ */
+ class OOp_Repeat : public OBinaryOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const ORowSetValue& lhs,const ORowSetValue& rhs) const override;
+ };
+
+ /** INSERT(str,pos,len,newstr)
+ Returns the string str, with the substring beginning at position pos and len characters long replaced by the string newstr:
+
+ > SELECT INSERT('Quadratic', 3, 4, 'What');
+ -> 'QuWhattic'
+
+ */
+ class OOp_Insert : public ONthOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const std::vector<ORowSetValue>& lhs) const override;
+ };
+
+ /** LEFT(str,len)
+ Returns the leftmost len characters from the string str:
+
+ > SELECT LEFT('foobarbar', 5);
+ -> 'fooba'
+
+ */
+ class OOp_Left : public OBinaryOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const ORowSetValue& lhs,const ORowSetValue& rhs) const override;
+ };
+
+ /** RIGHT(str,len)
+ Returns the rightmost len characters from the string str:
+
+ > SELECT RIGHT('foobarbar', 4);
+ -> 'rbar'
+ */
+ class OOp_Right : public OBinaryOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const ORowSetValue& lhs,const ORowSetValue& rhs) const override;
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/file/FTable.hxx b/connectivity/source/inc/file/FTable.hxx
new file mode 100644
index 0000000000..d8bbd92d6c
--- /dev/null
+++ b/connectivity/source/inc/file/FTable.hxx
@@ -0,0 +1,99 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <connectivity/sdbcx/VTable.hxx>
+#include <file/FConnection.hxx>
+#include <file/filedllapi.hxx>
+#include <tools/stream.hxx>
+#include <connectivity/FValue.hxx>
+#include <TResultSetHelper.hxx>
+
+namespace connectivity::file
+ {
+ typedef connectivity::sdbcx::OTable OTable_TYPEDEF;
+
+ class OOO_DLLPUBLIC_FILE OFileTable : public OTable_TYPEDEF
+ {
+ protected:
+ OConnection* m_pConnection;
+ std::unique_ptr<SvStream> m_pFileStream;
+ ::rtl::Reference<OSQLColumns> m_aColumns;
+ sal_Int32 m_nFilePos; // current IResultSetHelper::Movement
+ std::unique_ptr<sal_uInt8[]> m_pBuffer;
+ sal_uInt16 m_nBufferSize; // size of the ReadBuffer, if pBuffer != NULL
+ bool m_bWriteable; // svstream can't say if we are writeable
+ // so we have to
+
+ virtual void FileClose();
+ virtual ~OFileTable( ) override;
+ public:
+ virtual void refreshColumns() override;
+ virtual void refreshKeys() override;
+ virtual void refreshIndexes() override;
+ public:
+ OFileTable( sdbcx::OCollection* _pTables,OConnection* _pConnection);
+ OFileTable( sdbcx::OCollection* _pTables,OConnection* _pConnection,
+ const OUString& Name,
+ const OUString& Type,
+ const OUString& Description,
+ const OUString& SchemaName,
+ const OUString& CatalogName
+ );
+
+ //XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ // ::cppu::OComponentHelper
+ virtual void SAL_CALL disposing() override;
+
+ OConnection* getConnection() const { return m_pConnection;}
+ virtual sal_Int32 getCurrentLastPos() const {return -1;}
+
+ virtual bool seekRow(IResultSetHelper::Movement eCursorPosition, sal_Int32 nOffset, sal_Int32& nCurPos) = 0;
+ virtual bool fetchRow(OValueRefRow& _rRow, const OSQLColumns& _rCols, bool bRetrieveData) = 0;
+
+ const ::rtl::Reference<OSQLColumns>& getTableColumns() const {return m_aColumns;}
+ virtual bool InsertRow(OValueRefVector& rRow, const css::uno::Reference< css::container::XIndexAccess>& _xCols);
+ virtual bool DeleteRow(const OSQLColumns& _rCols);
+ virtual bool UpdateRow(OValueRefVector& rRow, OValueRefRow& pOrgRow,const css::uno::Reference< css::container::XIndexAccess>& _xCols);
+ virtual void addColumn(const css::uno::Reference< css::beans::XPropertySet>& descriptor);
+ virtual void dropColumn(sal_Int32 _nPos);
+ // refresh the header of file based tables to see changes done by someone
+ virtual void refreshHeader();
+
+ OUString SAL_CALL getName() override { return m_Name; }
+
+ const OUString& getSchema() const { return m_SchemaName; }
+ bool isReadOnly() const { return !m_bWriteable; }
+ // m_pFileStream && !m_pFileStream->IsWritable(); }
+
+ sal_Int32 getFilePos() const { return m_nFilePos; }
+
+ public:
+ // helper
+
+ // creates a stream using ::utl::UcbStreamHelper::CreateStream, but the error is simplified
+ // (NULL or non-NULL is returned)
+ static std::unique_ptr<SvStream> createStream_simpleError( const OUString& _rFileName, StreamMode _eOpenMode);
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/file/FTables.hxx b/connectivity/source/inc/file/FTables.hxx
new file mode 100644
index 0000000000..9d14c36279
--- /dev/null
+++ b/connectivity/source/inc/file/FTables.hxx
@@ -0,0 +1,44 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <file/filedllapi.hxx>
+#include <connectivity/sdbcx/VCollection.hxx>
+#include <com/sun/star/sdbc/XDatabaseMetaData.hpp>
+
+namespace connectivity::file
+ {
+ class OOO_DLLPUBLIC_FILE SAL_NO_VTABLE OTables :
+ public sdbcx::OCollection
+ {
+ protected:
+ virtual sdbcx::ObjectType createObject(const OUString& _rName) override;
+ virtual void impl_refresh() override;
+ public:
+ OTables(const css::uno::Reference< css::sdbc::XDatabaseMetaData >& _rMetaData,::cppu::OWeakObject& _rParent, ::osl::Mutex& _rMutex,
+ const ::std::vector< OUString> &_rVector) : sdbcx::OCollection(_rParent,_rMetaData->supportsMixedCaseQuotedIdentifiers(),_rMutex,_rVector)
+ {}
+
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/file/fanalyzer.hxx b/connectivity/source/inc/file/fanalyzer.hxx
new file mode 100644
index 0000000000..f913529d26
--- /dev/null
+++ b/connectivity/source/inc/file/fanalyzer.hxx
@@ -0,0 +1,70 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <file/fcomp.hxx>
+
+namespace connectivity::file
+ {
+ class OConnection;
+ class OSQLAnalyzer final
+ {
+ typedef std::pair< ::rtl::Reference<OPredicateCompiler>,::rtl::Reference<OPredicateInterpreter> > TPredicates;
+
+ std::vector< TPredicates > m_aSelectionEvaluations;
+ ::rtl::Reference<OPredicateCompiler> m_aCompiler;
+ ::rtl::Reference<OPredicateInterpreter> m_aInterpreter;
+ OConnection* m_pConnection;
+
+ mutable bool m_bHasSelectionCode;
+ mutable bool m_bSelectionFirstTime;
+
+ static void bindRow(OCodeList& rCodeList,const OValueRefRow& _pRow);
+
+ public:
+ OSQLAnalyzer(OConnection* _pConnection);
+ ~OSQLAnalyzer();
+
+ OConnection* getConnection() const { return m_pConnection; }
+ void bindEvaluationRow(OValueRefRow const & _pRow); // Bind an evaluation row to the restriction
+ /** bind the select columns if they contain a function which needs a row value
+ @param _pRow the result row
+ */
+ void bindSelectRow(const OValueRefRow& _pRow);
+
+ /** binds the row to parameter for the restrictions
+ @param _pRow the parameter row
+ */
+ void bindParameterRow(OValueRefRow const & _pRow);
+
+ void dispose();
+ void start(OSQLParseNode const * pSQLParseNode);
+ bool hasRestriction() const;
+ bool hasFunctions() const;
+ bool evaluateRestriction() { return m_aInterpreter->start(); }
+ void setSelectionEvaluationResult(OValueRefRow const & _pRow,const std::vector<sal_Int32>& _rColumnMapping);
+ void setOrigColumns(const css::uno::Reference< css::container::XNameAccess>& rCols);
+ static OOperandAttr* createOperandAttr(sal_Int32 _nPos,
+ const css::uno::Reference< css::beans::XPropertySet>& _xCol);
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/file/fcode.hxx b/connectivity/source/inc/file/fcode.hxx
new file mode 100644
index 0000000000..daadbf880f
--- /dev/null
+++ b/connectivity/source/inc/file/fcode.hxx
@@ -0,0 +1,331 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <connectivity/sqliterator.hxx>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <connectivity/FValue.hxx>
+#include <file/filedllapi.hxx>
+
+#include <stack>
+#include <utility>
+
+namespace connectivity
+{
+ class OSQLParseNode;
+ namespace file
+ {
+
+ class OOperand;
+ typedef std::stack<OOperand*> OCodeStack;
+
+ class OOO_DLLPUBLIC_FILE OCode
+ {
+ public:
+ //virtual dtor to allow this to be the root of the class hierarchy
+ virtual ~OCode();
+ //but that disables the default move ctor
+ OCode(OCode&&) = default;
+ //but that disables the rest of default ctors
+ OCode(const OCode&) = default;
+ OCode() = default;
+ //and same issue for the assignment operators
+ OCode& operator=(const OCode&) = default;
+ OCode& operator=(OCode&&) = default;
+ };
+
+
+ // operands that the parsetree generate
+ class OOO_DLLPUBLIC_FILE OOperand : public OCode
+ {
+ protected:
+ sal_Int32 m_eDBType;
+
+ OOperand(sal_Int32 _rType) : m_eDBType(_rType){}
+ OOperand() : m_eDBType(css::sdbc::DataType::OTHER){}
+
+ public:
+ virtual const ORowSetValue& getValue() const = 0;
+ virtual void setValue(const ORowSetValue& _rVal) = 0;
+
+ sal_Int32 getDBType() const {return m_eDBType;}
+ inline bool isValid() const;
+
+ };
+
+ class OOperandRow : public OOperand
+ {
+ sal_uInt16 m_nRowPos;
+ OValueRefRow m_pRow;
+
+ protected:
+ OOperandRow(sal_uInt16 _nPos, sal_Int32 _rType);
+ public:
+ virtual const ORowSetValue& getValue() const override;
+ virtual void setValue(const ORowSetValue& _rVal) override;
+ void bindValue(const OValueRefRow& _pRow); // Bind to the value that the operand represents
+
+ };
+
+ // Attributes from a result row
+ class OOperandAttr : public OOperandRow
+ {
+ public:
+ OOperandAttr(sal_uInt16 _nPos,
+ const css::uno::Reference< css::beans::XPropertySet>& _xColumn);
+
+ };
+
+ // Parameter for a predicate
+ class OOperandParam : public OOperandRow
+ {
+ public:
+ OOperandParam(sal_Int32 _nPos);
+ };
+
+ // Value operands
+ class OOperandValue : public OOperand
+ {
+ protected:
+ ORowSetValue m_aValue;
+
+ protected:
+ OOperandValue(){}
+ OOperandValue(ORowSetValue _aVar, sal_Int32 eDbType)
+ : OOperand(eDbType)
+ , m_aValue(std::move(_aVar))
+ {}
+
+ OOperandValue(sal_Int32 eDbType) :OOperand(eDbType){}
+ public:
+ virtual const ORowSetValue& getValue() const override;
+ virtual void setValue(const ORowSetValue& _rVal) override;
+
+ };
+
+
+ // Constants
+ class OOperandConst : public OOperandValue
+ {
+ public:
+ OOperandConst(const connectivity::OSQLParseNode& rColumnRef, const OUString& aStrValue);
+
+ };
+
+
+ // Result operands
+ class OOperandResult : public OOperandValue
+ {
+ protected:
+ OOperandResult(sal_Int32 eDbType)
+ :OOperandValue(eDbType) {}
+ public:
+ OOperandResult(const ORowSetValue& _rVar)
+ :OOperandValue(_rVar, _rVar.getTypeKind()) {}
+ };
+
+
+ class OOperandResultBOOL : public OOperandResult
+ {
+ public:
+ OOperandResultBOOL(bool bResult) : OOperandResult(css::sdbc::DataType::BIT)
+ {
+ m_aValue = bResult ? 1.0 : 0.0;
+ m_aValue.setBound(true);
+ }
+ };
+
+ class OOperandResultNUM : public OOperandResult
+ {
+ public:
+ OOperandResultNUM(double fNum) : OOperandResult(css::sdbc::DataType::DOUBLE)
+ {
+ m_aValue = fNum;
+ m_aValue.setBound(true);
+ }
+ };
+
+ /** special stop operand
+ is appended when a list of arguments ends
+ */
+ class OStopOperand : public OOperandValue
+ {
+ public:
+ OStopOperand(){}
+ };
+
+ // Operators
+ class OOO_DLLPUBLIC_FILE OOperator : public OCode
+ {
+ public:
+ virtual void Exec(OCodeStack&) = 0;
+ };
+
+
+ // Boolean operators
+ class OOO_DLLPUBLIC_FILE OBoolOperator : public OOperator
+ {
+ public:
+ virtual void Exec(OCodeStack&) override;
+ virtual bool operate(const OOperand*, const OOperand*) const;
+ };
+
+ class OOp_NOT : public OBoolOperator
+ {
+ public:
+
+ protected:
+ virtual void Exec(OCodeStack&) override;
+ virtual bool operate(const OOperand*, const OOperand*) const override;
+ };
+
+ class OOp_AND : public OBoolOperator
+ {
+ public:
+
+ protected:
+ virtual bool operate(const OOperand*, const OOperand*) const override;
+ };
+
+ class OOp_OR : public OBoolOperator
+ {
+ public:
+ protected:
+ virtual bool operate(const OOperand*, const OOperand*) const override;
+ };
+
+ class OOO_DLLPUBLIC_FILE OOp_ISNULL : public OBoolOperator
+ {
+ public:
+ public:
+ virtual void Exec(OCodeStack&) override;
+ virtual bool operate(const OOperand*, const OOperand*) const override;
+ };
+
+ class OOO_DLLPUBLIC_FILE OOp_ISNOTNULL : public OOp_ISNULL
+ {
+ public:
+ virtual bool operate(const OOperand*, const OOperand*) const override;
+ };
+
+ class OOO_DLLPUBLIC_FILE OOp_LIKE : public OBoolOperator
+ {
+ const sal_Unicode cEscape;
+
+ public:
+ OOp_LIKE(const sal_Unicode cEsc):cEscape(cEsc){};
+
+ virtual bool operate(const OOperand*, const OOperand*) const override;
+ };
+
+ class OOp_NOTLIKE : public OOp_LIKE
+ {
+ public:
+ public:
+ OOp_NOTLIKE(const sal_Unicode cEsc):OOp_LIKE(cEsc){};
+
+ virtual bool operate(const OOperand*, const OOperand*) const override;
+ };
+
+ class OOO_DLLPUBLIC_FILE OOp_COMPARE : public OBoolOperator
+ {
+ sal_Int32 aPredicateType;
+
+ public:
+ OOp_COMPARE(sal_Int32 aPType)
+ :aPredicateType(aPType) {}
+
+ sal_Int32 getPredicateType() const { return aPredicateType; }
+ virtual bool operate(const OOperand*, const OOperand*) const override;
+ };
+
+ // Numerical operators
+ class ONumOperator : public OOperator
+ {
+ public:
+ virtual void Exec(OCodeStack&) override;
+
+
+ protected:
+ virtual double operate(const double& fLeft,const double& fRight) const = 0;
+ };
+
+ class OOp_ADD : public ONumOperator
+ {
+ protected:
+ virtual double operate(const double& fLeft,const double& fRight) const override;
+ };
+
+ class OOp_SUB : public ONumOperator
+ {
+ protected:
+ virtual double operate(const double& fLeft,const double& fRight) const override;
+ };
+
+ class OOp_MUL : public ONumOperator
+ {
+ protected:
+ virtual double operate(const double& fLeft,const double& fRight) const override;
+ };
+
+ class OOp_DIV : public ONumOperator
+ {
+ protected:
+ virtual double operate(const double& fLeft,const double& fRight) const override;
+ };
+
+ inline bool OOperand::isValid() const
+ {
+ return getValue().getDouble() != 0.0;
+ }
+
+ // Operator
+ class ONthOperator : public OOperator
+ {
+ public:
+ virtual void Exec(OCodeStack&) override;
+
+
+ protected:
+ virtual ORowSetValue operate(const std::vector<ORowSetValue>& lhs) const = 0;
+ };
+
+ class OBinaryOperator : public OOperator
+ {
+ public:
+ virtual void Exec(OCodeStack&) override;
+
+
+ protected:
+ virtual ORowSetValue operate(const ORowSetValue& lhs,const ORowSetValue& rhs) const = 0;
+ };
+
+ class OUnaryOperator : public OOperator
+ {
+ public:
+ virtual void Exec(OCodeStack&) override;
+ virtual ORowSetValue operate(const ORowSetValue& lhs) const = 0;
+
+
+ };
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/file/fcomp.hxx b/connectivity/source/inc/file/fcomp.hxx
new file mode 100644
index 0000000000..72afcdb0a8
--- /dev/null
+++ b/connectivity/source/inc/file/fcomp.hxx
@@ -0,0 +1,111 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <file/fcode.hxx>
+#include <utility>
+
+namespace connectivity
+{
+ class OSQLParseNode;
+ namespace file
+ {
+ class OCode;
+ class OOperand;
+ class OSQLAnalyzer;
+ typedef std::vector<std::unique_ptr<OCode>> OCodeList;
+
+ class OPredicateCompiler final : public ::salhelper::SimpleReferenceObject
+ {
+ friend class OPredicateInterpreter;
+ friend class OSQLAnalyzer;
+
+ OCodeList m_aCodeList;
+ css::uno::Reference< css::container::XNameAccess> m_orgColumns; // in filecurs this are the filecolumns
+ OSQLAnalyzer* m_pAnalyzer;
+ sal_Int32 m_nParamCounter;
+ public:
+ OPredicateCompiler(OSQLAnalyzer* pAnalyzer);
+
+ virtual ~OPredicateCompiler() override;
+
+ void dispose();
+
+ void start(connectivity::OSQLParseNode const * pSQLParseNode);
+ OOperand* execute(connectivity::OSQLParseNode const * pPredicateNode);
+
+ void Clean();
+ bool isClean() const {return m_aCodeList.empty();}
+ bool hasCode() const {return !isClean();}
+ void setOrigColumns(const css::uno::Reference< css::container::XNameAccess>& rCols) { m_orgColumns = rCols; }
+ const css::uno::Reference< css::container::XNameAccess>& getOrigColumns() const { return m_orgColumns; }
+ private:
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void execute_COMPARE(connectivity::OSQLParseNode const * pPredicateNode);
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void execute_LIKE(connectivity::OSQLParseNode const * pPredicateNode);
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void execute_BETWEEN(connectivity::OSQLParseNode const * pPredicateNode);
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void execute_ISNULL(connectivity::OSQLParseNode const * pPredicateNode);
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ OOperand* execute_Operand(connectivity::OSQLParseNode const * pPredicateNode);
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void execute_Fold(OSQLParseNode const * pPredicateNode);
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void executeFunction(OSQLParseNode const * pPredicateNode);
+ };
+
+
+ class OPredicateInterpreter :
+ public ::salhelper::SimpleReferenceObject
+ {
+ OCodeStack m_aStack;
+ ::rtl::Reference<OPredicateCompiler> m_rCompiler;
+
+ public:
+ OPredicateInterpreter(::rtl::Reference<OPredicateCompiler> xComp) : m_rCompiler(std::move(xComp)){}
+ virtual ~OPredicateInterpreter() override;
+
+ bool evaluate(OCodeList& rCodeList);
+ void evaluateSelection(OCodeList& rCodeList, ORowSetValueDecoratorRef const & _rVal);
+
+ bool start()
+ {
+ return evaluate(m_rCompiler->m_aCodeList);
+ }
+
+ void startSelection(ORowSetValueDecoratorRef const & _rVal)
+ {
+ evaluateSelection(m_rCompiler->m_aCodeList,_rVal);
+ }
+
+
+ };
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/file/filedllapi.hxx b/connectivity/source/inc/file/filedllapi.hxx
new file mode 100644
index 0000000000..e32f5f17cb
--- /dev/null
+++ b/connectivity/source/inc/file/filedllapi.hxx
@@ -0,0 +1,32 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <sal/types.h>
+
+#if defined OOO_DLLIMPLEMENTATION_FILE
+#define OOO_DLLPUBLIC_FILE SAL_DLLPUBLIC_EXPORT
+#else
+#define OOO_DLLPUBLIC_FILE SAL_DLLPUBLIC_IMPORT
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/file/quotedstring.hxx b/connectivity/source/inc/file/quotedstring.hxx
new file mode 100644
index 0000000000..7c6becc37f
--- /dev/null
+++ b/connectivity/source/inc/file/quotedstring.hxx
@@ -0,0 +1,46 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <rtl/ustring.hxx>
+#include <file/filedllapi.hxx>
+
+namespace connectivity
+{
+
+ // Derived from String, overriding GetToken/GetTokenCount methods
+ // Especially true for the flat file format: Strings can be quoted
+
+ class OOO_DLLPUBLIC_FILE QuotedTokenizedString
+ {
+ OUString m_sString;
+ public:
+ QuotedTokenizedString() {}
+
+ sal_Int32 GetTokenCount( sal_Unicode cTok , sal_Unicode cStrDel ) const;
+ OUString GetTokenSpecial(sal_Int32& nStartPos, sal_Unicode cTok, sal_Unicode cStrDel = '\0') const;
+ OUString& GetString() { return m_sString; }
+ void SetString(const OUString& aStr) { m_sString = aStr;}
+ sal_Int32 Len() const { return m_sString.getLength(); }
+ operator OUString&() { return m_sString; }
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/flat/ECatalog.hxx b/connectivity/source/inc/flat/ECatalog.hxx
new file mode 100644
index 0000000000..d1252e464c
--- /dev/null
+++ b/connectivity/source/inc/flat/ECatalog.hxx
@@ -0,0 +1,38 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <file/FCatalog.hxx>
+
+namespace connectivity::flat
+ {
+ class OFlatConnection;
+ class OFlatCatalog : public file::OFileCatalog
+ {
+ public:
+ virtual void refreshTables() override;
+
+ public:
+ OFlatCatalog(OFlatConnection* _pCon);
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/flat/EColumns.hxx b/connectivity/source/inc/flat/EColumns.hxx
new file mode 100644
index 0000000000..d25f79aae2
--- /dev/null
+++ b/connectivity/source/inc/flat/EColumns.hxx
@@ -0,0 +1,41 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <file/FColumns.hxx>
+
+namespace connectivity::flat
+ {
+ class OFlatColumns : public file::OColumns
+ {
+ protected:
+ virtual sdbcx::ObjectType createObject(const OUString& _rName) override;
+ public:
+ OFlatColumns(file::OFileTable* _pTable,
+ ::osl::Mutex& _rMutex,
+ const ::std::vector< OUString> &_rVector
+ ) : file::OColumns(_pTable,_rMutex,_rVector)
+ {}
+
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/flat/EConnection.hxx b/connectivity/source/inc/flat/EConnection.hxx
new file mode 100644
index 0000000000..be7c3596d4
--- /dev/null
+++ b/connectivity/source/inc/flat/EConnection.hxx
@@ -0,0 +1,62 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <file/FConnection.hxx>
+
+namespace connectivity::flat
+ {
+ class ODriver;
+ class OFlatConnection : public file::OConnection
+ {
+ private:
+ sal_Int32 m_nMaxRowsToScan;
+ bool m_bHeaderLine; // column names in first row
+ sal_Unicode m_cFieldDelimiter; // look at the name
+ sal_Unicode m_cStringDelimiter;
+ sal_Unicode m_cDecimalDelimiter;
+ sal_Unicode m_cThousandDelimiter;
+ public:
+ OFlatConnection(ODriver* _pDriver);
+ virtual ~OFlatConnection() override;
+
+ virtual void construct(const OUString& _rUrl,const css::uno::Sequence< css::beans::PropertyValue >& _rInfo ) override;
+
+ // own methods
+ bool isHeaderLine() const { return m_bHeaderLine; }
+ sal_Unicode getFieldDelimiter() const { return m_cFieldDelimiter; }
+ sal_Unicode getStringDelimiter() const { return m_cStringDelimiter; }
+ sal_Unicode getDecimalDelimiter() const { return m_cDecimalDelimiter; }
+ sal_Unicode getThousandDelimiter() const { return m_cThousandDelimiter;}
+ sal_Int32 getMaxRowsToScan() const { return m_nMaxRowsToScan;}
+ // XServiceInfo
+ DECLARE_SERVICE_INFO();
+
+ // XConnection
+ virtual css::uno::Reference< css::sdbc::XDatabaseMetaData > SAL_CALL getMetaData( ) override;
+ virtual css::uno::Reference< css::sdbcx::XTablesSupplier > createCatalog() override;
+ virtual css::uno::Reference< css::sdbc::XStatement > SAL_CALL createStatement( ) override;
+ virtual css::uno::Reference< css::sdbc::XPreparedStatement > SAL_CALL prepareStatement( const OUString& sql ) override;
+ virtual css::uno::Reference< css::sdbc::XPreparedStatement > SAL_CALL prepareCall( const OUString& sql ) override;
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/flat/EDatabaseMetaData.hxx b/connectivity/source/inc/flat/EDatabaseMetaData.hxx
new file mode 100644
index 0000000000..bd6ce77581
--- /dev/null
+++ b/connectivity/source/inc/flat/EDatabaseMetaData.hxx
@@ -0,0 +1,44 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <file/FDatabaseMetaData.hxx>
+
+namespace connectivity::flat
+ {
+
+ //************ Class: java.sql.DatabaseMetaDataDate
+
+
+ class OFlatDatabaseMetaData : public file::ODatabaseMetaData
+ {
+ virtual css::uno::Reference< css::sdbc::XResultSet > impl_getTypeInfo_throw() override;
+ protected:
+ virtual ~OFlatDatabaseMetaData() override;
+ public:
+ OFlatDatabaseMetaData(file::OConnection* _pCon);
+
+ virtual OUString SAL_CALL getURL( ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getColumns( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& tableNamePattern, const OUString& columnNamePattern ) override;
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/flat/EDriver.hxx b/connectivity/source/inc/flat/EDriver.hxx
new file mode 100644
index 0000000000..7ed2718f20
--- /dev/null
+++ b/connectivity/source/inc/flat/EDriver.hxx
@@ -0,0 +1,45 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <connectivity/CommonTools.hxx>
+#include <file/FDriver.hxx>
+
+namespace connectivity::flat
+ {
+ /// @throws css::uno::Exception
+ css::uno::Reference< css::uno::XInterface > ODriver_CreateInstance(const css::uno::Reference< css::lang::XMultiServiceFactory >& _rxFactory);
+
+ class ODriver : public file::OFileDriver
+ {
+ public:
+ ODriver(const css::uno::Reference< css::uno::XComponentContext >& _rxContext) : file::OFileDriver(_rxContext){}
+
+ OUString SAL_CALL getImplementationName( ) override;
+ // XDriver
+ virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL connect( const OUString& url, const css::uno::Sequence< css::beans::PropertyValue >& info ) override;
+ virtual sal_Bool SAL_CALL acceptsURL( const OUString& url ) override;
+ virtual css::uno::Sequence< css::sdbc::DriverPropertyInfo > SAL_CALL getPropertyInfo( const OUString& url, const css::uno::Sequence< css::beans::PropertyValue >& info ) override;
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/flat/EPreparedStatement.hxx b/connectivity/source/inc/flat/EPreparedStatement.hxx
new file mode 100644
index 0000000000..ca164be8d5
--- /dev/null
+++ b/connectivity/source/inc/flat/EPreparedStatement.hxx
@@ -0,0 +1,38 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <file/FPreparedStatement.hxx>
+
+namespace connectivity::flat
+ {
+ class OConnection;
+ class OFlatPreparedStatement : public file::OPreparedStatement
+ {
+ protected:
+ virtual rtl::Reference<file::OResultSet> createResultSet() override;
+ public:
+ OFlatPreparedStatement( file::OConnection* _pConnection) : file::OPreparedStatement( _pConnection){}
+ DECLARE_SERVICE_INFO();
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/flat/EResultSet.hxx b/connectivity/source/inc/flat/EResultSet.hxx
new file mode 100644
index 0000000000..8d99ed55da
--- /dev/null
+++ b/connectivity/source/inc/flat/EResultSet.hxx
@@ -0,0 +1,70 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <file/FResultSet.hxx>
+#include <com/sun/star/sdbcx/XRowLocate.hpp>
+#include <cppuhelper/implbase1.hxx>
+
+namespace connectivity::flat
+ {
+ class OFlatResultSet;
+ // these typedef's are only necessary for the compiler
+ typedef ::cppu::ImplHelper1< css::sdbcx::XRowLocate> OFlatResultSet_BASE;
+ typedef file::OResultSet OFlatResultSet_BASE2;
+ typedef ::comphelper::OPropertyArrayUsageHelper<OFlatResultSet> OFlatResultSet_BASE3;
+
+
+ class OFlatResultSet : public OFlatResultSet_BASE2,
+ public OFlatResultSet_BASE,
+ public OFlatResultSet_BASE3
+ {
+ bool m_bBookmarkable;
+ protected:
+ // OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override;
+ // OPropertySetHelper
+ virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override;
+ public:
+ DECLARE_SERVICE_INFO();
+
+ OFlatResultSet( file::OStatement_Base* pStmt,connectivity::OSQLParseTreeIterator& _aSQLIterator);
+
+ // XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+ //XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override;
+ // XPropertySet
+ virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override;
+
+ // XRowLocate
+ virtual css::uno::Any SAL_CALL getBookmark( ) override;
+ virtual sal_Bool SAL_CALL moveToBookmark( const css::uno::Any& bookmark ) override;
+ virtual sal_Bool SAL_CALL moveRelativeToBookmark( const css::uno::Any& bookmark, sal_Int32 rows ) override;
+ virtual sal_Int32 SAL_CALL compareBookmarks( const css::uno::Any& first, const css::uno::Any& second ) override;
+ virtual sal_Bool SAL_CALL hasOrderedBookmarks( ) override;
+ virtual sal_Int32 SAL_CALL hashBookmark( const css::uno::Any& bookmark ) override;
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/flat/EStatement.hxx b/connectivity/source/inc/flat/EStatement.hxx
new file mode 100644
index 0000000000..d30bfc7097
--- /dev/null
+++ b/connectivity/source/inc/flat/EStatement.hxx
@@ -0,0 +1,38 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <file/FStatement.hxx>
+
+namespace connectivity::flat
+ {
+ class OConnection;
+ class OFlatStatement : public file::OStatement
+ {
+ protected:
+ virtual rtl::Reference<file::OResultSet> createResultSet() override;
+ public:
+ OFlatStatement( file::OConnection* _pConnection) : file::OStatement( _pConnection){}
+ DECLARE_SERVICE_INFO();
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/flat/ETable.hxx b/connectivity/source/inc/flat/ETable.hxx
new file mode 100644
index 0000000000..99359edfdd
--- /dev/null
+++ b/connectivity/source/inc/flat/ETable.hxx
@@ -0,0 +1,100 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <file/FTable.hxx>
+#include <flat/EConnection.hxx>
+#include <connectivity/CommonTools.hxx>
+#include <file/quotedstring.hxx>
+#include <unotools/syslocale.hxx>
+#include <com/sun/star/util/XNumberFormatter.hpp>
+
+namespace connectivity::flat
+ {
+ typedef file::OFileTable OFlatTable_BASE;
+ class OFlatConnection;
+
+ typedef std::pair<sal_Int32, sal_Int32> TRowPositionInFile;
+
+ class OFlatTable : public OFlatTable_BASE
+ {
+ // maps a row position to a file position
+ // row n is positions [m_aRowPosToFilePos[n]->first, m_aRowPosToFilePos[n]->second) in file
+ // "real" row indexes start at 1; for the purposes of m_aRowPosToFilePos, row 0 is headers
+ std::vector<TRowPositionInFile>
+ m_aRowPosToFilePos;
+ std::vector<sal_Int32> m_aTypes; // holds all type for columns just to avoid to ask the propertyset
+ std::vector<sal_Int32> m_aPrecisions; // same as aboth
+ std::vector<sal_Int32> m_aScales;
+ QuotedTokenizedString m_aCurrentLine;
+ css::uno::Reference< css::util::XNumberFormatter > m_xNumberFormatter;
+ css::util::Date m_aNullDate;
+ sal_Int32 m_nRowPos;
+ sal_Int32 m_nMaxRowCount; // will be set if stream is once eof
+ sal_Unicode m_cStringDelimiter; // delimiter for strings m_cStringDelimiter blabla m_cStringDelimiter
+ sal_Unicode m_cFieldDelimiter; // look at the name
+ bool m_bNeedToReadLine;
+ private:
+ void fillColumns(const css::lang::Locale& _aLocale);
+ bool readLine(sal_Int32 *pEndPos, sal_Int32 *pStartPos, bool nonEmpty = false);
+ void setRowPos(std::vector<TRowPositionInFile>::size_type rowNum, const TRowPositionInFile &rowPos);
+ void impl_fillColumnInfo_nothrow(QuotedTokenizedString const & aFirstLine, sal_Int32& nStartPosFirstLine, sal_Int32& nStartPosFirstLine2,
+ sal_Int32& io_nType, sal_Int32& io_nPrecisions, sal_Int32& io_nScales, OUString& o_sTypeName,
+ const sal_Unicode cDecimalDelimiter, const sal_Unicode cThousandDelimiter, const CharClass& aCharClass);
+ OFlatConnection* getFlatConnection()
+ {
+#if OSL_DEBUG_LEVEL > 0
+ OFlatConnection* pConnection = dynamic_cast<OFlatConnection*>(m_pConnection);
+ assert(pConnection);
+#else
+ OFlatConnection* pConnection = static_cast<OFlatConnection*>(m_pConnection);
+#endif
+ return pConnection;
+ }
+ public:
+ virtual void refreshColumns() override;
+
+ public:
+ // DECLARE_CTY_DEFAULTS( OFlatTable_BASE);
+ OFlatTable( sdbcx::OCollection* _pTables,OFlatConnection* _pConnection,
+ const OUString& Name,
+ const OUString& Type,
+ const OUString& Description = OUString(),
+ const OUString& SchemaName = OUString(),
+ const OUString& CatalogName = OUString()
+ );
+
+ void construct() override; // can throw any exception
+
+ virtual bool seekRow(IResultSetHelper::Movement eCursorPosition, sal_Int32 nOffset, sal_Int32& nCurPos) override;
+ virtual bool fetchRow(OValueRefRow& _rRow, const OSQLColumns& _rCols, bool bRetrieveData) override;
+ virtual void refreshHeader() override;
+
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ //XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override;
+ virtual void SAL_CALL disposing() override;
+
+ OUString getEntry() const;
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/flat/ETables.hxx b/connectivity/source/inc/flat/ETables.hxx
new file mode 100644
index 0000000000..cb9b032dbc
--- /dev/null
+++ b/connectivity/source/inc/flat/ETables.hxx
@@ -0,0 +1,40 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <file/FTables.hxx>
+
+namespace connectivity::flat
+ {
+ typedef file::OTables OFlatTables_BASE;
+
+ class OFlatTables : public OFlatTables_BASE
+ {
+ protected:
+ virtual sdbcx::ObjectType createObject(const OUString& _rName) override;
+ public:
+ OFlatTables(const css::uno::Reference< css::sdbc::XDatabaseMetaData >& _rMetaData,::cppu::OWeakObject& _rParent, ::osl::Mutex& _rMutex,
+ const ::std::vector< OUString> &_rVector) : OFlatTables_BASE(_rMetaData,_rParent,_rMutex,_rVector)
+ {}
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/hsqldb/HCatalog.hxx b/connectivity/source/inc/hsqldb/HCatalog.hxx
new file mode 100644
index 0000000000..8d1da42de1
--- /dev/null
+++ b/connectivity/source/inc/hsqldb/HCatalog.hxx
@@ -0,0 +1,60 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <sdbcx/VCatalog.hxx>
+
+namespace connectivity::hsqldb
+ {
+ // please don't name the class the same name as in another namespaces
+ // some compilers have problems with this task as I noticed on windows
+ class OHCatalog : public connectivity::sdbcx::OCatalog
+ {
+ css::uno::Reference< css::sdbc::XConnection > m_xConnection;
+
+ /** calls XDatabaseMetaData::getTables.
+ @param _sKindOfObject
+ The type of tables to be fetched.
+ @param _rNames
+ The container for the names to be filled.
+ */
+ void refreshObjects(const css::uno::Sequence< OUString >& _sKindOfObject,::std::vector< OUString>& _rNames);
+
+ public:
+ // implementation of the pure virtual methods
+ virtual void refreshTables() override;
+ virtual void refreshViews() override ;
+ virtual void refreshGroups() override;
+ virtual void refreshUsers() override ;
+
+ public:
+ OHCatalog(const css::uno::Reference< css::sdbc::XConnection >& _xConnection);
+
+ sdbcx::OCollection* getPrivateTables() const { return m_pTables.get(); }
+ sdbcx::OCollection* getPrivateViews() const { return m_pViews.get(); }
+ const css::uno::Reference< css::sdbc::XConnection >& getConnection() const { return m_xConnection; }
+
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ // ::cppu::OComponentHelper
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override;
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/hsqldb/HColumns.hxx b/connectivity/source/inc/hsqldb/HColumns.hxx
new file mode 100644
index 0000000000..c27645f458
--- /dev/null
+++ b/connectivity/source/inc/hsqldb/HColumns.hxx
@@ -0,0 +1,56 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+#include <connectivity/TColumnsHelper.hxx>
+#include <connectivity/sdbcx/VColumn.hxx>
+
+namespace connectivity::hsqldb
+ {
+ class OHSQLColumns : public OColumnsHelper
+ {
+ protected:
+ virtual css::uno::Reference< css::beans::XPropertySet > createDescriptor() override;
+ public:
+ OHSQLColumns( ::cppu::OWeakObject& _rParent
+ ,::osl::Mutex& _rMutex
+ ,const ::std::vector< OUString> &_rVector
+ );
+ };
+
+ class OHSQLColumn;
+ typedef ::comphelper::OIdPropertyArrayUsageHelper<OHSQLColumn> OHSQLColumn_PROP;
+
+ class OHSQLColumn : public sdbcx::OColumn,
+ public OHSQLColumn_PROP
+ {
+ OUString m_sAutoIncrement;
+ protected:
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper( sal_Int32 _nId) const override;
+ virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override;
+
+ public:
+ OHSQLColumn();
+ virtual void construct() override;
+
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/hsqldb/HConnection.hxx b/connectivity/source/inc/hsqldb/HConnection.hxx
new file mode 100644
index 0000000000..6e2a54c9ce
--- /dev/null
+++ b/connectivity/source/inc/hsqldb/HConnection.hxx
@@ -0,0 +1,142 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <connectivity/ConnectionWrapper.hxx>
+#include <com/sun/star/util/XFlushable.hpp>
+#include <com/sun/star/sdbc/XDriver.hpp>
+#include <com/sun/star/sdb/application/XTableUIProvider.hpp>
+#include <cppuhelper/compbase.hxx>
+#include <cppuhelper/basemutex.hxx>
+#include <comphelper/uno3.hxx>
+#include <comphelper/interfacecontainer2.hxx>
+
+namespace connectivity::hsqldb
+ {
+ class SAL_NO_VTABLE IMethodGuardAccess
+ {
+ public:
+ virtual ::osl::Mutex& getMutex() const = 0;
+ virtual void checkDisposed() const = 0;
+
+ protected:
+ ~IMethodGuardAccess() {}
+ };
+
+
+ // OHsqlConnection - wraps all methods to the real connection from the driver
+ // but when disposed it doesn't dispose the real connection
+
+ typedef ::cppu::WeakComponentImplHelper< css::util::XFlushable
+ , css::sdb::application::XTableUIProvider
+ > OHsqlConnection_BASE;
+
+ class OHsqlConnection :public cppu::BaseMutex
+ ,public OHsqlConnection_BASE
+ ,public OConnectionWrapper
+ ,public IMethodGuardAccess
+ {
+ private:
+ ::comphelper::OInterfaceContainerHelper2 m_aFlushListeners;
+ css::uno::Reference< css::sdbc::XDriver > m_xDriver;
+ css::uno::Reference< css::uno::XComponentContext > m_xContext;
+ bool m_bIni;
+ bool m_bReadOnly;
+
+ protected:
+ virtual void SAL_CALL disposing() override;
+ virtual ~OHsqlConnection() override;
+
+ public:
+ OHsqlConnection(
+ const css::uno::Reference< css::sdbc::XDriver >& _rxDriver,
+ const css::uno::Reference< css::sdbc::XConnection >& _xConnection,
+ const css::uno::Reference< css::uno::XComponentContext>& _rxContext
+ );
+
+ // XServiceInfo
+ DECLARE_SERVICE_INFO();
+ DECLARE_XTYPEPROVIDER()
+ DECLARE_XINTERFACE( )
+
+ // IMethodGuardAccess
+ virtual ::osl::Mutex& getMutex() const override;
+ virtual void checkDisposed() const override;
+
+ // XFlushable
+ virtual void SAL_CALL flush( ) override;
+ virtual void SAL_CALL addFlushListener( const css::uno::Reference< css::util::XFlushListener >& l ) override;
+ virtual void SAL_CALL removeFlushListener( const css::uno::Reference< css::util::XFlushListener >& l ) override;
+
+ // XTableUIProvider
+ virtual css::uno::Reference< css::graphic::XGraphic > SAL_CALL getTableIcon( const OUString& TableName, ::sal_Int32 ColorMode ) override;
+ virtual css::uno::Reference< css::uno::XInterface > SAL_CALL getTableEditor( const css::uno::Reference< css::sdb::application::XDatabaseDocumentUI >& DocumentUI, const OUString& TableName ) override;
+
+ private:
+
+ /** retrieves our table container
+ @return
+ our table container. Guaranteed to not be <NULL/>.
+ @throws css::lang::WrappedTargetException
+ if a non-RuntimeException is caught during obtaining the container.
+ @throws css::uno::RuntimeException
+ if a serious error occurs
+ @precond
+ We're not disposed.
+ */
+ css::uno::Reference< css::container::XNameAccess >
+ impl_getTableContainer_throw();
+
+ /** checks whether the given table name denotes an existing table
+ @param _rTableName
+ the fully name of the table to check for existence
+ @throws css::lang::IllegalArgumentException
+ if the name does not denote an existing table
+ @precond
+ We're not disposed.
+ */
+ void impl_checkExistingTable_throw( const OUString& _rTableName );
+
+ /** checks whether the given table name refers to a HSQL TEXT TABLE
+ */
+ bool impl_isTextTable_nothrow( const OUString& _rTableName );
+
+ /** retrieves the icon for HSQL TEXT TABLEs
+ */
+ css::uno::Reference< css::graphic::XGraphic >
+ impl_getTextTableIcon_nothrow();
+ };
+
+
+ // OHsqlConnection
+
+ class MethodGuard : public ::osl::MutexGuard
+ {
+ public:
+ MethodGuard( const IMethodGuardAccess& _rComponent )
+ : ::osl::MutexGuard( _rComponent.getMutex() )
+ {
+ _rComponent.checkDisposed();
+ }
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/hsqldb/HDriver.hxx b/connectivity/source/inc/hsqldb/HDriver.hxx
new file mode 100644
index 0000000000..0dda7e5e0f
--- /dev/null
+++ b/connectivity/source/inc/hsqldb/HDriver.hxx
@@ -0,0 +1,123 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <com/sun/star/sdbc/XDriver.hpp>
+#include <com/sun/star/sdbcx/XDataDefinitionSupplier.hpp>
+#include <com/sun/star/sdbcx/XCreateCatalog.hpp>
+#include <com/sun/star/embed/XTransactionListener.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <cppuhelper/compbase.hxx>
+#include <cppuhelper/basemutex.hxx>
+#include <connectivity/CommonTools.hxx>
+
+
+namespace connectivity::hsqldb
+ {
+ typedef ::cppu::WeakComponentImplHelper< css::sdbc::XDriver
+ , css::sdbcx::XDataDefinitionSupplier
+ , css::lang::XServiceInfo
+ , css::sdbcx::XCreateCatalog
+ , css::embed::XTransactionListener
+ > ODriverDelegator_BASE;
+
+ typedef std::pair< css::uno::WeakReferenceHelper,css::uno::WeakReferenceHelper> TWeakRefPair;
+ typedef std::pair< OUString ,TWeakRefPair > TWeakConnectionPair;
+
+ typedef std::pair< css::uno::WeakReferenceHelper,TWeakConnectionPair> TWeakPair;
+ typedef std::vector< TWeakPair > TWeakPairVector;
+
+
+ /** delegates all calls to the original driver and extend the existing one with the SDBCX layer.
+
+ */
+ class ODriverDelegator final : public ::cppu::BaseMutex
+ ,public ODriverDelegator_BASE
+ {
+ TWeakPairVector m_aConnections; // vector containing a list
+ // of all the Connection objects
+ // for this Driver
+ css::uno::Reference< css::sdbc::XDriver > m_xDriver;
+ css::uno::Reference< css::uno::XComponentContext > m_xContext;
+ bool m_bInShutDownConnections;
+
+ /** load the driver we want to delegate.
+ The <member>m_xDriver</member> may be <NULL/> if the driver could not be loaded.
+ @return
+ The driver which was currently selected.
+ */
+ css::uno::Reference< css::sdbc::XDriver > const & loadDriver( );
+
+ /** shut down the connection and revoke the storage from the map
+ @param _aIter
+ The connection to shut down and storage to revoke.
+ */
+ void shutdownConnection(const TWeakPairVector::iterator& _aIter);
+
+ public:
+ /** creates a new delegator for a HSQLDB driver
+ */
+ ODriverDelegator(const css::uno::Reference< css::uno::XComponentContext >& _rxContext);
+
+ // XServiceInfo
+ DECLARE_SERVICE_INFO();
+
+ // XDriver
+ virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL connect( const OUString& url, const css::uno::Sequence< css::beans::PropertyValue >& info ) override;
+ virtual sal_Bool SAL_CALL acceptsURL( const OUString& url ) override;
+ virtual css::uno::Sequence< css::sdbc::DriverPropertyInfo > SAL_CALL getPropertyInfo( const OUString& url, const css::uno::Sequence< css::beans::PropertyValue >& info ) override;
+ virtual sal_Int32 SAL_CALL getMajorVersion( ) override;
+ virtual sal_Int32 SAL_CALL getMinorVersion( ) override;
+
+ // XDataDefinitionSupplier
+ virtual css::uno::Reference< css::sdbcx::XTablesSupplier > SAL_CALL getDataDefinitionByConnection( const css::uno::Reference< css::sdbc::XConnection >& connection ) override;
+ virtual css::uno::Reference< css::sdbcx::XTablesSupplier > SAL_CALL getDataDefinitionByURL( const OUString& url, const css::uno::Sequence< css::beans::PropertyValue >& info ) override;
+
+ // XCreateCatalog
+ virtual void SAL_CALL createCatalog( const css::uno::Sequence< css::beans::PropertyValue >& info ) override;
+
+ // XEventListener
+ virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override;
+
+ // XTransactionListener
+ virtual void SAL_CALL preCommit( const css::lang::EventObject& aEvent ) override;
+ virtual void SAL_CALL commited( const css::lang::EventObject& aEvent ) override;
+ virtual void SAL_CALL preRevert( const css::lang::EventObject& aEvent ) override;
+ virtual void SAL_CALL reverted( const css::lang::EventObject& aEvent ) override;
+
+ void shutdownConnections();
+ void flushConnections();
+ private:
+ /// dtor
+ virtual ~ODriverDelegator() override;
+ // OComponentHelper
+ virtual void SAL_CALL disposing() override;
+
+ /** called when we connected to a newly created embedded database
+ */
+ void onConnectedNewDatabase(
+ const css::uno::Reference< css::sdbc::XConnection >& _rxConnection
+ );
+ };
+
+
+} // namespace connectivity::hsqldb
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/hsqldb/HStorageAccess.hxx b/connectivity/source/inc/hsqldb/HStorageAccess.hxx
new file mode 100644
index 0000000000..5a49162c2e
--- /dev/null
+++ b/connectivity/source/inc/hsqldb/HStorageAccess.hxx
@@ -0,0 +1,43 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#if defined __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunknown-attributes"
+#endif
+#include <jni.h>
+#if defined __clang__
+#pragma clang diagnostic pop
+#endif
+
+namespace connectivity::hsqldb
+{
+ class DataLogFile;
+}
+
+jint read_from_storage_stream( JNIEnv * env, jstring name, jstring key );
+jint read_from_storage_stream_into_buffer( JNIEnv * env, jstring name, jstring key, jbyteArray buffer, jint off, jint len );
+void write_to_storage_stream_from_buffer( JNIEnv* env, jstring name, jstring key, jbyteArray buffer, jint off, jint len );
+void write_to_storage_stream( JNIEnv* env, jstring name, jstring key, jint v );
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/hsqldb/HStorageMap.hxx b/connectivity/source/inc/hsqldb/HStorageMap.hxx
new file mode 100644
index 0000000000..1186c680ac
--- /dev/null
+++ b/connectivity/source/inc/hsqldb/HStorageMap.hxx
@@ -0,0 +1,97 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <sal/config.h>
+
+#include <map>
+#include <memory>
+
+#include <com/sun/star/embed/XStorage.hpp>
+#include <com/sun/star/embed/XTransactionListener.hpp>
+#include <com/sun/star/io/XStream.hpp>
+#include <com/sun/star/io/XOutputStream.hpp>
+#include <com/sun/star/io/XInputStream.hpp>
+#include <com/sun/star/io/XSeekable.hpp>
+
+#if defined __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunknown-attributes"
+#endif
+#include <jni.h>
+#if defined __clang__
+#pragma clang diagnostic pop
+#endif
+
+#include <uno/environment.hxx>
+
+namespace connectivity::hsqldb
+ {
+ class StreamHelper
+ {
+ css::uno::Reference< css::io::XStream> m_xStream;
+ css::uno::Reference< css::io::XSeekable> m_xSeek;
+ css::uno::Reference< css::io::XOutputStream> m_xOutputStream;
+ css::uno::Reference< css::io::XInputStream> m_xInputStream;
+ public:
+ StreamHelper(const css::uno::Reference< css::io::XStream>& _xStream);
+ ~StreamHelper();
+
+ css::uno::Reference< css::io::XInputStream> const & getInputStream();
+ css::uno::Reference< css::io::XOutputStream> const & getOutputStream();
+ css::uno::Reference< css::io::XSeekable> const & getSeek();
+ };
+
+
+ typedef std::map< OUString, std::shared_ptr<StreamHelper> > TStreamMap;
+
+ struct StorageData {
+ css::uno::Reference<css::embed::XStorage> storage;
+ css::uno::Environment storageEnvironment;
+ OUString url;
+ TStreamMap streams;
+
+ css::uno::Reference<css::embed::XStorage> mapStorage() const;
+ };
+
+ typedef std::map<OUString, StorageData> TStorages;
+ /** contains all storages so far accessed.
+ */
+ class StorageContainer
+ {
+ public:
+ static OUString registerStorage(const css::uno::Reference< css::embed::XStorage>& _xStorage,const OUString& _sURL);
+ static TStorages::mapped_type getRegisteredStorage(const OUString& _sKey);
+ static OUString getRegisteredKey(const css::uno::Reference< css::embed::XStorage>& _xStorage);
+ static void revokeStorage(const OUString& _sKey,const css::uno::Reference< css::embed::XTransactionListener>& _xListener);
+
+ static TStreamMap::mapped_type registerStream(JNIEnv * env,jstring name, jstring key,sal_Int32 _nMode);
+ static void revokeStream(JNIEnv * env,jstring name, jstring key);
+ static TStreamMap::mapped_type getRegisteredStream( JNIEnv * env, jstring name, jstring key);
+
+ static OUString jstring2ustring(JNIEnv * env, jstring jstr);
+ static OUString removeURLPrefix(std::u16string_view _sURL, std::u16string_view _sFileURL);
+ static OUString removeOldURLPrefix(const OUString& _sURL);
+ static void throwJavaException(const css::uno::Exception& _aException,JNIEnv * env);
+ };
+
+} // namespace connectivity::hsqldb
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/hsqldb/HTable.hxx b/connectivity/source/inc/hsqldb/HTable.hxx
new file mode 100644
index 0000000000..d6ac5ced76
--- /dev/null
+++ b/connectivity/source/inc/hsqldb/HTable.hxx
@@ -0,0 +1,112 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <string_view>
+
+#include <connectivity/TTableHelper.hxx>
+#include <comphelper/IdPropArrayHelper.hxx>
+
+namespace connectivity::hsqldb
+ {
+
+ class OHSQLTable;
+ typedef ::comphelper::OIdPropertyArrayUsageHelper< OHSQLTable > OHSQLTable_PROP;
+ class OHSQLTable : public OTableHelper
+ ,public OHSQLTable_PROP
+ {
+ sal_Int32 m_nPrivileges; // we have to set our privileges by our own
+
+ /** executes the statement.
+ @param _rStatement
+ The statement to execute.
+ */
+ void executeStatement(const OUString& _rStatement );
+ protected:
+
+ /** creates the column collection for the table
+ @param _rNames
+ The column names.
+ */
+ virtual sdbcx::OCollection* createColumns(const ::std::vector< OUString>& _rNames) override;
+
+ /** creates the key collection for the table
+ @param _rNames
+ The key names.
+ */
+ virtual sdbcx::OCollection* createKeys(const ::std::vector< OUString>& _rNames) override;
+
+ /** creates the index collection for the table
+ @param _rNames
+ The index names.
+ */
+ virtual sdbcx::OCollection* createIndexes(const ::std::vector< OUString>& _rNames) override;
+
+ /** used to implement the creation of the array helper which is shared amongst all instances of the class.
+ This method needs to be implemented in derived classes.
+ <BR>
+ The method gets called with s_aMutex acquired.
+ @return a pointer to the newly created array helper. Must not be NULL.
+ */
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper(sal_Int32 nId) const override;
+ virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override;
+
+ public:
+ OHSQLTable( sdbcx::OCollection* _pTables,
+ const css::uno::Reference< css::sdbc::XConnection >& _xConnection);
+ OHSQLTable( sdbcx::OCollection* _pTables,
+ const css::uno::Reference< css::sdbc::XConnection >& _xConnection,
+ const OUString& Name,
+ const OUString& Type,
+ const OUString& Description,
+ const OUString& SchemaName,
+ const OUString& CatalogName,
+ sal_Int32 _nPrivileges
+ );
+
+ // ODescriptor
+ virtual void construct() override;
+
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ //XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override;
+ // XAlterTable
+ virtual void SAL_CALL alterColumnByName( const OUString& colName, const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override;
+
+ // XRename
+ virtual void SAL_CALL rename( const OUString& newName ) override;
+
+ /**
+ returns the ALTER TABLE XXX COLUMN statement
+ */
+ OUString getAlterTableColumnPart() const;
+
+ // some methods to alter table structures
+ void alterColumnType(sal_Int32 nNewType,const OUString& _rColName,const css::uno::Reference< css::beans::XPropertySet >& _xDescriptor);
+ void alterDefaultValue(std::u16string_view _sNewDefault,const OUString& _rColName);
+ void dropDefaultValue(const OUString& _sNewDefault);
+
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/hsqldb/HTables.hxx b/connectivity/source/inc/hsqldb/HTables.hxx
new file mode 100644
index 0000000000..bff5e0e642
--- /dev/null
+++ b/connectivity/source/inc/hsqldb/HTables.hxx
@@ -0,0 +1,53 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <connectivity/sdbcx/VCollection.hxx>
+#include <com/sun/star/sdbc/XDatabaseMetaData.hpp>
+#include <utility>
+namespace connectivity::hsqldb
+ {
+ class OTables final : public sdbcx::OCollection
+ {
+ css::uno::Reference< css::sdbc::XDatabaseMetaData > m_xMetaData;
+
+ virtual sdbcx::ObjectType createObject(const OUString& _rName) override;
+ virtual void impl_refresh() override;
+ virtual css::uno::Reference< css::beans::XPropertySet > createDescriptor() override;
+ virtual sdbcx::ObjectType appendObject( const OUString& _rForName, const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override;
+ virtual void dropObject(sal_Int32 _nPos, const OUString& _sElementName) override;
+
+ void createTable( const css::uno::Reference< css::beans::XPropertySet >& descriptor );
+ virtual OUString getNameForObject(const sdbcx::ObjectType& _xObject) override;
+ public:
+ OTables(css::uno::Reference< css::sdbc::XDatabaseMetaData > _xMetaData, ::cppu::OWeakObject& _rParent, ::osl::Mutex& _rMutex,
+ const ::std::vector< OUString> &_rVector) : sdbcx::OCollection(_rParent, true, _rMutex, _rVector)
+ ,m_xMetaData(std::move(_xMetaData))
+ {}
+
+ // only the name is identical to ::cppu::OComponentHelper
+ virtual void disposing() override;
+
+ // XDrop
+ void appendNew(const OUString& _rsNewTable);
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/hsqldb/HTools.hxx b/connectivity/source/inc/hsqldb/HTools.hxx
new file mode 100644
index 0000000000..a847b2d9a5
--- /dev/null
+++ b/connectivity/source/inc/hsqldb/HTools.hxx
@@ -0,0 +1,49 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <rtl/ustrbuf.hxx>
+
+
+namespace connectivity::hsqldb
+{
+
+ class HTools
+ {
+ public:
+ /** appends a proper WHERE clause to the given buffer, which filters
+ for a given table name
+
+ @param _bShortForm
+ <TRUE/> if the column names of the system table which is being asked
+ have the short form (TABLE_CAT instead of TABLE_CATALOG, and so on)
+ */
+ static void appendTableFilterCrit(
+ OUStringBuffer& _inout_rBuffer, std::u16string_view _rCatalog,
+ std::u16string_view _rSchema, std::u16string_view _rName,
+ bool _bShortForm
+ );
+ };
+
+
+} // namespace connectivity::hsqldb
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/hsqldb/HUser.hxx b/connectivity/source/inc/hsqldb/HUser.hxx
new file mode 100644
index 0000000000..67c44e185b
--- /dev/null
+++ b/connectivity/source/inc/hsqldb/HUser.hxx
@@ -0,0 +1,73 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sdbcx/VUser.hxx>
+#include <com/sun/star/sdbc/XConnection.hpp>
+
+namespace connectivity::hsqldb
+ {
+ typedef connectivity::sdbcx::OUser OUser_TYPEDEF;
+
+ class OHSQLUser : public OUser_TYPEDEF
+ {
+ css::uno::Reference< css::sdbc::XConnection > m_xConnection;
+
+ static OUString getPrivilegeString(sal_Int32 nRights);
+ // return the privileges and additional the grant rights
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void findPrivilegesAndGrantPrivileges(const OUString& objName, sal_Int32 objType,sal_Int32& nRights,sal_Int32& nRightsWithGrant);
+ public:
+ virtual void refreshGroups() override;
+ public:
+ OHSQLUser( css::uno::Reference< css::sdbc::XConnection > _xConnection);
+ OHSQLUser( css::uno::Reference< css::sdbc::XConnection > _xConnection, const OUString& Name);
+
+ // XUser
+ virtual void SAL_CALL changePassword( const OUString& objPassword, const OUString& newPassword ) override;
+ // XAuthorizable
+ virtual sal_Int32 SAL_CALL getPrivileges( const OUString& objName, sal_Int32 objType ) override;
+ virtual sal_Int32 SAL_CALL getGrantablePrivileges( const OUString& objName, sal_Int32 objType ) override;
+ virtual void SAL_CALL grantPrivileges( const OUString& objName, sal_Int32 objType, sal_Int32 objPrivileges ) override;
+ virtual void SAL_CALL revokePrivileges( const OUString& objName, sal_Int32 objType, sal_Int32 objPrivileges ) override;
+ };
+
+ class OUserExtend;
+ typedef ::comphelper::OPropertyArrayUsageHelper<OUserExtend> OUserExtend_PROP;
+
+ class OUserExtend : public OHSQLUser,
+ public OUserExtend_PROP
+ {
+ OUString m_Password;
+ protected:
+ // OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper() const override;
+ // OPropertySetHelper
+ virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override;
+ public:
+ OUserExtend(const css::uno::Reference< css::sdbc::XConnection >& _xConnection);
+
+ virtual void construct() override;
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/hsqldb/HUsers.hxx b/connectivity/source/inc/hsqldb/HUsers.hxx
new file mode 100644
index 0000000000..a5a099e992
--- /dev/null
+++ b/connectivity/source/inc/hsqldb/HUsers.hxx
@@ -0,0 +1,52 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <connectivity/sdbcx/VCollection.hxx>
+#include <com/sun/star/sdbc/XConnection.hpp>
+namespace connectivity
+{
+ namespace sdbcx
+ {
+ class IRefreshableUsers;
+ }
+ namespace hsqldb
+ {
+ class OUsers : public sdbcx::OCollection
+ {
+ css::uno::Reference< css::sdbc::XConnection > m_xConnection;
+ connectivity::sdbcx::IRefreshableUsers* m_pParent;
+ public:
+ virtual sdbcx::ObjectType createObject(const OUString& _rName) override;
+ virtual css::uno::Reference< css::beans::XPropertySet > createDescriptor() override;
+ virtual void impl_refresh() override;
+ virtual sdbcx::ObjectType appendObject( const OUString& _rForName, const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override;
+ virtual void dropObject(sal_Int32 _nPos, const OUString& _sElementName) override;
+ public:
+ OUsers( ::cppu::OWeakObject& _rParent,
+ ::osl::Mutex& _rMutex,
+ const ::std::vector< OUString> &_rVector,
+ css::uno::Reference< css::sdbc::XConnection > _xConnection,
+ connectivity::sdbcx::IRefreshableUsers* _pParent);
+ };
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/hsqldb/HView.hxx b/connectivity/source/inc/hsqldb/HView.hxx
new file mode 100644
index 0000000000..62e8e5f456
--- /dev/null
+++ b/connectivity/source/inc/hsqldb/HView.hxx
@@ -0,0 +1,88 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <connectivity/sdbcx/VView.hxx>
+
+#include <com/sun/star/sdbcx/XAlterView.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+
+#include <comphelper/uno3.hxx>
+#include <cppuhelper/implbase1.hxx>
+
+
+namespace connectivity::hsqldb
+{
+
+ typedef ::connectivity::sdbcx::OView HView_Base;
+ typedef ::cppu::ImplHelper1< css::sdbcx::XAlterView > HView_IBASE;
+ class HView :public HView_Base
+ ,public HView_IBASE
+ {
+ public:
+ HView(
+ const css::uno::Reference< css::sdbc::XConnection >& _rxConnection,
+ bool _bCaseSensitive,
+ const OUString& _rSchemaName,
+ const OUString& _rName
+ );
+
+ // UNO
+ DECLARE_XINTERFACE()
+ DECLARE_XTYPEPROVIDER()
+
+ // XAlterView
+ virtual void SAL_CALL alterCommand( const OUString& NewCommand ) override;
+
+ protected:
+ virtual ~HView() override;
+
+ protected:
+ // OPropertyContainer
+ virtual void SAL_CALL getFastPropertyValue( css::uno::Any& _rValue, sal_Int32 _nHandle ) const override;
+
+ private:
+ /** retrieves the current command of the View */
+ OUString impl_getCommand() const;
+
+ /** retrieves the current command of the View
+
+ @throws css::lang::WrappedTargetException
+ if an error occurs while retrieving the command from the database.
+ */
+ OUString impl_getCommand_wrapSQLException() const;
+ /** retrieves the current command of the View
+
+ @throws css::sdbc::SQLException
+ if an error occurs while retrieving the command from the database.
+ */
+ OUString impl_getCommand_throwSQLException() const;
+
+ private:
+ css::uno::Reference< css::sdbc::XConnection > m_xConnection;
+ private:
+ using HView_Base::getFastPropertyValue;
+ };
+
+
+} // namespace connectivity::hsqldb
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/hsqldb/HViews.hxx b/connectivity/source/inc/hsqldb/HViews.hxx
new file mode 100644
index 0000000000..cb2041524e
--- /dev/null
+++ b/connectivity/source/inc/hsqldb/HViews.hxx
@@ -0,0 +1,51 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <connectivity/sdbcx/VCollection.hxx>
+#include <com/sun/star/sdbc/XDatabaseMetaData.hpp>
+namespace connectivity::hsqldb
+ {
+ class HViews final : public sdbcx::OCollection
+ {
+ css::uno::Reference< css::sdbc::XConnection > m_xConnection;
+ css::uno::Reference< css::sdbc::XDatabaseMetaData > m_xMetaData;
+ bool m_bInDrop;
+
+ virtual sdbcx::ObjectType createObject(const OUString& _rName) override;
+ virtual void impl_refresh() override;
+ virtual css::uno::Reference< css::beans::XPropertySet > createDescriptor() override;
+ virtual sdbcx::ObjectType appendObject( const OUString& _rForName, const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override;
+ virtual void dropObject(sal_Int32 _nPos, const OUString& _sElementName) override;
+
+ void createView( const css::uno::Reference< css::beans::XPropertySet >& descriptor );
+ public:
+ HViews(
+ const css::uno::Reference< css::sdbc::XConnection >& _rxConnection,
+ ::cppu::OWeakObject& _rParent, ::osl::Mutex& _rMutex, const ::std::vector< OUString> &_rVector );
+
+ // only the name is identical to ::cppu::OComponentHelper
+ virtual void disposing() override;
+
+ void dropByNameImpl(const OUString& elementName);
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/java/ContextClassLoader.hxx b/connectivity/source/inc/java/ContextClassLoader.hxx
new file mode 100644
index 0000000000..e7079239aa
--- /dev/null
+++ b/connectivity/source/inc/java/ContextClassLoader.hxx
@@ -0,0 +1,79 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <java/GlobalRef.hxx>
+
+namespace comphelper
+{
+ class EventLogger;
+}
+
+
+namespace connectivity::jdbc
+{
+ class ContextClassLoaderScope
+ {
+ public:
+ /** creates the instance. If isActive returns <FALSE/> afterwards, then an exception
+ happened in the JVM, which should be raised as UNO exception by the caller
+
+ @param environment
+ the current JNI environment
+ @param newClassLoader
+ the new class loader to set at the current thread
+ @param _rLoggerForErrors
+ the logger which should be passed to java_lang_object::ThrowLoggedSQLException in case
+ an error occurs
+ @param _rxErrorContext
+ the context which should be passed to java_lang_object::ThrowLoggedSQLException in case
+ an error occurs
+
+ */
+ ContextClassLoaderScope(
+ JNIEnv& environment,
+ const GlobalRef< jobject >& newClassLoader,
+ const ::comphelper::EventLogger& _rLoggerForErrors,
+ const css::uno::Reference< css::uno::XInterface >& _rxErrorContext
+ );
+
+ ~ContextClassLoaderScope();
+
+ bool isActive() const
+ {
+ return ( m_currentThread.is() )
+ && ( m_setContextClassLoaderMethod != nullptr );
+ }
+
+ private:
+ ContextClassLoaderScope(ContextClassLoaderScope const &) = delete;
+ ContextClassLoaderScope& operator =(ContextClassLoaderScope const &) = delete;
+
+ JNIEnv& m_environment;
+ LocalRef< jobject > m_currentThread;
+ LocalRef< jobject > m_oldContextClassLoader;
+ jmethodID m_setContextClassLoaderMethod;
+ };
+
+
+} // namespace connectivity::jdbc
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/java/GlobalRef.hxx b/connectivity/source/inc/java/GlobalRef.hxx
new file mode 100644
index 0000000000..1a97bfb33a
--- /dev/null
+++ b/connectivity/source/inc/java/GlobalRef.hxx
@@ -0,0 +1,102 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <java/LocalRef.hxx>
+#include <java/lang/Object.hxx>
+
+
+namespace connectivity::jdbc
+{
+ /** helper class to hold a local ref to a JNI object
+ */
+ template< typename T >
+ class GlobalRef
+ {
+ public:
+ GlobalRef()
+ :m_object( nullptr )
+ {
+ }
+
+ GlobalRef( const GlobalRef& _source )
+ :m_object( nullptr )
+ {
+ *this = _source;
+ }
+
+ GlobalRef& operator=( const GlobalRef& _source )
+ {
+ if ( &_source == this )
+ return *this;
+
+ SDBThreadAttach t;
+ set( t.env(), _source.get() );
+ return *this;
+ }
+
+ ~GlobalRef() COVERITY_NOEXCEPT_FALSE
+ {
+ reset();
+ }
+
+ void reset()
+ {
+ if ( m_object != nullptr )
+ {
+ SDBThreadAttach t;
+ t.env().DeleteGlobalRef( m_object );
+ m_object = nullptr;
+ }
+ }
+
+ void set( JNIEnv& _environment, T _object )
+ {
+ if ( m_object != nullptr )
+ _environment.DeleteGlobalRef( m_object );
+ m_object = _object;
+ if ( m_object )
+ m_object = static_cast< T >( _environment.NewGlobalRef( m_object ) );
+ }
+
+ void set( LocalRef< T >& _object )
+ {
+ set( _object.env(), _object.release() );
+ }
+
+ T get() const
+ {
+ return m_object;
+ }
+
+ bool is() const
+ {
+ return m_object != nullptr;
+ }
+
+ private:
+ T m_object;
+ };
+
+
+} // namespace connectivity::jdbc
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/java/LocalRef.hxx b/connectivity/source/inc/java/LocalRef.hxx
new file mode 100644
index 0000000000..ad40737f86
--- /dev/null
+++ b/connectivity/source/inc/java/LocalRef.hxx
@@ -0,0 +1,95 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#if defined __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunknown-attributes"
+#endif
+#include <jni.h>
+#if defined __clang__
+#pragma clang diagnostic pop
+#endif
+
+namespace connectivity::jdbc
+{
+
+ /** helper class to hold a local ref to a JNI object
+
+ Note that this class never actually calls NewLocalRef. It is assumed that all objects
+ passed are already acquired with a local ref (as it usually is the case if you obtain
+ the object from a JNI method).
+ */
+ template< typename T >
+ class LocalRef final
+ {
+ public:
+ explicit LocalRef( JNIEnv& environment )
+ :m_environment( environment )
+ ,m_object( nullptr )
+ {
+ }
+
+ LocalRef( JNIEnv& environment, T object )
+ :m_environment( environment )
+ ,m_object( object )
+ {
+ }
+
+ ~LocalRef()
+ {
+ reset();
+ }
+
+ T release()
+ {
+ T t = m_object;
+ m_object = nullptr;
+ return t;
+ }
+
+ void set( T object ) { reset(); m_object = object; }
+
+ void reset()
+ {
+ if ( m_object != nullptr )
+ {
+ m_environment.DeleteLocalRef( m_object );
+ m_object = nullptr;
+ }
+ }
+
+ JNIEnv& env() const { return m_environment; }
+ T get() const { return m_object; }
+ bool is() const { return m_object != nullptr; }
+
+ private:
+ LocalRef(LocalRef const &) = delete;
+ LocalRef& operator =(LocalRef const &) = delete;
+
+ JNIEnv& m_environment;
+ T m_object;
+ };
+
+
+} // namespace connectivity::jdbc
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/java/io/InputStream.hxx b/connectivity/source/inc/java/io/InputStream.hxx
new file mode 100644
index 0000000000..4a0b5788f1
--- /dev/null
+++ b/connectivity/source/inc/java/io/InputStream.hxx
@@ -0,0 +1,51 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <java/lang/Object.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <com/sun/star/io/XInputStream.hpp>
+
+namespace connectivity
+{
+
+
+ //************ Class: java.io.InputStream
+
+ class java_io_InputStream : public java_lang_Object,
+ public ::cppu::WeakImplHelper< css::io::XInputStream>
+ {
+ protected:
+ // static Data for the Class
+ static jclass theClass;
+ virtual ~java_io_InputStream() override;
+ public:
+ virtual jclass getMyClass() const override;
+ // a Constructor, that is needed for when Returning the Object is needed:
+ java_io_InputStream( JNIEnv * pEnv, jobject myObj );
+ // XInputStream
+ virtual sal_Int32 SAL_CALL readBytes( css::uno::Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead ) override;
+ virtual sal_Int32 SAL_CALL readSomeBytes( css::uno::Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead ) override;
+ virtual void SAL_CALL skipBytes( sal_Int32 nBytesToSkip ) override;
+ virtual sal_Int32 SAL_CALL available( ) override;
+ virtual void SAL_CALL closeInput( ) override;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/java/io/Reader.hxx b/connectivity/source/inc/java/io/Reader.hxx
new file mode 100644
index 0000000000..8386eda449
--- /dev/null
+++ b/connectivity/source/inc/java/io/Reader.hxx
@@ -0,0 +1,52 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <java/lang/Object.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <com/sun/star/io/XInputStream.hpp>
+#include <optional>
+
+namespace connectivity
+{
+
+ //************ Class: java.io.InputStream
+
+ class java_io_Reader final : public java_lang_Object,
+ public ::cppu::WeakImplHelper< css::io::XInputStream>
+ {
+ // static Data for the Class
+ static jclass theClass;
+ virtual ~java_io_Reader() override;
+ std::optional<char> m_buf;
+ public:
+ virtual jclass getMyClass() const override;
+ // a Constructor, that is needed for when Returning the Object is needed:
+ java_io_Reader( JNIEnv * pEnv, jobject myObj );
+ // XInputStream
+ virtual sal_Int32 SAL_CALL readBytes( css::uno::Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead ) override;
+ virtual sal_Int32 SAL_CALL readSomeBytes( css::uno::Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead ) override;
+ virtual void SAL_CALL skipBytes( sal_Int32 nBytesToSkip ) override;
+ virtual sal_Int32 SAL_CALL available( ) override;
+ virtual void SAL_CALL closeInput( ) override;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/java/lang/Boolean.hxx b/connectivity/source/inc/java/lang/Boolean.hxx
new file mode 100644
index 0000000000..536ba5de31
--- /dev/null
+++ b/connectivity/source/inc/java/lang/Boolean.hxx
@@ -0,0 +1,43 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <java/lang/Object.hxx>
+
+//************ Class: java.lang.Boolean
+
+namespace connectivity
+{
+ class java_lang_Boolean : public java_lang_Object
+ {
+ protected:
+ // static Data for the class
+ static jclass theClass;
+ public:
+ virtual jclass getMyClass() const override;
+ virtual ~java_lang_Boolean() override;
+ // a Constructor, that is needed for when Returning the Object is needed:
+ java_lang_Boolean( JNIEnv * pEnv, jobject myObj ) : java_lang_Object( pEnv, myObj ){}
+
+ static jclass st_getMyClass();
+ };
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/java/lang/Class.hxx b/connectivity/source/inc/java/lang/Class.hxx
new file mode 100644
index 0000000000..bcd5628c1d
--- /dev/null
+++ b/connectivity/source/inc/java/lang/Class.hxx
@@ -0,0 +1,49 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+//************ Class: java.lang.Class
+
+#include <sal/config.h>
+
+#include <string_view>
+
+#include <java/lang/Object.hxx>
+
+namespace connectivity
+{
+ class java_lang_Class : public java_lang_Object
+ {
+ protected:
+ // static Data for the Class
+ static jclass theClass;
+ public:
+ virtual jclass getMyClass() const override;
+ virtual ~java_lang_Class() override;
+ // a Constructor, that is needed for when Returning the Object is needed:
+ java_lang_Class( JNIEnv * pEnv, jobject myObj ) : java_lang_Object( pEnv, myObj ){}
+
+ static java_lang_Class * forName( std::u16string_view _par0 );
+ // return the jre object
+ jobject newInstanceObject();
+
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/java/lang/Exception.hxx b/connectivity/source/inc/java/lang/Exception.hxx
new file mode 100644
index 0000000000..28b2d56dc9
--- /dev/null
+++ b/connectivity/source/inc/java/lang/Exception.hxx
@@ -0,0 +1,42 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <java/lang/Throwable.hxx>
+
+namespace connectivity
+{
+
+
+ //************ Class: java.lang.Exception
+
+ class java_lang_Exception : public java_lang_Throwable{
+ protected:
+ // statis Data for the class
+ static jclass theClass;
+ public:
+ virtual jclass getMyClass() const override;
+ virtual ~java_lang_Exception() override;
+ // a Constructor, that is needed for when Returning the Object is needed:
+ java_lang_Exception( JNIEnv * pEnv, jobject myObj ) : java_lang_Throwable( pEnv, myObj ){}
+
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/java/lang/Object.hxx b/connectivity/source/inc/java/lang/Object.hxx
new file mode 100644
index 0000000000..63d7af3f59
--- /dev/null
+++ b/connectivity/source/inc/java/lang/Object.hxx
@@ -0,0 +1,147 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <jvmaccess/virtualmachine.hxx>
+
+#ifdef HAVE_64BIT_POINTERS
+#error "no 64 bit pointer"
+#endif //HAVE_64BIT_POINTERS
+
+namespace comphelper
+{
+ class EventLogger;
+}
+
+namespace connectivity
+{
+ class SDBThreadAttach
+ {
+ jvmaccess::VirtualMachine::AttachGuard m_aGuard;
+ SDBThreadAttach(SDBThreadAttach const &) = delete;
+ SDBThreadAttach& operator= (SDBThreadAttach const &) = delete;
+ public:
+ SDBThreadAttach();
+ ~SDBThreadAttach();
+
+ JNIEnv* pEnv;
+ static void addRef();
+ static void releaseRef();
+
+ public:
+ JNIEnv& env() const
+ {
+ // according to the documentation of jvmaccess::VirtualMachine::AttachGuard, our env is never
+ // NULL, so why bothering with pointer checks?
+ return *pEnv;
+ }
+ };
+
+
+ class java_lang_Object
+ {
+ java_lang_Object& operator= (java_lang_Object const &) = delete;
+ java_lang_Object(java_lang_Object const &) = delete;
+
+ protected:
+ // The Java handle to this class
+ jobject object;
+
+ // Class definition
+ // New in SJ2:
+ static jclass theClass; // The class needs to be requested only once!
+
+ virtual jclass getMyClass() const;
+
+ public:
+ // Ctor that should be used for the derived classes
+ java_lang_Object( JNIEnv * pEnv, jobject myObj );
+
+ // The actual ctor
+ java_lang_Object();
+
+ virtual ~java_lang_Object() COVERITY_NOEXCEPT_FALSE;
+
+ void saveRef( JNIEnv * pEnv, jobject myObj );
+ jobject getJavaObject() const { return object; }
+ void clearObject(JNIEnv& rEnv);
+ void clearObject();
+
+ OUString toString() const;
+
+ static void ThrowSQLException(JNIEnv * pEnv,const css::uno::Reference< css::uno::XInterface> & _rContext);
+ static void ThrowLoggedSQLException(
+ const ::comphelper::EventLogger& _rLogger,
+ JNIEnv* pEnvironment,
+ const css::uno::Reference< css::uno::XInterface >& _rxContext
+ );
+ static void ThrowRuntimeException(JNIEnv * pEnv,const css::uno::Reference< css::uno::XInterface> & _rContext);
+
+ static ::rtl::Reference< jvmaccess::VirtualMachine > getVM(const css::uno::Reference< css::uno::XComponentContext >& _rxContext=nullptr);
+
+ static jclass findMyClass(const char* _pClassName);
+ void obtainMethodId_throwSQL(JNIEnv* _pEnv, const char* _pMethodName, const char* _pSignature, jmethodID& _inout_MethodID) const;
+ void obtainMethodId_throwRuntime(JNIEnv* _pEnv, const char* _pMethodName, const char* _pSignature, jmethodID& _inout_MethodID) const;
+
+ bool callBooleanMethod( const char* _pMethodName, jmethodID& _inout_MethodID ) const;
+ bool callBooleanMethodWithIntArg( const char* _pMethodName, jmethodID& _inout_MethodID, sal_Int32 _nArgument ) const;
+ jobject callResultSetMethod( JNIEnv& _rEnv, const char* _pMethodName, jmethodID& _inout_MethodID ) const;
+ sal_Int32 callIntMethod_ThrowSQL(const char* _pMethodName, jmethodID& _inout_MethodID) const;
+ sal_Int32 callIntMethod_ThrowRuntime(const char* _pMethodName, jmethodID& _inout_MethodID) const;
+ sal_Int32 callIntMethodWithIntArg_ThrowSQL( const char* _pMethodName, jmethodID& _inout_MethodID, sal_Int32 _nArgument ) const;
+ sal_Int32 callIntMethodWithIntArg_ThrowRuntime( const char* _pMethodName, jmethodID& _inout_MethodID, sal_Int32 _nArgument ) const;
+ sal_Int32 callIntMethodWithStringArg( const char* _pMethodName, jmethodID& _inout_MethodID,const OUString& _nArgument ) const;
+ OUString callStringMethod( const char* _pMethodName, jmethodID& _inout_MethodID ) const;
+ OUString callStringMethodWithIntArg( const char* _pMethodName, jmethodID& _inout_MethodID , sal_Int32 _nArgument) const;
+ void callVoidMethod_ThrowSQL( const char* _pMethodName, jmethodID& _inout_MethodID) const;
+ void callVoidMethod_ThrowRuntime( const char* _pMethodName, jmethodID& _inout_MethodID) const;
+ void callVoidMethodWithIntArg_ThrowSQL( const char* _pMethodName, jmethodID& _inout_MethodID, sal_Int32 _nArgument ) const;
+ void callVoidMethodWithIntArg_ThrowRuntime( const char* _pMethodName, jmethodID& _inout_MethodID, sal_Int32 _nArgument ) const;
+ void callVoidMethodWithBoolArg_ThrowSQL( const char* _pMethodName, jmethodID& _inout_MethodID, bool _nArgument ) const;
+ void callVoidMethodWithBoolArg_ThrowRuntime( const char* _pMethodName, jmethodID& _inout_MethodID, bool _nArgument ) const;
+ void callVoidMethodWithStringArg( const char* _pMethodName, jmethodID& _inout_MethodID, const OUString& _nArgument ) const;
+ jobject callObjectMethod( JNIEnv * pEnv, const char* _pMethodName, const char* _pSignature, jmethodID& _inout_MethodID ) const;
+ jobject callObjectMethodWithIntArg( JNIEnv * pEnv, const char* _pMethodName, const char* _pSignature, jmethodID& _inout_MethodID , sal_Int32 _nArgument) const;
+
+ template< typename T >
+ T callMethodWithIntArg(T (JNIEnv::*pCallMethod)( jobject obj, jmethodID methodID, ... ) ,const char* _pMethodName, const char* _pSignature, jmethodID& _inout_MethodID , sal_Int32 _nArgument) const
+ {
+ SDBThreadAttach t;
+ obtainMethodId_throwSQL(t.pEnv, _pMethodName,_pSignature, _inout_MethodID);
+ T out = (t.pEnv->*pCallMethod)( object, _inout_MethodID,_nArgument);
+ ThrowSQLException( t.pEnv, nullptr );
+ return out;
+ }
+
+ template< typename T >
+ void callVoidMethod_ThrowSQL(const char* _pMethodName, const char* _pSignature, jmethodID& _inout_MethodID,sal_Int32 _nArgument, const T& _aValue) const
+ {
+ SDBThreadAttach t;
+ obtainMethodId_throwSQL(t.pEnv, _pMethodName,_pSignature, _inout_MethodID);
+ t.pEnv->CallVoidMethod( object, _inout_MethodID,_nArgument,_aValue);
+ ThrowSQLException( t.pEnv, nullptr );
+ }
+
+
+ };
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/java/lang/String.hxx b/connectivity/source/inc/java/lang/String.hxx
new file mode 100644
index 0000000000..2783b6eeb9
--- /dev/null
+++ b/connectivity/source/inc/java/lang/String.hxx
@@ -0,0 +1,43 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <java/lang/Object.hxx>
+
+namespace connectivity
+{
+ class java_lang_String : public java_lang_Object
+ {
+ protected:
+ // statis Data for the Class
+ static jclass theClass;
+ public:
+ virtual jclass getMyClass() const override;
+ virtual ~java_lang_String() override;
+ // a Constructor, that is needed for when Returning the Object is needed:
+ java_lang_String( JNIEnv * pEnv, jobject myObj ) : java_lang_Object( pEnv, myObj ){}
+
+ operator OUString();
+
+ static jclass st_getMyClass();
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/java/lang/Throwable.hxx b/connectivity/source/inc/java/lang/Throwable.hxx
new file mode 100644
index 0000000000..65cfc24fe7
--- /dev/null
+++ b/connectivity/source/inc/java/lang/Throwable.hxx
@@ -0,0 +1,49 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <java/lang/Object.hxx>
+
+namespace connectivity
+{
+
+ //************ Class: java.lang.Throwable
+
+ class java_lang_Throwable : public java_lang_Object
+ {
+ protected:
+ // static Data for the class
+ static jclass theClass;
+ public:
+ virtual jclass getMyClass() const override;
+ virtual ~java_lang_Throwable() override;
+ // a Constructor, that is needed for when Returning the Object is needed:
+ java_lang_Throwable( JNIEnv * pEnv, jobject myObj ) : java_lang_Object( pEnv, myObj ){}
+ OUString getMessage() const;
+ OUString getLocalizedMessage() const;
+
+#if OSL_DEBUG_LEVEL > 0
+ void printStackTrace() const;
+#endif
+
+ static jclass st_getMyClass();
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/java/math/BigDecimal.hxx b/connectivity/source/inc/java/math/BigDecimal.hxx
new file mode 100644
index 0000000000..f4fb684b87
--- /dev/null
+++ b/connectivity/source/inc/java/math/BigDecimal.hxx
@@ -0,0 +1,41 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <java/lang/Object.hxx>
+
+//************ Class: java.lang.Boolean
+
+namespace connectivity
+{
+ class java_math_BigDecimal : public java_lang_Object
+ {
+ // static Data for the class
+ static jclass theClass;
+ public:
+ virtual jclass getMyClass() const override;
+ virtual ~java_math_BigDecimal() override;
+
+ java_math_BigDecimal( const OUString& _par0 );
+ java_math_BigDecimal( const double& _par0 );
+ };
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/java/sql/Array.hxx b/connectivity/source/inc/java/sql/Array.hxx
new file mode 100644
index 0000000000..93cce69386
--- /dev/null
+++ b/connectivity/source/inc/java/sql/Array.hxx
@@ -0,0 +1,54 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <java/lang/Object.hxx>
+#include <com/sun/star/sdbc/XArray.hpp>
+#include <cppuhelper/implbase.hxx>
+
+namespace connectivity
+{
+
+
+ //************ Class: java.sql.SQLWarning
+
+ class java_sql_Array : public java_lang_Object,
+ public ::cppu::WeakImplHelper< css::sdbc::XArray>
+ {
+ protected:
+ // Static data for the class
+ static jclass theClass;
+ public:
+ virtual jclass getMyClass() const override;
+ virtual ~java_sql_Array() override;
+ // A ctor that is needed for returning the object
+ java_sql_Array( JNIEnv * pEnv, jobject myObj ) : java_lang_Object( pEnv, myObj ){}
+
+ // XArray
+ virtual OUString SAL_CALL getBaseTypeName( ) override;
+ virtual sal_Int32 SAL_CALL getBaseType( ) override;
+ virtual css::uno::Sequence< css::uno::Any > SAL_CALL getArray( const css::uno::Reference< css::container::XNameAccess >& typeMap ) override;
+ virtual css::uno::Sequence< css::uno::Any > SAL_CALL getArrayAtIndex( sal_Int32 index, sal_Int32 count, const css::uno::Reference< css::container::XNameAccess >& typeMap ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getResultSet( const css::uno::Reference< css::container::XNameAccess >& typeMap ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getResultSetAtIndex( sal_Int32 index, sal_Int32 count, const css::uno::Reference< css::container::XNameAccess >& typeMap ) override;
+
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/java/sql/Blob.hxx b/connectivity/source/inc/java/sql/Blob.hxx
new file mode 100644
index 0000000000..02ac0df134
--- /dev/null
+++ b/connectivity/source/inc/java/sql/Blob.hxx
@@ -0,0 +1,54 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <java/lang/Object.hxx>
+#include <com/sun/star/sdbc/XBlob.hpp>
+#include <cppuhelper/implbase.hxx>
+
+namespace connectivity
+{
+
+
+ //************ Class: java.sql.SQLWarning
+
+ class java_sql_Blob : public java_lang_Object,
+ public ::cppu::WeakImplHelper< css::sdbc::XBlob>
+ {
+ protected:
+ // Static data for the class
+ static jclass theClass;
+ virtual ~java_sql_Blob() override;
+ public:
+ virtual jclass getMyClass() const override;
+
+ // A ctor that is needed for returning the object
+ java_sql_Blob( JNIEnv * pEnv, jobject myObj );
+
+ // XBlob
+ virtual sal_Int64 SAL_CALL length( ) override;
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getBytes( sal_Int64 pos, sal_Int32 length ) override;
+ virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getBinaryStream( ) override;
+ virtual sal_Int64 SAL_CALL position( const css::uno::Sequence< sal_Int8 >& pattern, sal_Int64 start ) override;
+ virtual sal_Int64 SAL_CALL positionOfBlob( const css::uno::Reference< css::sdbc::XBlob >& pattern, sal_Int64 start ) override;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/java/sql/CallableStatement.hxx b/connectivity/source/inc/java/sql/CallableStatement.hxx
new file mode 100644
index 0000000000..7391837741
--- /dev/null
+++ b/connectivity/source/inc/java/sql/CallableStatement.hxx
@@ -0,0 +1,82 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <java/sql/PreparedStatement.hxx>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XOutParameters.hpp>
+
+namespace connectivity
+{
+
+
+ //************ Class: java.sql.CallableStatement
+
+
+ class java_sql_CallableStatement : public java_sql_PreparedStatement,
+ public css::sdbc::XRow,
+ public css::sdbc::XOutParameters
+ {
+ protected:
+ // Static data for the class
+ static jclass theClass;
+ virtual void createStatement(JNIEnv* _pEnv) override;
+
+ virtual ~java_sql_CallableStatement() override;
+ public:
+ DECLARE_SERVICE_INFO();
+ virtual jclass getMyClass() const override;
+
+ // A ctor that is needed for returning the object
+ java_sql_CallableStatement( JNIEnv * pEnv, java_sql_Connection& _rCon, const OUString& sql );
+
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+ //XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override;
+
+ // XRow
+ virtual sal_Bool SAL_CALL wasNull( ) override;
+ virtual OUString SAL_CALL getString( sal_Int32 columnIndex ) override;
+ virtual sal_Bool SAL_CALL getBoolean( sal_Int32 columnIndex ) override;
+ virtual sal_Int8 SAL_CALL getByte( sal_Int32 columnIndex ) override;
+ virtual sal_Int16 SAL_CALL getShort( sal_Int32 columnIndex ) override;
+ virtual sal_Int32 SAL_CALL getInt( sal_Int32 columnIndex ) override;
+ virtual sal_Int64 SAL_CALL getLong( sal_Int32 columnIndex ) override;
+ virtual float SAL_CALL getFloat( sal_Int32 columnIndex ) override;
+ virtual double SAL_CALL getDouble( sal_Int32 columnIndex ) override;
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getBytes( sal_Int32 columnIndex ) override;
+ virtual css::util::Date SAL_CALL getDate( sal_Int32 columnIndex ) override;
+ virtual css::util::Time SAL_CALL getTime( sal_Int32 columnIndex ) override;
+ virtual css::util::DateTime SAL_CALL getTimestamp( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getBinaryStream( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getCharacterStream( sal_Int32 columnIndex ) override;
+ virtual css::uno::Any SAL_CALL getObject( sal_Int32 columnIndex, const css::uno::Reference< css::container::XNameAccess >& typeMap ) override;
+ virtual css::uno::Reference< css::sdbc::XRef > SAL_CALL getRef( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XBlob > SAL_CALL getBlob( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XClob > SAL_CALL getClob( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XArray > SAL_CALL getArray( sal_Int32 columnIndex ) override;
+ // XOutParameters
+ virtual void SAL_CALL registerOutParameter( sal_Int32 parameterIndex, sal_Int32 sqlType, const OUString& typeName ) override;
+ virtual void SAL_CALL registerNumericOutParameter( sal_Int32 parameterIndex, sal_Int32 sqlType, sal_Int32 scale ) override;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/java/sql/Clob.hxx b/connectivity/source/inc/java/sql/Clob.hxx
new file mode 100644
index 0000000000..67a69bb6db
--- /dev/null
+++ b/connectivity/source/inc/java/sql/Clob.hxx
@@ -0,0 +1,54 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <java/lang/Object.hxx>
+#include <com/sun/star/sdbc/XClob.hpp>
+#include <cppuhelper/implbase.hxx>
+
+namespace connectivity
+{
+
+
+ //************ Class: java.sql.SQLWarning
+
+ class java_sql_Clob : public java_lang_Object,
+ public ::cppu::WeakImplHelper< css::sdbc::XClob>
+ {
+ protected:
+ // Static data for the class
+ static jclass theClass;
+ virtual ~java_sql_Clob() override;
+ public:
+ virtual jclass getMyClass() const override;
+
+ // A ctor that is needed for returning the object
+ java_sql_Clob( JNIEnv * pEnv, jobject myObj );
+
+ // XClob
+ virtual sal_Int64 SAL_CALL length( ) override;
+ virtual OUString SAL_CALL getSubString( sal_Int64 pos, sal_Int32 length ) override;
+ virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getCharacterStream( ) override;
+ virtual sal_Int64 SAL_CALL position( const OUString& searchstr, sal_Int32 start ) override;
+ virtual sal_Int64 SAL_CALL positionOfClob( const css::uno::Reference< css::sdbc::XClob >& pattern, sal_Int64 start ) override;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/java/sql/Connection.hxx b/connectivity/source/inc/java/sql/Connection.hxx
new file mode 100644
index 0000000000..444d44df51
--- /dev/null
+++ b/connectivity/source/inc/java/sql/Connection.hxx
@@ -0,0 +1,135 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <java/lang/Object.hxx>
+#include <TConnection.hxx>
+#include <connectivity/CommonTools.hxx>
+#include <AutoRetrievingBase.hxx>
+#include <java/sql/ConnectionLog.hxx>
+#include <java/GlobalRef.hxx>
+
+#include <com/sun/star/beans/NamedValue.hpp>
+
+namespace connectivity
+{
+ class java_sql_Driver;
+
+ typedef OMetaConnection java_sql_Connection_BASE;
+
+ class java_sql_Connection : public java_sql_Connection_BASE,
+ public java_lang_Object,
+ public OAutoRetrievingBase
+ {
+ css::uno::Reference< css::uno::XComponentContext > m_xContext;
+ const java_sql_Driver* m_pDriver;
+ jobject m_pDriverobject;
+ jdbc::GlobalRef< jobject >
+ m_pDriverClassLoader;
+
+ jclass m_Driver_theClass;
+ java::sql::ConnectionLog
+ m_aLogger;
+ bool m_bIgnoreDriverPrivileges;
+ bool m_bIgnoreCurrency;
+ css::uno::Any m_aCatalogRestriction;
+ css::uno::Any m_aSchemaRestriction;
+
+ /** transform named parameter into unnamed one.
+ @param _sSQL
+ The SQL statement to transform.
+ @return
+ The new statement with unnamed parameters.
+ */
+ OUString transFormPreparedStatement(const OUString& _sSQL);
+ void loadDriverFromProperties(
+ const OUString& _sDriverClass,
+ const OUString& _sDriverClassPath,
+ const css::uno::Sequence< css::beans::NamedValue >& _rSystemProperties
+ );
+ /** load driver class path from system configuration.
+ @param _sDriverClass
+ The driver class name to look for in the configuration.
+ */
+ OUString impl_getJavaDriverClassPath_nothrow(const OUString& _sDriverClass);
+
+ protected:
+ // Static data for the class
+ static jclass theClass;
+
+ virtual ~java_sql_Connection() override;
+
+ public:
+ virtual jclass getMyClass() const override;
+
+ DECLARE_SERVICE_INFO();
+ // A ctor that is needed for returning the object
+ java_sql_Connection( const java_sql_Driver& _rDriver );
+ bool construct( const OUString& url,
+ const css::uno::Sequence< css::beans::PropertyValue >& info);
+
+ const css::uno::Sequence< css::beans::PropertyValue >&
+ getConnectionInfo() const { return m_aConnectionInfo; }
+
+ bool isIgnoreDriverPrivilegesEnabled() const { return m_bIgnoreDriverPrivileges;}
+ bool isIgnoreCurrencyEnabled() const { return m_bIgnoreCurrency; }
+ const css::uno::Any& getCatalogRestriction() const { return m_aCatalogRestriction; }
+ const css::uno::Any& getSchemaRestriction() const { return m_aSchemaRestriction; }
+
+ /** returns the instance used for logging events related to this connection
+ */
+ const java::sql::ConnectionLog& getLogger() const { return m_aLogger; }
+
+ /** returns the class loader which was used to load the driver class
+
+ Usually used in conjunction with a ContextClassLoaderScope instance.
+ */
+ const jdbc::GlobalRef< jobject >& getDriverClassLoader() const { return m_pDriverClassLoader; }
+
+ // OComponentHelper
+ virtual void SAL_CALL disposing() override;
+
+ // XConnection
+ virtual css::uno::Reference< css::sdbc::XStatement > SAL_CALL createStatement( ) override;
+ virtual css::uno::Reference< css::sdbc::XPreparedStatement > SAL_CALL prepareStatement( const OUString& sql ) override;
+ virtual css::uno::Reference< css::sdbc::XPreparedStatement > SAL_CALL prepareCall( const OUString& sql ) override;
+ virtual OUString SAL_CALL nativeSQL( const OUString& sql ) override;
+ virtual void SAL_CALL setAutoCommit( sal_Bool autoCommit ) override;
+ virtual sal_Bool SAL_CALL getAutoCommit( ) override;
+ virtual void SAL_CALL commit( ) override;
+ virtual void SAL_CALL rollback( ) override;
+ virtual sal_Bool SAL_CALL isClosed( ) override;
+ virtual css::uno::Reference< css::sdbc::XDatabaseMetaData > SAL_CALL getMetaData( ) override;
+ virtual void SAL_CALL setReadOnly( sal_Bool readOnly ) override;
+ virtual sal_Bool SAL_CALL isReadOnly( ) override;
+ virtual void SAL_CALL setCatalog( const OUString& catalog ) override;
+ virtual OUString SAL_CALL getCatalog( ) override;
+ virtual void SAL_CALL setTransactionIsolation( sal_Int32 level ) override;
+ virtual sal_Int32 SAL_CALL getTransactionIsolation( ) override;
+ virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getTypeMap( ) override;
+ virtual void SAL_CALL setTypeMap( const css::uno::Reference< css::container::XNameAccess >& typeMap ) override;
+ // XCloseable
+ virtual void SAL_CALL close( ) override;
+ // XWarningsSupplier
+ virtual css::uno::Any SAL_CALL getWarnings( ) override;
+ virtual void SAL_CALL clearWarnings( ) override;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/java/sql/ConnectionLog.hxx b/connectivity/source/inc/java/sql/ConnectionLog.hxx
new file mode 100644
index 0000000000..cea19cdff0
--- /dev/null
+++ b/connectivity/source/inc/java/sql/ConnectionLog.hxx
@@ -0,0 +1,127 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/logging/LogLevel.hpp>
+
+#include <rtl/ustring.hxx>
+
+// Strange enough, GCC requires the following forward declarations of the various
+// convertLogArgToString flavors to be *before* the inclusion of comphelper/logging.hxx
+
+namespace com::sun::star::util
+{
+ struct Date;
+ struct Time;
+ struct DateTime;
+}
+
+
+namespace comphelper::log::convert
+{
+
+
+ // helpers for logging more data types than are defined in comphelper/logging.hxx
+ OUString convertLogArgToString( const css::util::Date& _rDate );
+ OUString convertLogArgToString( const css::util::Time& _rTime );
+ OUString convertLogArgToString( const css::util::DateTime& _rDateTime );
+
+
+}
+
+
+#include <comphelper/logging.hxx>
+
+namespace connectivity
+{
+ namespace LogLevel = css::logging::LogLevel;
+}
+
+
+namespace connectivity::java::sql {
+
+ typedef ::comphelper::EventLogger ConnectionLog_Base;
+ class ConnectionLog : public ConnectionLog_Base
+ {
+ public:
+ enum ObjectType
+ {
+ CONNECTION = 0,
+ STATEMENT,
+ RESULTSET,
+
+ ObjectTypeCount = RESULTSET + 1
+ };
+
+ private:
+ const sal_Int32 m_nObjectID;
+
+ public:
+ /// will construct an instance of ObjectType CONNECTION
+ ConnectionLog( const ::comphelper::EventLogger & _rDriverLog );
+ /// will create an instance with the same object ID / ObjectType as a given source instance
+ ConnectionLog( const ConnectionLog& _rSourceLog );
+ /// will create an instance of arbitrary ObjectType
+ ConnectionLog( const ConnectionLog& _rSourceLog, ObjectType _eType );
+
+ sal_Int32 getObjectID() const { return m_nObjectID; }
+
+ /// logs a given message, without any arguments, or source class/method names
+ void log( const sal_Int32 _nLogLevel, const OUString& rMessage )
+ {
+ ConnectionLog_Base::log( _nLogLevel, rMessage, m_nObjectID );
+ }
+
+ template< typename ARGTYPE1 >
+ void log( const sal_Int32 _nLogLevel, const OUString& rMessage, ARGTYPE1 _argument1 ) const
+ {
+ ConnectionLog_Base::log( _nLogLevel, rMessage, m_nObjectID, _argument1 );
+ }
+
+ template< typename ARGTYPE1, typename ARGTYPE2 >
+ void log( const sal_Int32 _nLogLevel, const OUString& rMessage, ARGTYPE1 _argument1, ARGTYPE2 _argument2 ) const
+ {
+ ConnectionLog_Base::log( _nLogLevel, rMessage, m_nObjectID, _argument1, _argument2 );
+ }
+
+ template< typename ARGTYPE1, typename ARGTYPE2, typename ARGTYPE3 >
+ void log( const sal_Int32 _nLogLevel, const OUString& rMessage, ARGTYPE1 _argument1, ARGTYPE2 _argument2, ARGTYPE3 _argument3 ) const
+ {
+ ConnectionLog_Base::log( _nLogLevel, rMessage, m_nObjectID, _argument1, _argument2, _argument3 );
+ }
+
+ template< typename ARGTYPE1, typename ARGTYPE2, typename ARGTYPE3, typename ARGTYPE4 >
+ void log( const sal_Int32 _nLogLevel, const OUString& rMessage, ARGTYPE1 _argument1, ARGTYPE2 _argument2, ARGTYPE3 _argument3, ARGTYPE4 _argument4 ) const
+ {
+ ConnectionLog_Base::log( _nLogLevel, rMessage, m_nObjectID, _argument1, _argument2, _argument3, _argument4 );
+ }
+
+ template< typename ARGTYPE1, typename ARGTYPE2, typename ARGTYPE3, typename ARGTYPE4, typename ARGTYPE5 >
+ void log( const sal_Int32 _nLogLevel, const OUString& rMessage, ARGTYPE1 _argument1, ARGTYPE2 _argument2, ARGTYPE3 _argument3, ARGTYPE4 _argument4, ARGTYPE5 _argument5 ) const
+ {
+ ConnectionLog_Base::log( _nLogLevel, rMessage, m_nObjectID, _argument1, _argument2, _argument3, _argument4, _argument5 );
+ }
+ };
+
+
+} // namespace connectivity::java::sql
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/java/sql/DatabaseMetaData.hxx b/connectivity/source/inc/java/sql/DatabaseMetaData.hxx
new file mode 100644
index 0000000000..eb43f2537a
--- /dev/null
+++ b/connectivity/source/inc/java/sql/DatabaseMetaData.hxx
@@ -0,0 +1,216 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <java/lang/Object.hxx>
+#include <TDatabaseMetaDataBase.hxx>
+
+#include <java/sql/ConnectionLog.hxx>
+
+namespace connectivity
+{
+ class java_sql_Connection;
+
+ //************ Class: java.sql.DatabaseMetaDataDate
+
+
+ class java_sql_DatabaseMetaData : public ODatabaseMetaDataBase,
+ public java_lang_Object
+ {
+ java_sql_Connection* m_pConnection;
+ java::sql::ConnectionLog m_aLogger;
+
+ // Static data for the class
+ static jclass theClass;
+
+ public:
+ virtual jclass getMyClass() const override;
+ virtual ~java_sql_DatabaseMetaData() override;
+ // A ctor that is needed for returning the object
+ java_sql_DatabaseMetaData( JNIEnv * pEnv, jobject myObj, java_sql_Connection& _rConnection );
+
+ private:
+
+ virtual css::uno::Reference< css::sdbc::XResultSet > impl_getTypeInfo_throw() override;
+ // cached database information
+ virtual OUString impl_getIdentifierQuoteString_throw( ) override;
+ virtual bool impl_isCatalogAtStart_throw( ) override;
+ virtual OUString impl_getCatalogSeparator_throw( ) override;
+ virtual bool impl_supportsCatalogsInTableDefinitions_throw( ) override;
+ virtual bool impl_supportsSchemasInTableDefinitions_throw( ) override ;
+ virtual bool impl_supportsCatalogsInDataManipulation_throw( ) override;
+ virtual bool impl_supportsSchemasInDataManipulation_throw( ) override ;
+ virtual bool impl_supportsMixedCaseQuotedIdentifiers_throw( ) override;
+ virtual bool impl_supportsAlterTableWithAddColumn_throw( ) override;
+ virtual bool impl_supportsAlterTableWithDropColumn_throw( ) override;
+ virtual sal_Int32 impl_getMaxStatements_throw( ) override;
+ virtual sal_Int32 impl_getMaxTablesInSelect_throw( ) override;
+ virtual bool impl_storesMixedCaseQuotedIdentifiers_throw( ) override;
+
+ virtual sal_Bool SAL_CALL allProceduresAreCallable( ) override;
+ virtual sal_Bool SAL_CALL allTablesAreSelectable( ) override;
+ virtual OUString SAL_CALL getURL( ) override;
+ virtual OUString SAL_CALL getUserName( ) override;
+ virtual sal_Bool SAL_CALL isReadOnly( ) override;
+ virtual sal_Bool SAL_CALL nullsAreSortedHigh( ) override;
+ virtual sal_Bool SAL_CALL nullsAreSortedLow( ) override;
+ virtual sal_Bool SAL_CALL nullsAreSortedAtStart( ) override;
+ virtual sal_Bool SAL_CALL nullsAreSortedAtEnd( ) override;
+ virtual OUString SAL_CALL getDatabaseProductName( ) override;
+ virtual OUString SAL_CALL getDatabaseProductVersion( ) override;
+ virtual OUString SAL_CALL getDriverName( ) override;
+ virtual OUString SAL_CALL getDriverVersion( ) override;
+ virtual sal_Int32 SAL_CALL getDriverMajorVersion( ) override;
+ virtual sal_Int32 SAL_CALL getDriverMinorVersion( ) override;
+ virtual sal_Bool SAL_CALL usesLocalFiles( ) override;
+ virtual sal_Bool SAL_CALL usesLocalFilePerTable( ) override;
+ virtual sal_Bool SAL_CALL supportsMixedCaseIdentifiers( ) override;
+ virtual sal_Bool SAL_CALL storesUpperCaseIdentifiers( ) override;
+ virtual sal_Bool SAL_CALL storesLowerCaseIdentifiers( ) override;
+ virtual sal_Bool SAL_CALL storesMixedCaseIdentifiers( ) override;
+ virtual sal_Bool SAL_CALL storesUpperCaseQuotedIdentifiers( ) override;
+ virtual sal_Bool SAL_CALL storesLowerCaseQuotedIdentifiers( ) override;
+ virtual OUString SAL_CALL getSQLKeywords( ) override;
+ virtual OUString SAL_CALL getNumericFunctions( ) override;
+ virtual OUString SAL_CALL getStringFunctions( ) override;
+ virtual OUString SAL_CALL getSystemFunctions( ) override;
+ virtual OUString SAL_CALL getTimeDateFunctions( ) override;
+ virtual OUString SAL_CALL getSearchStringEscape( ) override;
+ virtual OUString SAL_CALL getExtraNameCharacters( ) override;
+ virtual sal_Bool SAL_CALL supportsColumnAliasing( ) override;
+ virtual sal_Bool SAL_CALL nullPlusNonNullIsNull( ) override;
+ virtual sal_Bool SAL_CALL supportsTypeConversion( ) override;
+ virtual sal_Bool SAL_CALL supportsConvert( sal_Int32 fromType, sal_Int32 toType ) override;
+ virtual sal_Bool SAL_CALL supportsTableCorrelationNames( ) override;
+ virtual sal_Bool SAL_CALL supportsDifferentTableCorrelationNames( ) override;
+ virtual sal_Bool SAL_CALL supportsExpressionsInOrderBy( ) override;
+ virtual sal_Bool SAL_CALL supportsOrderByUnrelated( ) override;
+ virtual sal_Bool SAL_CALL supportsGroupBy( ) override;
+ virtual sal_Bool SAL_CALL supportsGroupByUnrelated( ) override;
+ virtual sal_Bool SAL_CALL supportsGroupByBeyondSelect( ) override;
+ virtual sal_Bool SAL_CALL supportsLikeEscapeClause( ) override;
+ virtual sal_Bool SAL_CALL supportsMultipleResultSets( ) override;
+ virtual sal_Bool SAL_CALL supportsMultipleTransactions( ) override;
+ virtual sal_Bool SAL_CALL supportsNonNullableColumns( ) override;
+ virtual sal_Bool SAL_CALL supportsMinimumSQLGrammar( ) override;
+ virtual sal_Bool SAL_CALL supportsCoreSQLGrammar( ) override;
+ virtual sal_Bool SAL_CALL supportsExtendedSQLGrammar( ) override;
+ virtual sal_Bool SAL_CALL supportsANSI92EntryLevelSQL( ) override;
+ virtual sal_Bool SAL_CALL supportsANSI92IntermediateSQL( ) override;
+ virtual sal_Bool SAL_CALL supportsANSI92FullSQL( ) override;
+ virtual sal_Bool SAL_CALL supportsIntegrityEnhancementFacility( ) override;
+ virtual sal_Bool SAL_CALL supportsOuterJoins( ) override;
+ virtual sal_Bool SAL_CALL supportsFullOuterJoins( ) override;
+ virtual sal_Bool SAL_CALL supportsLimitedOuterJoins( ) override;
+ virtual OUString SAL_CALL getSchemaTerm( ) override;
+ virtual OUString SAL_CALL getProcedureTerm( ) override;
+ virtual OUString SAL_CALL getCatalogTerm( ) override;
+ virtual sal_Bool SAL_CALL supportsSchemasInProcedureCalls( ) override;
+ virtual sal_Bool SAL_CALL supportsSchemasInIndexDefinitions( ) override;
+ virtual sal_Bool SAL_CALL supportsSchemasInPrivilegeDefinitions( ) override;
+ virtual sal_Bool SAL_CALL supportsCatalogsInProcedureCalls( ) override;
+ virtual sal_Bool SAL_CALL supportsCatalogsInIndexDefinitions( ) override;
+ virtual sal_Bool SAL_CALL supportsCatalogsInPrivilegeDefinitions( ) override;
+ virtual sal_Bool SAL_CALL supportsPositionedDelete( ) override;
+ virtual sal_Bool SAL_CALL supportsPositionedUpdate( ) override;
+ virtual sal_Bool SAL_CALL supportsSelectForUpdate( ) override;
+ virtual sal_Bool SAL_CALL supportsStoredProcedures( ) override;
+ virtual sal_Bool SAL_CALL supportsSubqueriesInComparisons( ) override;
+ virtual sal_Bool SAL_CALL supportsSubqueriesInExists( ) override;
+ virtual sal_Bool SAL_CALL supportsSubqueriesInIns( ) override;
+ virtual sal_Bool SAL_CALL supportsSubqueriesInQuantifieds( ) override;
+ virtual sal_Bool SAL_CALL supportsCorrelatedSubqueries( ) override;
+ virtual sal_Bool SAL_CALL supportsUnion( ) override;
+ virtual sal_Bool SAL_CALL supportsUnionAll( ) override;
+ virtual sal_Bool SAL_CALL supportsOpenCursorsAcrossCommit( ) override;
+ virtual sal_Bool SAL_CALL supportsOpenCursorsAcrossRollback( ) override;
+ virtual sal_Bool SAL_CALL supportsOpenStatementsAcrossCommit( ) override;
+ virtual sal_Bool SAL_CALL supportsOpenStatementsAcrossRollback( ) override;
+ virtual sal_Int32 SAL_CALL getMaxBinaryLiteralLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxCharLiteralLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxColumnNameLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxColumnsInGroupBy( ) override;
+ virtual sal_Int32 SAL_CALL getMaxColumnsInIndex( ) override;
+ virtual sal_Int32 SAL_CALL getMaxColumnsInOrderBy( ) override;
+ virtual sal_Int32 SAL_CALL getMaxColumnsInSelect( ) override;
+ virtual sal_Int32 SAL_CALL getMaxColumnsInTable( ) override;
+ virtual sal_Int32 SAL_CALL getMaxConnections( ) override;
+ virtual sal_Int32 SAL_CALL getMaxCursorNameLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxIndexLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxSchemaNameLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxProcedureNameLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxCatalogNameLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxRowSize( ) override;
+ virtual sal_Bool SAL_CALL doesMaxRowSizeIncludeBlobs( ) override;
+ virtual sal_Int32 SAL_CALL getMaxStatementLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxTableNameLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxUserNameLength( ) override;
+ virtual sal_Int32 SAL_CALL getDefaultTransactionIsolation( ) override;
+ virtual sal_Bool SAL_CALL supportsTransactions( ) override;
+ virtual sal_Bool SAL_CALL supportsTransactionIsolationLevel( sal_Int32 level ) override;
+ virtual sal_Bool SAL_CALL supportsDataDefinitionAndDataManipulationTransactions( ) override;
+ virtual sal_Bool SAL_CALL supportsDataManipulationTransactionsOnly( ) override;
+ virtual sal_Bool SAL_CALL dataDefinitionCausesTransactionCommit( ) override;
+ virtual sal_Bool SAL_CALL dataDefinitionIgnoredInTransactions( ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getProcedures( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& procedureNamePattern ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getProcedureColumns( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& procedureNamePattern, const OUString& columnNamePattern ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getTables( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& tableNamePattern, const css::uno::Sequence< OUString >& types ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getSchemas( ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getCatalogs( ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getTableTypes( ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getColumns( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& tableNamePattern, const OUString& columnNamePattern ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getColumnPrivileges( const css::uno::Any& catalog, const OUString& schema, const OUString& table, const OUString& columnNamePattern ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getTablePrivileges( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& tableNamePattern ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getBestRowIdentifier( const css::uno::Any& catalog, const OUString& schema, const OUString& table, sal_Int32 scope, sal_Bool nullable ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getVersionColumns( const css::uno::Any& catalog, const OUString& schema, const OUString& table ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getPrimaryKeys( const css::uno::Any& catalog, const OUString& schema, const OUString& table ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getImportedKeys( const css::uno::Any& catalog, const OUString& schema, const OUString& table ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getExportedKeys( const css::uno::Any& catalog, const OUString& schema, const OUString& table ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getCrossReference( const css::uno::Any& primaryCatalog, const OUString& primarySchema, const OUString& primaryTable, const css::uno::Any& foreignCatalog, const OUString& foreignSchema, const OUString& foreignTable ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getIndexInfo( const css::uno::Any& catalog, const OUString& schema, const OUString& table, sal_Bool unique, sal_Bool approximate ) override;
+ virtual sal_Bool SAL_CALL supportsResultSetType( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL supportsResultSetConcurrency( sal_Int32 setType, sal_Int32 concurrency ) override;
+ virtual sal_Bool SAL_CALL ownUpdatesAreVisible( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL ownDeletesAreVisible( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL ownInsertsAreVisible( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL othersUpdatesAreVisible( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL othersDeletesAreVisible( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL othersInsertsAreVisible( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL updatesAreDetected( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL deletesAreDetected( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL insertsAreDetected( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL supportsBatchUpdates( ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getUDTs( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& typeNamePattern, const css::uno::Sequence< sal_Int32 >& types ) override;
+
+ private:
+ bool impl_callBooleanMethod( const char* _pMethodName, jmethodID& _inout_MethodID );
+ OUString impl_callStringMethod( const char* _pMethodName, jmethodID& _inout_MethodID );
+ sal_Int32 impl_callIntMethod_ThrowSQL( const char* _pMethodName, jmethodID& _inout_MethodID );
+ sal_Int32 impl_callIntMethod_ThrowRuntime( const char* _pMethodName, jmethodID& _inout_MethodID );
+ bool impl_callBooleanMethodWithIntArg( const char* _pMethodName, jmethodID& _inout_MethodID, sal_Int32 _nArgument );
+ css::uno::Reference< css::sdbc::XResultSet >
+ impl_callResultSetMethod( const char* _pMethodName, jmethodID& _inout_MethodID );
+ css::uno::Reference< css::sdbc::XResultSet >
+ impl_callResultSetMethodWithStrings( const char* _pMethodName, jmethodID& _inout_MethodID, const css::uno::Any& _rCatalog,
+ const OUString& _rSchemaPattern, const OUString& _rLeastPattern,
+ const OUString* _pOptionalAdditionalString = nullptr);
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/java/sql/Driver.hxx b/connectivity/source/inc/java/sql/Driver.hxx
new file mode 100644
index 0000000000..805df2ed12
--- /dev/null
+++ b/connectivity/source/inc/java/sql/Driver.hxx
@@ -0,0 +1,59 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/sdbc/XDriver.hpp>
+#include <cppuhelper/implbase.hxx>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+
+#include <comphelper/logging.hxx>
+
+namespace connectivity
+{
+ class java_sql_Driver : public ::cppu::WeakImplHelper< css::sdbc::XDriver,css::lang::XServiceInfo>
+ {
+ css::uno::Reference<css::uno::XComponentContext> m_aContext;
+ ::comphelper::EventLogger m_aLogger;
+
+ protected:
+ virtual ~java_sql_Driver() override;
+
+ public:
+ java_sql_Driver(const css::uno::Reference< css::uno::XComponentContext >& _rxContext);
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+ // XDriver
+ virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL connect( const OUString& url, const css::uno::Sequence< css::beans::PropertyValue >& info ) override ;
+ virtual sal_Bool SAL_CALL acceptsURL( const OUString& url ) override ;
+ virtual css::uno::Sequence< css::sdbc::DriverPropertyInfo > SAL_CALL getPropertyInfo( const OUString& url, const css::uno::Sequence< css::beans::PropertyValue >& info ) override ;
+ virtual sal_Int32 SAL_CALL getMajorVersion( ) override ;
+ virtual sal_Int32 SAL_CALL getMinorVersion( ) override;
+
+ const css::uno::Reference<css::uno::XComponentContext>& getContext() const { return m_aContext; }
+ const ::comphelper::EventLogger& getLogger() const { return m_aLogger; }
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/java/sql/DriverPropertyInfo.hxx b/connectivity/source/inc/java/sql/DriverPropertyInfo.hxx
new file mode 100644
index 0000000000..4bc6816226
--- /dev/null
+++ b/connectivity/source/inc/java/sql/DriverPropertyInfo.hxx
@@ -0,0 +1,42 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <java/lang/Object.hxx>
+
+namespace connectivity
+{
+
+
+//************ Class: java.sql.DriverPropertyInfo
+
+ class java_sql_DriverPropertyInfo : public java_lang_Object
+ {
+ protected:
+ // Static data for the class
+ static jclass theClass;
+ public:
+ virtual jclass getMyClass() const override;
+ virtual ~java_sql_DriverPropertyInfo() override;
+ };
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/java/sql/JStatement.hxx b/connectivity/source/inc/java/sql/JStatement.hxx
new file mode 100644
index 0000000000..89a091bd96
--- /dev/null
+++ b/connectivity/source/inc/java/sql/JStatement.hxx
@@ -0,0 +1,234 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <java/lang/Object.hxx>
+#include <com/sun/star/sdbc/XStatement.hpp>
+#include <com/sun/star/sdbc/XWarningsSupplier.hpp>
+#include <com/sun/star/sdbc/XMultipleResults.hpp>
+#include <com/sun/star/sdbc/XBatchExecution.hpp>
+#include <com/sun/star/sdbc/XCloseable.hpp>
+#include <com/sun/star/util/XCancellable.hpp>
+#include <com/sun/star/sdbc/XGeneratedResultSet.hpp>
+#include <comphelper/proparrhlp.hxx>
+#include <cppuhelper/compbase.hxx>
+#include <cppuhelper/basemutex.hxx>
+#include <connectivity/CommonTools.hxx>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+
+#include <java/sql/Connection.hxx>
+#include <java/sql/ConnectionLog.hxx>
+
+namespace connectivity
+{
+
+ typedef ::cppu::WeakComponentImplHelper< css::sdbc::XStatement,
+ css::sdbc::XWarningsSupplier,
+ css::util::XCancellable,
+ css::sdbc::XCloseable,
+ css::sdbc::XGeneratedResultSet,
+ css::sdbc::XMultipleResults> java_sql_Statement_BASE;
+
+ //************ Class: java.sql.Statement
+
+ class java_sql_Statement_Base : public cppu::BaseMutex,
+ public java_sql_Statement_BASE,
+ public java_lang_Object,
+ public ::cppu::OPropertySetHelper,
+ public ::comphelper::OPropertyArrayUsageHelper<java_sql_Statement_Base>
+
+ {
+
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ sal_Int32 getQueryTimeOut();
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ sal_Int32 getMaxFieldSize();
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ sal_Int32 getMaxRows();
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ sal_Int32 getResultSetConcurrency();
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ sal_Int32 getResultSetType();
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ sal_Int32 getFetchDirection();
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ sal_Int32 getFetchSize();
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ OUString getCursorName();
+
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void setQueryTimeOut(sal_Int32 _par0);
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void setMaxFieldSize(sal_Int32 _par0);
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void setMaxRows(sal_Int32 _par0);
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void setResultSetConcurrency(sal_Int32 _par0);
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void setResultSetType(sal_Int32 _par0);
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void setFetchDirection(sal_Int32 _par0);
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void setFetchSize(sal_Int32 _par0);
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void setCursorName(const OUString &_par0);
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void setEscapeProcessing(bool _par0);
+
+ protected:
+ css::uno::Reference< css::sdbc::XStatement> m_xGeneratedStatement;
+ rtl::Reference<java_sql_Connection> m_pConnection;
+ java::sql::ConnectionLog m_aLogger;
+ OUString m_sSqlStatement;
+ // Properties
+ sal_Int32 m_nResultSetConcurrency;
+ sal_Int32 m_nResultSetType;
+ bool m_bEscapeProcessing;
+
+
+ // Static data for the class
+ static jclass theClass;
+
+ // OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override;
+ // OPropertySetHelper
+ virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override;
+
+ virtual sal_Bool SAL_CALL convertFastPropertyValue(
+ css::uno::Any & rConvertedValue,
+ css::uno::Any & rOldValue,
+ sal_Int32 nHandle,
+ const css::uno::Any& rValue
+ ) override;
+
+ virtual void SAL_CALL setFastPropertyValue_NoBroadcast(
+ sal_Int32 nHandle,
+ const css::uno::Any& rValue
+ ) override;
+
+ virtual void SAL_CALL getFastPropertyValue(
+ css::uno::Any& rValue,
+ sal_Int32 nHandle
+ ) const override;
+
+ virtual void createStatement(JNIEnv* _pEnv) = 0;
+
+ virtual ~java_sql_Statement_Base() override;
+
+ sal_Int32 impl_getProperty(const char* _pMethodName, jmethodID& _inout_MethodID);
+ sal_Int32 impl_getProperty(const char* _pMethodName, jmethodID& _inout_MethodID,sal_Int32 _nDefault);
+
+ public:
+ virtual jclass getMyClass() const override;
+
+ // A ctor that is needed for returning the object
+ java_sql_Statement_Base( JNIEnv * pEnv, java_sql_Connection& _rCon );
+
+ sal_Int32 getStatementObjectID() const { return m_aLogger.getObjectID(); }
+
+ // OComponentHelper
+ virtual void SAL_CALL disposing() override;
+ // XInterface
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ //XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override;
+
+ // XPropertySet
+ virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override;
+ // XStatement
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL executeQuery( const OUString& sql ) override ;
+ virtual sal_Int32 SAL_CALL executeUpdate( const OUString& sql ) override ;
+ virtual sal_Bool SAL_CALL execute( const OUString& sql ) override ;
+ virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL getConnection( ) override ;
+ // XWarningsSupplier
+ virtual css::uno::Any SAL_CALL getWarnings( ) override;
+ virtual void SAL_CALL clearWarnings( ) override;
+ // XCancellable
+ virtual void SAL_CALL cancel( ) override;
+ // XCloseable
+ virtual void SAL_CALL close( ) override;
+ // XMultipleResults
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getResultSet( ) override;
+ virtual sal_Int32 SAL_CALL getUpdateCount( ) override;
+ virtual sal_Bool SAL_CALL getMoreResults( ) override;
+ //XGeneratedResultSet
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getGeneratedValues( ) override;
+
+ public:
+ using ::cppu::OPropertySetHelper::getFastPropertyValue;
+ };
+
+ class OStatement_BASE2 : public java_sql_Statement_Base
+
+ {
+ public:
+ OStatement_BASE2(JNIEnv * pEnv, java_sql_Connection& _rCon ) : java_sql_Statement_Base( pEnv, _rCon ) {}
+
+ // OComponentHelper
+ virtual void SAL_CALL disposing() override;
+ };
+
+ class java_sql_Statement : public OStatement_BASE2,
+ public css::sdbc::XBatchExecution,
+ public css::lang::XServiceInfo
+ {
+ protected:
+ // Static data for the class
+ static jclass theClass;
+
+ virtual void createStatement(JNIEnv* _pEnv) override;
+
+ virtual ~java_sql_Statement() override;
+ public:
+ DECLARE_SERVICE_INFO();
+ virtual jclass getMyClass() const override;
+
+ // A ctor that is needed for returning the object
+ java_sql_Statement( JNIEnv * pEnv, java_sql_Connection& _rCon ) : OStatement_BASE2( pEnv, _rCon){};
+
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+ // XBatchExecution
+ virtual void SAL_CALL addBatch( const OUString& sql ) override;
+ virtual void SAL_CALL clearBatch( ) override;
+ virtual css::uno::Sequence< sal_Int32 > SAL_CALL executeBatch( ) override;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/java/sql/PreparedStatement.hxx b/connectivity/source/inc/java/sql/PreparedStatement.hxx
new file mode 100644
index 0000000000..711fd2d006
--- /dev/null
+++ b/connectivity/source/inc/java/sql/PreparedStatement.hxx
@@ -0,0 +1,103 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <java/sql/JStatement.hxx>
+#include <com/sun/star/sdbc/XPreparedStatement.hpp>
+#include <com/sun/star/sdbc/XParameters.hpp>
+#include <com/sun/star/sdbc/XPreparedBatchExecution.hpp>
+#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+
+namespace connectivity
+{
+
+ //************ Class: java.sql.PreparedStatement
+
+
+ class java_sql_PreparedStatement : public OStatement_BASE2,
+ public css::sdbc::XPreparedStatement,
+ public css::sdbc::XResultSetMetaDataSupplier,
+ public css::sdbc::XParameters,
+ public css::sdbc::XPreparedBatchExecution,
+ public css::lang::XServiceInfo
+ {
+ protected:
+ // Static data for the class
+ static jclass theClass;
+
+ virtual void createStatement(JNIEnv* _pEnv) override;
+ virtual ~java_sql_PreparedStatement() override;
+ public:
+ DECLARE_SERVICE_INFO();
+ virtual jclass getMyClass() const override;
+
+ // A ctor that is needed for returning the object
+ java_sql_PreparedStatement( JNIEnv * pEnv, java_sql_Connection& _rCon,const OUString& sql );
+
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+ //XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override;
+
+ // XPreparedStatement
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL executeQuery( ) override;
+ virtual sal_Int32 SAL_CALL executeUpdate( ) override;
+ virtual sal_Bool SAL_CALL execute( ) override;
+ virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL getConnection( ) override;
+ // XParameters
+ virtual void SAL_CALL setNull( sal_Int32 parameterIndex, sal_Int32 sqlType ) override;
+ virtual void SAL_CALL setObjectNull( sal_Int32 parameterIndex, sal_Int32 sqlType, const OUString& typeName ) override;
+ virtual void SAL_CALL setBoolean( sal_Int32 parameterIndex, sal_Bool x ) override;
+ virtual void SAL_CALL setByte( sal_Int32 parameterIndex, sal_Int8 x ) override;
+ virtual void SAL_CALL setShort( sal_Int32 parameterIndex, sal_Int16 x ) override;
+ virtual void SAL_CALL setInt( sal_Int32 parameterIndex, sal_Int32 x ) override;
+ virtual void SAL_CALL setLong( sal_Int32 parameterIndex, sal_Int64 x ) override;
+ virtual void SAL_CALL setFloat( sal_Int32 parameterIndex, float x ) override;
+ virtual void SAL_CALL setDouble( sal_Int32 parameterIndex, double x ) override;
+ virtual void SAL_CALL setString( sal_Int32 parameterIndex, const OUString& x ) override;
+ virtual void SAL_CALL setBytes( sal_Int32 parameterIndex, const css::uno::Sequence< sal_Int8 >& x ) override;
+ virtual void SAL_CALL setDate( sal_Int32 parameterIndex, const css::util::Date& x ) override;
+ virtual void SAL_CALL setTime( sal_Int32 parameterIndex, const css::util::Time& x ) override;
+ virtual void SAL_CALL setTimestamp( sal_Int32 parameterIndex, const css::util::DateTime& x ) override;
+ virtual void SAL_CALL setBinaryStream( sal_Int32 parameterIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override;
+ virtual void SAL_CALL setCharacterStream( sal_Int32 parameterIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override;
+ virtual void SAL_CALL setObject( sal_Int32 parameterIndex, const css::uno::Any& x ) override;
+ virtual void SAL_CALL setObjectWithInfo( sal_Int32 parameterIndex, const css::uno::Any& x, sal_Int32 targetSqlType, sal_Int32 scale ) override;
+ virtual void SAL_CALL setRef( sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XRef >& x ) override;
+ virtual void SAL_CALL setBlob( sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XBlob >& x ) override;
+ virtual void SAL_CALL setClob( sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XClob >& x ) override;
+ virtual void SAL_CALL setArray( sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XArray >& x ) override;
+ virtual void SAL_CALL clearParameters( ) override;
+ // XPreparedBatchExecution
+ virtual void SAL_CALL addBatch( ) override;
+ virtual void SAL_CALL clearBatch( ) override;
+ virtual css::uno::Sequence< sal_Int32 > SAL_CALL executeBatch( ) override;
+ // XResultSetMetaDataSupplier
+ virtual css::uno::Reference< css::sdbc::XResultSetMetaData > SAL_CALL getMetaData( ) override;
+
+ public:
+ using java_sql_Statement_Base::executeQuery;
+ using java_sql_Statement_Base::executeUpdate;
+ using java_sql_Statement_Base::execute;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/java/sql/Ref.hxx b/connectivity/source/inc/java/sql/Ref.hxx
new file mode 100644
index 0000000000..f127178b27
--- /dev/null
+++ b/connectivity/source/inc/java/sql/Ref.hxx
@@ -0,0 +1,49 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <java/lang/Object.hxx>
+#include <com/sun/star/sdbc/XRef.hpp>
+#include <cppuhelper/implbase.hxx>
+
+namespace connectivity
+{
+
+ //************ Class: java.sql.Ref
+
+ class java_sql_Ref : public java_lang_Object,
+ public ::cppu::WeakImplHelper< css::sdbc::XRef>
+ {
+ protected:
+ // Static data for the class
+ static jclass theClass;
+ virtual ~java_sql_Ref() override;
+ public:
+ virtual jclass getMyClass() const override;
+
+ // A ctor that is needed for returning the object
+ java_sql_Ref( JNIEnv * pEnv, jobject myObj );
+
+ // XRef
+ virtual OUString SAL_CALL getBaseTypeName( ) override;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/java/sql/ResultSet.hxx b/connectivity/source/inc/java/sql/ResultSet.hxx
new file mode 100644
index 0000000000..183c6fa3a3
--- /dev/null
+++ b/connectivity/source/inc/java/sql/ResultSet.hxx
@@ -0,0 +1,210 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <java/lang/Object.hxx>
+#include <com/sun/star/sdbc/XResultSet.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
+#include <com/sun/star/sdbc/XCloseable.hpp>
+#include <com/sun/star/sdbc/XColumnLocate.hpp>
+#include <com/sun/star/util/XCancellable.hpp>
+#include <com/sun/star/sdbc/XWarningsSupplier.hpp>
+#include <com/sun/star/sdbc/XResultSetUpdate.hpp>
+#include <com/sun/star/sdbc/XRowUpdate.hpp>
+#include <cppuhelper/compbase.hxx>
+#include <comphelper/proparrhlp.hxx>
+#include <connectivity/CommonTools.hxx>
+#include <java/sql/JStatement.hxx>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <java/sql/ConnectionLog.hxx>
+
+namespace connectivity
+{
+
+ /*
+ ** java_sql_ResultSet
+ */
+ typedef ::cppu::WeakComponentImplHelper< css::sdbc::XResultSet,
+ css::sdbc::XRow,
+ css::sdbc::XResultSetMetaDataSupplier,
+ css::util::XCancellable,
+ css::sdbc::XWarningsSupplier,
+ css::sdbc::XResultSetUpdate,
+ css::sdbc::XRowUpdate,
+ css::sdbc::XCloseable,
+ css::sdbc::XColumnLocate,
+ css::lang::XServiceInfo> java_sql_ResultSet_BASE;
+
+ class java_sql_Connection;
+ class java_sql_ResultSet : public cppu::BaseMutex,
+ public java_sql_ResultSet_BASE,
+ public java_lang_Object,
+ public ::cppu::OPropertySetHelper,
+ public ::comphelper::OPropertyArrayUsageHelper<java_sql_ResultSet>
+ {
+ css::uno::Reference< css::uno::XInterface> m_xStatement;
+ java::sql::ConnectionLog m_aLogger;
+ java_sql_Connection* m_pConnection;
+
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ sal_Int32 getResultSetConcurrency() const;
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ sal_Int32 getResultSetType() const;
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ sal_Int32 getFetchDirection() const;
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ sal_Int32 getFetchSize() const;
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ OUString getCursorName() const;
+
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void setFetchDirection(sal_Int32 _par0);
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void setFetchSize(sal_Int32 _par0);
+ protected:
+ // Static data for the class
+ static jclass theClass;
+
+ // OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override;
+ // OPropertySetHelper
+ virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override;
+
+ virtual sal_Bool SAL_CALL convertFastPropertyValue(
+ css::uno::Any & rConvertedValue,
+ css::uno::Any & rOldValue,
+ sal_Int32 nHandle,
+ const css::uno::Any& rValue ) override;
+ virtual void SAL_CALL setFastPropertyValue_NoBroadcast(
+ sal_Int32 nHandle,
+ const css::uno::Any& rValue
+ ) override;
+ virtual void SAL_CALL getFastPropertyValue(
+ css::uno::Any& rValue,
+ sal_Int32 nHandle
+ ) const override;
+ virtual ~java_sql_ResultSet() override;
+ public:
+ DECLARE_SERVICE_INFO();
+ virtual jclass getMyClass() const override;
+ // A ctor that is needed for returning the object
+ java_sql_ResultSet( JNIEnv * pEnv, jobject myObj, const java::sql::ConnectionLog& _rParentLogger,java_sql_Connection& _rConnection,
+ java_sql_Statement_Base* pStmt = nullptr );
+
+ // ::cppu::OComponentHelper
+ virtual void SAL_CALL disposing() override;
+ // XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+ //XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override;
+ // XPropertySet
+ virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override;
+ // XResultSet
+ virtual sal_Bool SAL_CALL next( ) override;
+ virtual sal_Bool SAL_CALL isBeforeFirst( ) override;
+ virtual sal_Bool SAL_CALL isAfterLast( ) override;
+ virtual sal_Bool SAL_CALL isFirst( ) override;
+ virtual sal_Bool SAL_CALL isLast( ) override;
+ virtual void SAL_CALL beforeFirst( ) override;
+ virtual void SAL_CALL afterLast( ) override;
+ virtual sal_Bool SAL_CALL first( ) override;
+ virtual sal_Bool SAL_CALL last( ) override;
+ virtual sal_Int32 SAL_CALL getRow( ) override;
+ virtual sal_Bool SAL_CALL absolute( sal_Int32 row ) override;
+ virtual sal_Bool SAL_CALL relative( sal_Int32 rows ) override;
+ virtual sal_Bool SAL_CALL previous( ) override;
+ virtual void SAL_CALL refreshRow( ) override;
+ virtual sal_Bool SAL_CALL rowUpdated( ) override;
+ virtual sal_Bool SAL_CALL rowInserted( ) override;
+ virtual sal_Bool SAL_CALL rowDeleted( ) override;
+ virtual css::uno::Reference< css::uno::XInterface > SAL_CALL getStatement( ) override;
+ // XRow
+ virtual sal_Bool SAL_CALL wasNull( ) override;
+ virtual OUString SAL_CALL getString( sal_Int32 columnIndex ) override;
+ virtual sal_Bool SAL_CALL getBoolean( sal_Int32 columnIndex ) override;
+ virtual sal_Int8 SAL_CALL getByte( sal_Int32 columnIndex ) override;
+ virtual sal_Int16 SAL_CALL getShort( sal_Int32 columnIndex ) override;
+ virtual sal_Int32 SAL_CALL getInt( sal_Int32 columnIndex ) override;
+ virtual sal_Int64 SAL_CALL getLong( sal_Int32 columnIndex ) override;
+ virtual float SAL_CALL getFloat( sal_Int32 columnIndex ) override;
+ virtual double SAL_CALL getDouble( sal_Int32 columnIndex ) override;
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getBytes( sal_Int32 columnIndex ) override;
+ virtual css::util::Date SAL_CALL getDate( sal_Int32 columnIndex ) override;
+ virtual css::util::Time SAL_CALL getTime( sal_Int32 columnIndex ) override;
+ virtual css::util::DateTime SAL_CALL getTimestamp( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getBinaryStream( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getCharacterStream( sal_Int32 columnIndex ) override;
+ virtual css::uno::Any SAL_CALL getObject( sal_Int32 columnIndex, const css::uno::Reference< css::container::XNameAccess >& typeMap ) override;
+ virtual css::uno::Reference< css::sdbc::XRef > SAL_CALL getRef( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XBlob > SAL_CALL getBlob( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XClob > SAL_CALL getClob( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XArray > SAL_CALL getArray( sal_Int32 columnIndex ) override;
+ // XResultSetMetaDataSupplier
+ virtual css::uno::Reference< css::sdbc::XResultSetMetaData > SAL_CALL getMetaData( ) override;
+ // XCancellable
+ virtual void SAL_CALL cancel( ) override;
+ // XCloseable
+ virtual void SAL_CALL close( ) override;
+ // XWarningsSupplier
+ virtual css::uno::Any SAL_CALL getWarnings( ) override;
+ virtual void SAL_CALL clearWarnings( ) override;
+ // XResultSetUpdate
+ virtual void SAL_CALL insertRow( ) override;
+ virtual void SAL_CALL updateRow( ) override;
+ virtual void SAL_CALL deleteRow( ) override;
+ virtual void SAL_CALL cancelRowUpdates( ) override;
+ virtual void SAL_CALL moveToInsertRow( ) override;
+ virtual void SAL_CALL moveToCurrentRow( ) override;
+ // XRowUpdate
+ virtual void SAL_CALL updateNull( sal_Int32 columnIndex ) override;
+ virtual void SAL_CALL updateBoolean( sal_Int32 columnIndex, sal_Bool x ) override;
+ virtual void SAL_CALL updateByte( sal_Int32 columnIndex, sal_Int8 x ) override;
+ virtual void SAL_CALL updateShort( sal_Int32 columnIndex, sal_Int16 x ) override;
+ virtual void SAL_CALL updateInt( sal_Int32 columnIndex, sal_Int32 x ) override;
+ virtual void SAL_CALL updateLong( sal_Int32 columnIndex, sal_Int64 x ) override;
+ virtual void SAL_CALL updateFloat( sal_Int32 columnIndex, float x ) override;
+ virtual void SAL_CALL updateDouble( sal_Int32 columnIndex, double x ) override;
+ virtual void SAL_CALL updateString( sal_Int32 columnIndex, const OUString& x ) override;
+ virtual void SAL_CALL updateBytes( sal_Int32 columnIndex, const css::uno::Sequence< sal_Int8 >& x ) override;
+ virtual void SAL_CALL updateDate( sal_Int32 columnIndex, const css::util::Date& x ) override;
+ virtual void SAL_CALL updateTime( sal_Int32 columnIndex, const css::util::Time& x ) override;
+ virtual void SAL_CALL updateTimestamp( sal_Int32 columnIndex, const css::util::DateTime& x ) override;
+ virtual void SAL_CALL updateBinaryStream( sal_Int32 columnIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override;
+ virtual void SAL_CALL updateCharacterStream( sal_Int32 columnIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override;
+ virtual void SAL_CALL updateObject( sal_Int32 columnIndex, const css::uno::Any& x ) override;
+ virtual void SAL_CALL updateNumericObject( sal_Int32 columnIndex, const css::uno::Any& x, sal_Int32 scale ) override;
+ // XColumnLocate
+ virtual sal_Int32 SAL_CALL findColumn( const OUString& columnName ) override;
+
+ public:
+ using ::cppu::OPropertySetHelper::getFastPropertyValue;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/java/sql/ResultSetMetaData.hxx b/connectivity/source/inc/java/sql/ResultSetMetaData.hxx
new file mode 100644
index 0000000000..e5017f1158
--- /dev/null
+++ b/connectivity/source/inc/java/sql/ResultSetMetaData.hxx
@@ -0,0 +1,70 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <java/lang/Object.hxx>
+#include <com/sun/star/sdbc/XResultSetMetaData.hpp>
+#include <cppuhelper/implbase.hxx>
+
+namespace connectivity
+{
+
+ //************ Class: java.sql.ResultSetMetaData
+
+ class java_sql_Connection;
+ class java_sql_ResultSetMetaData final : public ::cppu::WeakImplHelper< css::sdbc::XResultSetMetaData>,
+ public java_lang_Object
+ {
+ java_sql_Connection* m_pConnection;
+ sal_Int32 m_nColumnCount;
+
+ // Static data for the class
+ static jclass theClass;
+ virtual ~java_sql_ResultSetMetaData() override;
+ public:
+ virtual jclass getMyClass() const override;
+
+ // A ctor that is needed for returning the object
+ java_sql_ResultSetMetaData( JNIEnv * pEnv, jobject myObj, java_sql_Connection& _rCon );
+
+ virtual sal_Int32 SAL_CALL getColumnCount( ) override;
+ virtual sal_Bool SAL_CALL isAutoIncrement( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isCaseSensitive( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isSearchable( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isCurrency( sal_Int32 column ) override;
+ virtual sal_Int32 SAL_CALL isNullable( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isSigned( sal_Int32 column ) override;
+ virtual sal_Int32 SAL_CALL getColumnDisplaySize( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getColumnLabel( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getColumnName( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getSchemaName( sal_Int32 column ) override;
+ virtual sal_Int32 SAL_CALL getPrecision( sal_Int32 column ) override;
+ virtual sal_Int32 SAL_CALL getScale( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getTableName( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getCatalogName( sal_Int32 column ) override;
+ virtual sal_Int32 SAL_CALL getColumnType( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getColumnTypeName( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isReadOnly( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isWritable( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isDefinitelyWritable( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getColumnServiceName( sal_Int32 column ) override;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/java/sql/SQLException.hxx b/connectivity/source/inc/java/sql/SQLException.hxx
new file mode 100644
index 0000000000..cff1aad466
--- /dev/null
+++ b/connectivity/source/inc/java/sql/SQLException.hxx
@@ -0,0 +1,56 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <java/lang/Exception.hxx>
+#include <com/sun/star/sdbc/SQLException.hpp>
+
+namespace connectivity
+{
+ //************ Class: java.sql.SQLException
+
+ class java_sql_SQLException_BASE;
+ class java_sql_SQLException : public css::sdbc::SQLException
+ {
+ public:
+ // A ctor that is needed for returning the object
+ java_sql_SQLException( const java_sql_SQLException_BASE& _rException,const css::uno::Reference< css::uno::XInterface> & _rContext);
+ };
+
+ class java_sql_SQLException_BASE : public java_lang_Exception
+ {
+ protected:
+ // Static data for the class
+ static jclass theClass;
+ public:
+ virtual jclass getMyClass() const override;
+ virtual ~java_sql_SQLException_BASE() override;
+ // A ctor that is needed for returning the object
+ java_sql_SQLException_BASE( JNIEnv * pEnv, jobject myObj );
+
+ OUString getSQLState() const;
+ sal_Int32 getErrorCode() const;
+ css::sdbc::SQLException getNextException() const;
+
+ static jclass st_getMyClass();
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/java/sql/SQLWarning.hxx b/connectivity/source/inc/java/sql/SQLWarning.hxx
new file mode 100644
index 0000000000..5fd8c97943
--- /dev/null
+++ b/connectivity/source/inc/java/sql/SQLWarning.hxx
@@ -0,0 +1,49 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <java/sql/SQLException.hxx>
+
+namespace connectivity
+{
+ //************ Class: java.sql.SQLWarning
+
+ class java_sql_SQLWarning_BASE : public java_sql_SQLException_BASE
+ {
+ protected:
+ // Static data for the class
+ static jclass theClass;
+ public:
+ virtual jclass getMyClass() const override;
+ virtual ~java_sql_SQLWarning_BASE() override;
+ // A ctor that is needed for returning the object
+ java_sql_SQLWarning_BASE( JNIEnv * pEnv, jobject myObj ) : java_sql_SQLException_BASE( pEnv, myObj ){}
+
+ };
+
+ class java_sql_SQLWarning : public java_sql_SQLException
+ {
+ public:
+ java_sql_SQLWarning(const java_sql_SQLWarning_BASE& _rW,const css::uno::Reference< css::uno::XInterface> & _rContext)
+ : java_sql_SQLException(_rW,_rContext) {}
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/java/sql/Timestamp.hxx b/connectivity/source/inc/java/sql/Timestamp.hxx
new file mode 100644
index 0000000000..599dfb78e4
--- /dev/null
+++ b/connectivity/source/inc/java/sql/Timestamp.hxx
@@ -0,0 +1,88 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <java/util/Date.hxx>
+#include <com/sun/star/util/Date.hpp>
+#include <com/sun/star/util/Time.hpp>
+#include <com/sun/star/util/DateTime.hpp>
+
+
+namespace connectivity
+{
+
+ //************ Class: java.sql.Date
+
+
+ class java_sql_Date : public java_util_Date
+ {
+ protected:
+ // static data for the class
+ static jclass theClass;
+ public:
+ virtual jclass getMyClass() const override;
+ virtual ~java_sql_Date() override;
+ // A ctor that is needed for returning the object
+ java_sql_Date( JNIEnv * pEnv, jobject myObj ) : java_util_Date(pEnv,myObj){}
+ java_sql_Date( const css::util::Date& _rOut );
+
+ operator css::util::Date();
+ static jclass st_getMyClass();
+ };
+
+
+ //************ Class: java.sql.Time
+
+
+ class java_sql_Time : public java_util_Date
+ {
+ protected:
+ // static data for the class
+ static jclass theClass;
+ public:
+ virtual jclass getMyClass() const override;
+ virtual ~java_sql_Time() override;
+ // A ctor that is needed for returning the object
+ java_sql_Time( JNIEnv * pEnv, jobject myObj ) : java_util_Date( pEnv, myObj ){}
+ java_sql_Time( const css::util::Time& _rOut );
+ operator css::util::Time();
+ static jclass st_getMyClass();
+ };
+
+
+ //************ Class: java.sql.Timestamp
+
+ class java_sql_Timestamp : public java_util_Date
+ {
+ protected:
+ // static data for the class
+ static jclass theClass;
+ public:
+ virtual jclass getMyClass() const override;
+ virtual ~java_sql_Timestamp() override;
+ // A ctor that is needed for returning the object
+ java_sql_Timestamp( JNIEnv * pEnv, jobject myObj ) : java_util_Date( pEnv, myObj ){}
+ java_sql_Timestamp( const css::util::DateTime& _rOut);
+ operator css::util::DateTime();
+
+ static jclass st_getMyClass();
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/java/tools.hxx b/connectivity/source/inc/java/tools.hxx
new file mode 100644
index 0000000000..44a35ecee3
--- /dev/null
+++ b/connectivity/source/inc/java/tools.hxx
@@ -0,0 +1,66 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <memory>
+
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/uno/Sequence.h>
+
+#if defined __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunknown-attributes"
+#endif
+#include <jni.h>
+#if defined __clang__
+#pragma clang diagnostic pop
+#endif
+
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <com/sun/star/io/XInputStream.hpp>
+
+
+namespace connectivity
+{
+
+ jstring convertwchar_tToJavaString(JNIEnv *pEnv,const OUString& Temp);
+ OUString JavaString2String(JNIEnv *pEnv,jstring Str);
+ class java_util_Properties;
+
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ std::unique_ptr<java_util_Properties> createStringPropertyArray(const css::uno::Sequence< css::beans::PropertyValue >& info );
+
+ jobject convertTypeMapToJavaMap(const css::uno::Reference< css::container::XNameAccess > & _rMap);
+
+ /** return if an exception occurred
+ the exception will be cleared.
+ @param pEnv
+ The native java env
+ */
+ bool isExceptionOccurred(JNIEnv *pEnv);
+
+ jobject createByteInputStream(const css::uno::Reference< css::io::XInputStream >& x,sal_Int32 length);
+ jobject createCharArrayReader(const css::uno::Reference< css::io::XInputStream >& x,sal_Int32 length);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/java/util/Date.hxx b/connectivity/source/inc/java/util/Date.hxx
new file mode 100644
index 0000000000..fe55242867
--- /dev/null
+++ b/connectivity/source/inc/java/util/Date.hxx
@@ -0,0 +1,45 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <java/lang/Object.hxx>
+//#include <com/sun/star/util/Date.hpp>
+
+namespace connectivity
+{
+
+
+ //************ Class: java.util.Date
+
+
+ class java_util_Date : public java_lang_Object
+ {
+ protected:
+ // Static data for the class
+ static jclass theClass;
+ public:
+ virtual jclass getMyClass() const override;
+ virtual ~java_util_Date() override;
+ // A ctor that is needed for returning the object
+ java_util_Date( JNIEnv * pEnv, jobject myObj ) : java_lang_Object( pEnv, myObj ){}
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/java/util/Property.hxx b/connectivity/source/inc/java/util/Property.hxx
new file mode 100644
index 0000000000..628f951ba4
--- /dev/null
+++ b/connectivity/source/inc/java/util/Property.hxx
@@ -0,0 +1,38 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <java/lang/Object.hxx>
+
+namespace connectivity
+{
+ class java_util_Properties : public java_lang_Object
+ {
+ protected:
+ // Static data for the class
+ static jclass theClass;
+ public:
+ virtual jclass getMyClass() const override;
+ virtual ~java_util_Properties() override;
+ java_util_Properties( );
+ void setProperty(const OUString& key, const OUString& value);
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/mysql/YCatalog.hxx b/connectivity/source/inc/mysql/YCatalog.hxx
new file mode 100644
index 0000000000..5eb348af99
--- /dev/null
+++ b/connectivity/source/inc/mysql/YCatalog.hxx
@@ -0,0 +1,60 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <sdbcx/VCatalog.hxx>
+
+namespace connectivity::mysql
+ {
+ // please don't name the class the same name as in another namespaces
+ // some compilers have problems with this task as I noticed on windows
+ class OMySQLCatalog : public connectivity::sdbcx::OCatalog
+ {
+ css::uno::Reference< css::sdbc::XConnection > m_xConnection;
+
+ /** calls XDatabaseMetaData::getTables.
+ @param _sKindOfObject
+ The type of tables to be fetched.
+ @param _rNames
+ The container for the names to be filled. <OUT/>
+ */
+ void refreshObjects(const css::uno::Sequence< OUString >& _sKindOfObject,::std::vector< OUString>& _rNames);
+
+ public:
+ // implementation of the pure virtual methods
+ virtual void refreshTables() override;
+ virtual void refreshViews() override ;
+ virtual void refreshGroups() override;
+ virtual void refreshUsers() override ;
+
+ public:
+ OMySQLCatalog(const css::uno::Reference< css::sdbc::XConnection >& _xConnection);
+
+ sdbcx::OCollection* getPrivateTables() const { return m_pTables.get();}
+ sdbcx::OCollection* getPrivateViews() const { return m_pViews.get(); }
+ const css::uno::Reference< css::sdbc::XConnection >& getConnection() const { return m_xConnection; }
+
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ // ::cppu::OComponentHelper
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override;
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/mysql/YColumns.hxx b/connectivity/source/inc/mysql/YColumns.hxx
new file mode 100644
index 0000000000..1ffcfc9533
--- /dev/null
+++ b/connectivity/source/inc/mysql/YColumns.hxx
@@ -0,0 +1,56 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+#include <connectivity/TColumnsHelper.hxx>
+#include <connectivity/sdbcx/VColumn.hxx>
+
+namespace connectivity::mysql
+ {
+ class OMySQLColumns : public OColumnsHelper
+ {
+ protected:
+ virtual css::uno::Reference< css::beans::XPropertySet > createDescriptor() override;
+ public:
+ OMySQLColumns( ::cppu::OWeakObject& _rParent
+ ,::osl::Mutex& _rMutex
+ ,const ::std::vector< OUString> &_rVector
+ );
+ };
+
+ class OMySQLColumn;
+ typedef ::comphelper::OIdPropertyArrayUsageHelper<OMySQLColumn> OMySQLColumn_PROP;
+
+ class OMySQLColumn : public sdbcx::OColumn,
+ public OMySQLColumn_PROP
+ {
+ OUString m_sAutoIncrement;
+ protected:
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper( sal_Int32 _nId) const override;
+ virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override;
+
+ public:
+ OMySQLColumn();
+ virtual void construct() override;
+
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/mysql/YDriver.hxx b/connectivity/source/inc/mysql/YDriver.hxx
new file mode 100644
index 0000000000..84fad1af1c
--- /dev/null
+++ b/connectivity/source/inc/mysql/YDriver.hxx
@@ -0,0 +1,106 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <sal/config.h>
+
+#include <map>
+
+#include <com/sun/star/sdbc/XDriver.hpp>
+#include <com/sun/star/sdbcx/XDataDefinitionSupplier.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <cppuhelper/compbase.hxx>
+#include <cppuhelper/basemutex.hxx>
+#include <connectivity/CommonTools.hxx>
+
+
+namespace connectivity
+{
+
+
+ class OMetaConnection;
+
+ namespace mysql
+ {
+ typedef ::cppu::WeakComponentImplHelper< css::sdbc::XDriver
+ , css::sdbcx::XDataDefinitionSupplier
+ , css::lang::XServiceInfo
+ > ODriverDelegator_BASE;
+
+ typedef std::pair< css::uno::WeakReferenceHelper,OMetaConnection*> TWeakConnectionPair;
+ typedef std::pair< css::uno::WeakReferenceHelper,TWeakConnectionPair> TWeakPair;
+ typedef std::vector< TWeakPair > TWeakPairVector;
+ typedef std::map< OUString, css::uno::Reference< css::sdbc::XDriver > > TJDBCDrivers;
+
+ /** delegates all calls to the original driver and extend the existing one with the SDBCX layer.
+
+ */
+ class ODriverDelegator : public ::cppu::BaseMutex
+ ,public ODriverDelegator_BASE
+ {
+ TJDBCDrivers m_aJdbcDrivers; // all jdbc drivers
+ TWeakPairVector m_aConnections; // vector containing a list
+ // of all the Connection objects
+ // for this Driver
+ css::uno::Reference< css::sdbc::XDriver > m_xODBCDriver;
+ css::uno::Reference< css::sdbc::XDriver > m_xNativeDriver;
+ css::uno::Reference< css::uno::XComponentContext > m_xContext;
+
+ /** load the driver we want to delegate.
+ The <member>m_xODBCDriver</member> or <member>m_xDBCDriver</member> may be <NULL/> if the driver could not be loaded.
+ @param url
+ The URL.
+ @param info
+ The property info contains which driver we have to delegate.
+ @return
+ The driver which was currently selected.
+ */
+ css::uno::Reference< css::sdbc::XDriver > loadDriver( std::u16string_view url, const css::uno::Sequence< css::beans::PropertyValue >& info );
+
+ public:
+ /** creates a new delegator for a mysql driver
+ */
+ ODriverDelegator(const css::uno::Reference< css::uno::XComponentContext >& _rxContext);
+
+ // XServiceInfo
+ DECLARE_SERVICE_INFO();
+
+ // XDriver
+ virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL connect( const OUString& url, const css::uno::Sequence< css::beans::PropertyValue >& info ) override;
+ virtual sal_Bool SAL_CALL acceptsURL( const OUString& url ) override;
+ virtual css::uno::Sequence< css::sdbc::DriverPropertyInfo > SAL_CALL getPropertyInfo( const OUString& url, const css::uno::Sequence< css::beans::PropertyValue >& info ) override;
+ virtual sal_Int32 SAL_CALL getMajorVersion( ) override;
+ virtual sal_Int32 SAL_CALL getMinorVersion( ) override;
+
+ // XDataDefinitionSupplier
+ virtual css::uno::Reference< css::sdbcx::XTablesSupplier > SAL_CALL getDataDefinitionByConnection( const css::uno::Reference< css::sdbc::XConnection >& connection ) override;
+ virtual css::uno::Reference< css::sdbcx::XTablesSupplier > SAL_CALL getDataDefinitionByURL( const OUString& url, const css::uno::Sequence< css::beans::PropertyValue >& info ) override;
+ protected:
+ /// dtor
+ virtual ~ODriverDelegator() override;
+ // OComponentHelper
+ virtual void SAL_CALL disposing() override;
+ };
+ }
+
+
+} // namespace connectivity
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/mysql/YTable.hxx b/connectivity/source/inc/mysql/YTable.hxx
new file mode 100644
index 0000000000..c891b7d7d9
--- /dev/null
+++ b/connectivity/source/inc/mysql/YTable.hxx
@@ -0,0 +1,112 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <string_view>
+
+#include <connectivity/TTableHelper.hxx>
+#include <comphelper/IdPropArrayHelper.hxx>
+
+namespace connectivity::mysql
+ {
+
+ class OMySQLTable;
+ typedef ::comphelper::OIdPropertyArrayUsageHelper< OMySQLTable > OMySQLTable_PROP;
+ class OMySQLTable : public OTableHelper
+ ,public OMySQLTable_PROP
+ {
+ sal_Int32 m_nPrivileges; // we have to set our privileges by our own
+
+ /** executes the statement.
+ @param _rStatement
+ The statement to execute.
+ */
+ void executeStatement(const OUString& _rStatement );
+ protected:
+
+ /** creates the column collection for the table
+ @param _rNames
+ The column names.
+ */
+ virtual sdbcx::OCollection* createColumns(const ::std::vector< OUString>& _rNames) override;
+
+ /** creates the key collection for the table
+ @param _rNames
+ The key names.
+ */
+ virtual sdbcx::OCollection* createKeys(const ::std::vector< OUString>& _rNames) override;
+
+ /** creates the index collection for the table
+ @param _rNames
+ The index names.
+ */
+ virtual sdbcx::OCollection* createIndexes(const ::std::vector< OUString>& _rNames) override;
+
+ /** Returns always "RENAME TABLE " even for views.
+ *
+ * \return The start of the rename statement.
+ * @see http://dev.mysql.com/doc/refman/5.1/de/rename-table.html
+ */
+ virtual OUString getRenameStart() const override;
+
+ /** used to implement the creation of the array helper which is shared amongst all instances of the class.
+ This method needs to be implemented in derived classes.
+ <BR>
+ The method gets called with s_aMutex acquired.
+ @return a pointer to the newly created array helper. Must not be NULL.
+ */
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper(sal_Int32 nId) const override;
+ virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override;
+
+ public:
+ OMySQLTable( sdbcx::OCollection* _pTables,
+ const css::uno::Reference< css::sdbc::XConnection >& _xConnection);
+ OMySQLTable( sdbcx::OCollection* _pTables,
+ const css::uno::Reference< css::sdbc::XConnection >& _xConnection,
+ const OUString& Name,
+ const OUString& Type,
+ const OUString& Description,
+ const OUString& SchemaName,
+ const OUString& CatalogName,
+ sal_Int32 _nPrivileges
+ );
+
+ // ODescriptor
+ virtual void construct() override;
+
+ // XAlterTable
+ virtual void SAL_CALL alterColumnByName( const OUString& colName, const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override;
+ /** returns the ALTER TABLE XXX statement
+ */
+ OUString getAlterTableColumnPart() const;
+
+ // some methods to alter table structures
+ void alterColumnType(sal_Int32 nNewType,const OUString& _rColName,const css::uno::Reference< css::beans::XPropertySet >& _xDescriptor);
+ void alterDefaultValue(std::u16string_view _sNewDefault,const OUString& _rColName);
+ void dropDefaultValue(const OUString& _sNewDefault);
+
+ virtual OUString getTypeCreatePattern() const override;
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/mysql/YTables.hxx b/connectivity/source/inc/mysql/YTables.hxx
new file mode 100644
index 0000000000..3e3283ca96
--- /dev/null
+++ b/connectivity/source/inc/mysql/YTables.hxx
@@ -0,0 +1,63 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <connectivity/sdbcx/VCollection.hxx>
+#include <SQLStatementHelper.hxx>
+#include <com/sun/star/sdbc/XDatabaseMetaData.hpp>
+#include <utility>
+namespace connectivity::mysql
+ {
+ class OTables final : public sdbcx::OCollection,
+ public ::dbtools::ISQLStatementHelper
+ {
+ css::uno::Reference< css::sdbc::XDatabaseMetaData > m_xMetaData;
+
+ virtual sdbcx::ObjectType createObject(const OUString& _rName) override;
+ virtual void impl_refresh() override;
+ virtual css::uno::Reference< css::beans::XPropertySet > createDescriptor() override;
+ virtual sdbcx::ObjectType appendObject( const OUString& _rForName, const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override;
+ virtual void dropObject(sal_Int32 _nPos, const OUString& _sElementName) override;
+
+ void createTable( const css::uno::Reference< css::beans::XPropertySet >& descriptor );
+ virtual OUString getNameForObject(const sdbcx::ObjectType& _xObject) override;
+ public:
+ OTables(css::uno::Reference< css::sdbc::XDatabaseMetaData > _xMetaData, ::cppu::OWeakObject& _rParent, ::osl::Mutex& _rMutex,
+ const ::std::vector< OUString> &_rVector) : sdbcx::OCollection(_rParent, true, _rMutex, _rVector)
+ ,m_xMetaData(std::move(_xMetaData))
+ {}
+
+ // only the name is identical to ::cppu::OComponentHelper
+ virtual void disposing() override;
+
+ // XDrop
+ void appendNew(const OUString& _rsNewTable);
+
+ /** convert the sql statement to fit MySQL notation
+ @param _sSql in/out
+ */
+ static OUString adjustSQL(const OUString& _sSql);
+
+ // ISQLStatementHelper
+ virtual void addComment(const css::uno::Reference< css::beans::XPropertySet >& descriptor,OUStringBuffer& _rOut) override;
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/mysql/YUser.hxx b/connectivity/source/inc/mysql/YUser.hxx
new file mode 100644
index 0000000000..1713f63bfb
--- /dev/null
+++ b/connectivity/source/inc/mysql/YUser.hxx
@@ -0,0 +1,73 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sdbcx/VUser.hxx>
+#include <com/sun/star/sdbc/XConnection.hpp>
+
+namespace connectivity::mysql
+ {
+ typedef connectivity::sdbcx::OUser OUser_TYPEDEF;
+
+ class OMySQLUser : public OUser_TYPEDEF
+ {
+ css::uno::Reference< css::sdbc::XConnection > m_xConnection;
+
+ static OUString getPrivilegeString(sal_Int32 nRights);
+ // return the privileges and additional the grant rights
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void findPrivilegesAndGrantPrivileges(const OUString& objName, sal_Int32 objType,sal_Int32& nRights,sal_Int32& nRightsWithGrant);
+ public:
+ virtual void refreshGroups() override;
+ public:
+ OMySQLUser( css::uno::Reference< css::sdbc::XConnection > _xConnection);
+ OMySQLUser( css::uno::Reference< css::sdbc::XConnection > _xConnection, const OUString& Name);
+
+ // XUser
+ virtual void SAL_CALL changePassword( const OUString& objPassword, const OUString& newPassword ) override;
+ // XAuthorizable
+ virtual sal_Int32 SAL_CALL getPrivileges( const OUString& objName, sal_Int32 objType ) override;
+ virtual sal_Int32 SAL_CALL getGrantablePrivileges( const OUString& objName, sal_Int32 objType ) override;
+ virtual void SAL_CALL grantPrivileges( const OUString& objName, sal_Int32 objType, sal_Int32 objPrivileges ) override;
+ virtual void SAL_CALL revokePrivileges( const OUString& objName, sal_Int32 objType, sal_Int32 objPrivileges ) override;
+ };
+
+ class OUserExtend;
+ typedef ::comphelper::OPropertyArrayUsageHelper<OUserExtend> OUserExtend_PROP;
+
+ class OUserExtend : public OMySQLUser,
+ public OUserExtend_PROP
+ {
+ OUString m_Password;
+ protected:
+ // OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper() const override;
+ // OPropertySetHelper
+ virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override;
+ public:
+ OUserExtend(const css::uno::Reference< css::sdbc::XConnection >& _xConnection);
+
+ virtual void construct() override;
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/mysql/YUsers.hxx b/connectivity/source/inc/mysql/YUsers.hxx
new file mode 100644
index 0000000000..e4b35c12e7
--- /dev/null
+++ b/connectivity/source/inc/mysql/YUsers.hxx
@@ -0,0 +1,52 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <connectivity/sdbcx/VCollection.hxx>
+#include <com/sun/star/sdbc/XConnection.hpp>
+namespace connectivity
+{
+ namespace sdbcx
+ {
+ class IRefreshableUsers;
+ }
+ namespace mysql
+ {
+ class OUsers : public sdbcx::OCollection
+ {
+ css::uno::Reference< css::sdbc::XConnection > m_xConnection;
+ connectivity::sdbcx::IRefreshableUsers* m_pParent;
+ public:
+ virtual sdbcx::ObjectType createObject(const OUString& _rName) override;
+ virtual css::uno::Reference< css::beans::XPropertySet > createDescriptor() override;
+ virtual void impl_refresh() override;
+ virtual sdbcx::ObjectType appendObject( const OUString& _rForName, const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override;
+ virtual void dropObject(sal_Int32 _nPos,const OUString& _sElementName) override;
+ public:
+ OUsers( ::cppu::OWeakObject& _rParent,
+ ::osl::Mutex& _rMutex,
+ const ::std::vector< OUString> &_rVector,
+ css::uno::Reference< css::sdbc::XConnection > _xConnection,
+ connectivity::sdbcx::IRefreshableUsers* _pParent);
+ };
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/mysql/YViews.hxx b/connectivity/source/inc/mysql/YViews.hxx
new file mode 100644
index 0000000000..2e9a1b2516
--- /dev/null
+++ b/connectivity/source/inc/mysql/YViews.hxx
@@ -0,0 +1,52 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <connectivity/sdbcx/VCollection.hxx>
+#include <com/sun/star/sdbc/XDatabaseMetaData.hpp>
+#include <utility>
+namespace connectivity::mysql
+ {
+ class OViews final : public sdbcx::OCollection
+ {
+ css::uno::Reference< css::sdbc::XDatabaseMetaData > m_xMetaData;
+ bool m_bInDrop;
+ virtual sdbcx::ObjectType createObject(const OUString& _rName) override;
+ virtual void impl_refresh() override;
+ virtual css::uno::Reference< css::beans::XPropertySet > createDescriptor() override;
+ virtual sdbcx::ObjectType appendObject( const OUString& _rForName, const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override;
+ virtual void dropObject(sal_Int32 _nPos, const OUString& _sElementName) override;
+
+ void createView( const css::uno::Reference< css::beans::XPropertySet >& descriptor );
+ public:
+ OViews(css::uno::Reference< css::sdbc::XDatabaseMetaData > _xMetaData, ::cppu::OWeakObject& _rParent, ::osl::Mutex& _rMutex,
+ const ::std::vector< OUString> &_rVector) : sdbcx::OCollection(_rParent, true, _rMutex, _rVector)
+ ,m_xMetaData(std::move(_xMetaData))
+ ,m_bInDrop(false)
+ {}
+
+ // only the name is identical to ::cppu::OComponentHelper
+ virtual void disposing() override;
+
+ void dropByNameImpl(const OUString& elementName);
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/odbc/OBoundParam.hxx b/connectivity/source/inc/odbc/OBoundParam.hxx
new file mode 100644
index 0000000000..77d09ba297
--- /dev/null
+++ b/connectivity/source/inc/odbc/OBoundParam.hxx
@@ -0,0 +1,128 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <com/sun/star/io/XInputStream.hpp>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <odbc/odbcbasedllapi.hxx>
+#include <connectivity/odbc.hxx>
+
+namespace connectivity::odbc
+ {
+ class OOO_DLLPUBLIC_ODBCBASE OBoundParam
+ {
+
+ public:
+ OBoundParam()
+ : binaryData(nullptr)
+ , paramLength(0)
+ , paramInputStreamLen(0)
+ {
+ }
+ ~OBoundParam()
+ {
+ free(binaryData);
+ }
+
+ // allocBindDataBuffer
+ // Allocates and returns a new bind data buffer of the specified
+ // length
+
+ void* allocBindDataBuffer (sal_Int32 bufLen)
+ {
+ // Reset the input stream and sequence, we are doing a new bind
+ setInputStream (nullptr, 0);
+ aSequence.realloc(0);
+
+ free(binaryData);
+ binaryData = (bufLen > 0) ? malloc(bufLen) : nullptr;
+
+ return binaryData;
+ }
+
+
+ // getBindLengthBuffer
+ // Returns the length buffer to be used when binding to a parameter
+
+ SQLLEN& getBindLengthBuffer ()
+ {
+ return paramLength;
+ }
+
+
+ // setInputStream
+ // Sets the input stream for the bound parameter
+
+ void setInputStream(const css::uno::Reference< css::io::XInputStream>& inputStream,
+ sal_Int32 len)
+ {
+ paramInputStream = inputStream;
+ paramInputStreamLen = len;
+ }
+
+ void setSequence(const css::uno::Sequence< sal_Int8 >& _aSequence)
+ {
+ aSequence = _aSequence;
+ }
+
+
+ // getInputStream
+ // Gets the input stream for the bound parameter
+
+ const css::uno::Reference< css::io::XInputStream>& getInputStream () const
+ {
+ return paramInputStream;
+ }
+
+
+ // getInputStreamLen
+ // Gets the input stream length for the bound parameter
+
+ sal_Int32 getInputStreamLen () const
+ {
+ return paramInputStreamLen;
+ }
+
+
+ private:
+
+ // Data attributes
+
+
+ void *binaryData; // Storage area to be used
+ // when binding the parameter
+
+ SQLLEN paramLength; // Storage area to be used
+ // for the bound length of the
+ // parameter. Note that this
+ // data is in native format.
+
+ css::uno::Reference< css::io::XInputStream> paramInputStream;
+ css::uno::Sequence< sal_Int8 > aSequence;
+ // When an input stream is
+ // bound to a parameter, a
+ // reference to the input stream is saved
+ // until not needed anymore.
+
+ sal_Int32 paramInputStreamLen; // Length of input stream
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/odbc/OConnection.hxx b/connectivity/source/inc/odbc/OConnection.hxx
new file mode 100644
index 0000000000..b08544b859
--- /dev/null
+++ b/connectivity/source/inc/odbc/OConnection.hxx
@@ -0,0 +1,126 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <com/sun/star/sdbc/SQLWarning.hpp>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <connectivity/odbc.hxx>
+#include <odbc/odbcbasedllapi.hxx>
+#include <connectivity/CommonTools.hxx>
+#include <TConnection.hxx>
+#include <OTypeInfo.hxx>
+#include <odbc/OTools.hxx>
+#include <cppuhelper/weakref.hxx>
+#include <AutoRetrievingBase.hxx>
+#include <osl/module.h>
+#include <rtl/ref.hxx>
+
+
+#include <map>
+
+namespace connectivity::odbc
+ {
+ class ODBCDriver;
+
+ typedef connectivity::OMetaConnection OConnection_BASE;
+ typedef std::vector< ::connectivity::OTypeInfo> TTypeInfoVector;
+
+ class OOO_DLLPUBLIC_ODBCBASE OConnection final :
+ public OConnection_BASE,
+ public OAutoRetrievingBase
+ {
+ // Data attributes
+
+ std::map< SQLHANDLE, rtl::Reference<OConnection>> m_aConnections; // holds all connections which are need for several statements
+
+
+ OUString m_sUser; // the user name
+ rtl::Reference<ODBCDriver>
+ m_xDriver; // Pointer to the owning
+ // driver object
+
+ SQLHANDLE m_aConnectionHandle;
+ SQLHANDLE m_pDriverHandleCopy; // performance reason
+ sal_Int32 m_nStatementCount;
+ bool m_bClosed;
+ bool m_bUseCatalog; // should we use the catalog on filebased databases
+ bool m_bUseOldDateFormat;
+ bool m_bIgnoreDriverPrivileges;
+ bool m_bPreventGetVersionColumns; // #i60273#
+ bool m_bReadOnly;
+
+
+ SQLRETURN OpenConnection(const OUString& aConnectStr,sal_Int32 nTimeOut, bool bSilent);
+
+ public:
+ oslGenericFunction getOdbcFunction(ODBC3SQLFunctionId _nIndex) const;
+ /// @throws css::sdbc::SQLException
+ SQLRETURN Construct( const OUString& url,const css::uno::Sequence< css::beans::PropertyValue >& info);
+
+ OConnection(const SQLHANDLE _pDriverHandle,ODBCDriver* _pDriver);
+ // OConnection(const SQLHANDLE _pConnectionHandle);
+ virtual ~OConnection() override;
+
+ // OComponentHelper
+ virtual void SAL_CALL disposing() override;
+
+ // XServiceInfo
+ DECLARE_SERVICE_INFO();
+ // XConnection
+ virtual css::uno::Reference< css::sdbc::XStatement > SAL_CALL createStatement( ) override;
+ virtual css::uno::Reference< css::sdbc::XPreparedStatement > SAL_CALL prepareStatement( const OUString& sql ) override;
+ virtual css::uno::Reference< css::sdbc::XPreparedStatement > SAL_CALL prepareCall( const OUString& sql ) override;
+ virtual OUString SAL_CALL nativeSQL( const OUString& sql ) override;
+ virtual void SAL_CALL setAutoCommit( sal_Bool autoCommit ) override;
+ virtual sal_Bool SAL_CALL getAutoCommit( ) override;
+ virtual void SAL_CALL commit( ) override;
+ virtual void SAL_CALL rollback( ) override;
+ virtual sal_Bool SAL_CALL isClosed( ) override;
+ virtual css::uno::Reference< css::sdbc::XDatabaseMetaData > SAL_CALL getMetaData( ) override;
+ virtual void SAL_CALL setReadOnly( sal_Bool readOnly ) override;
+ virtual sal_Bool SAL_CALL isReadOnly( ) override;
+ virtual void SAL_CALL setCatalog( const OUString& catalog ) override;
+ virtual OUString SAL_CALL getCatalog( ) override;
+ virtual void SAL_CALL setTransactionIsolation( sal_Int32 level ) override;
+ virtual sal_Int32 SAL_CALL getTransactionIsolation( ) override;
+ virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getTypeMap( ) override;
+ virtual void SAL_CALL setTypeMap( const css::uno::Reference< css::container::XNameAccess >& typeMap ) override;
+ // XCloseable
+ virtual void SAL_CALL close( ) override;
+ // XWarningsSupplier
+ virtual css::uno::Any SAL_CALL getWarnings( ) override;
+ virtual void SAL_CALL clearWarnings( ) override;
+
+ SQLHANDLE getConnection() { return m_aConnectionHandle; }
+
+ // should we use the catalog on filebased databases
+ bool isCatalogUsed() const { return m_bUseCatalog; }
+ bool isIgnoreDriverPrivilegesEnabled() const { return m_bIgnoreDriverPrivileges; }
+ bool preventGetVersionColumns() const { return m_bPreventGetVersionColumns; }
+ bool useOldDateFormat() const { return m_bUseOldDateFormat; }
+ ODBCDriver* getDriver() const { return m_xDriver.get();}
+
+ SQLHANDLE createStatementHandle();
+ // close and free the handle and set it to SQL_NULLHANDLE
+ void freeStatementHandle(SQLHANDLE& _pHandle);
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/odbc/ODatabaseMetaData.hxx b/connectivity/source/inc/odbc/ODatabaseMetaData.hxx
new file mode 100644
index 0000000000..b0b4a6552a
--- /dev/null
+++ b/connectivity/source/inc/odbc/ODatabaseMetaData.hxx
@@ -0,0 +1,203 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <odbc/OConnection.hxx>
+#include <odbc/odbcbasedllapi.hxx>
+#include <TDatabaseMetaDataBase.hxx>
+
+namespace connectivity::odbc
+ {
+
+ //************ Class: ODatabaseMetaData
+
+
+ class OOO_DLLPUBLIC_ODBCBASE ODatabaseMetaData final :
+ public ODatabaseMetaDataBase
+ {
+ SQLHANDLE m_aConnectionHandle;
+ OConnection* m_pConnection;
+ bool m_bUseCatalog;
+
+ // cached database information
+ virtual OUString impl_getIdentifierQuoteString_throw( ) override;
+ virtual bool impl_isCatalogAtStart_throw( ) override;
+ virtual OUString impl_getCatalogSeparator_throw( ) override;
+ virtual bool impl_supportsCatalogsInTableDefinitions_throw( ) override;
+ virtual bool impl_supportsSchemasInTableDefinitions_throw( ) override ;
+ virtual bool impl_supportsCatalogsInDataManipulation_throw( ) override;
+ virtual bool impl_supportsSchemasInDataManipulation_throw( ) override ;
+ virtual bool impl_supportsMixedCaseQuotedIdentifiers_throw( ) override ;
+ virtual bool impl_supportsAlterTableWithAddColumn_throw( ) override;
+ virtual bool impl_supportsAlterTableWithDropColumn_throw( ) override;
+ virtual sal_Int32 impl_getMaxStatements_throw( ) override;
+ virtual sal_Int32 impl_getMaxTablesInSelect_throw( ) override;
+ virtual bool impl_storesMixedCaseQuotedIdentifiers_throw( ) override;
+ OUString getURLImpl();
+ virtual css::uno::Reference< css::sdbc::XResultSet > impl_getTypeInfo_throw() override;
+ virtual ~ODatabaseMetaData() override;
+
+ public:
+ ODatabaseMetaData(const SQLHANDLE _pHandle,OConnection* _pCon);
+
+ // XDatabaseMetaData
+ virtual sal_Bool SAL_CALL allProceduresAreCallable( ) override;
+ virtual sal_Bool SAL_CALL allTablesAreSelectable( ) override;
+ virtual OUString SAL_CALL getURL( ) override;
+ virtual OUString SAL_CALL getUserName( ) override;
+ virtual sal_Bool SAL_CALL isReadOnly( ) override;
+ virtual sal_Bool SAL_CALL nullsAreSortedHigh( ) override;
+ virtual sal_Bool SAL_CALL nullsAreSortedLow( ) override;
+ virtual sal_Bool SAL_CALL nullsAreSortedAtStart( ) override;
+ virtual sal_Bool SAL_CALL nullsAreSortedAtEnd( ) override;
+ virtual OUString SAL_CALL getDatabaseProductName( ) override;
+ virtual OUString SAL_CALL getDatabaseProductVersion( ) override;
+ virtual OUString SAL_CALL getDriverName( ) override;
+ virtual OUString SAL_CALL getDriverVersion( ) override;
+ virtual sal_Int32 SAL_CALL getDriverMajorVersion( ) override;
+ virtual sal_Int32 SAL_CALL getDriverMinorVersion( ) override;
+ virtual sal_Bool SAL_CALL usesLocalFiles( ) override;
+ virtual sal_Bool SAL_CALL usesLocalFilePerTable( ) override;
+ virtual sal_Bool SAL_CALL supportsMixedCaseIdentifiers( ) override;
+ virtual sal_Bool SAL_CALL storesUpperCaseIdentifiers( ) override;
+ virtual sal_Bool SAL_CALL storesLowerCaseIdentifiers( ) override;
+ virtual sal_Bool SAL_CALL storesMixedCaseIdentifiers( ) override;
+
+ virtual sal_Bool SAL_CALL storesUpperCaseQuotedIdentifiers( ) override;
+ virtual sal_Bool SAL_CALL storesLowerCaseQuotedIdentifiers( ) override;
+
+ virtual OUString SAL_CALL getSQLKeywords( ) override;
+ virtual OUString SAL_CALL getNumericFunctions( ) override;
+ virtual OUString SAL_CALL getStringFunctions( ) override;
+ virtual OUString SAL_CALL getSystemFunctions( ) override;
+ virtual OUString SAL_CALL getTimeDateFunctions( ) override;
+ virtual OUString SAL_CALL getSearchStringEscape( ) override;
+ virtual OUString SAL_CALL getExtraNameCharacters( ) override;
+ virtual sal_Bool SAL_CALL supportsColumnAliasing( ) override;
+ virtual sal_Bool SAL_CALL nullPlusNonNullIsNull( ) override;
+ virtual sal_Bool SAL_CALL supportsTypeConversion( ) override;
+ virtual sal_Bool SAL_CALL supportsConvert( sal_Int32 fromType, sal_Int32 toType ) override;
+ virtual sal_Bool SAL_CALL supportsTableCorrelationNames( ) override;
+ virtual sal_Bool SAL_CALL supportsDifferentTableCorrelationNames( ) override;
+ virtual sal_Bool SAL_CALL supportsExpressionsInOrderBy( ) override;
+ virtual sal_Bool SAL_CALL supportsOrderByUnrelated( ) override;
+ virtual sal_Bool SAL_CALL supportsGroupBy( ) override;
+ virtual sal_Bool SAL_CALL supportsGroupByUnrelated( ) override;
+ virtual sal_Bool SAL_CALL supportsGroupByBeyondSelect( ) override;
+ virtual sal_Bool SAL_CALL supportsLikeEscapeClause( ) override;
+ virtual sal_Bool SAL_CALL supportsMultipleResultSets( ) override;
+ virtual sal_Bool SAL_CALL supportsMultipleTransactions( ) override;
+ virtual sal_Bool SAL_CALL supportsNonNullableColumns( ) override;
+ virtual sal_Bool SAL_CALL supportsMinimumSQLGrammar( ) override;
+ virtual sal_Bool SAL_CALL supportsCoreSQLGrammar( ) override;
+ virtual sal_Bool SAL_CALL supportsExtendedSQLGrammar( ) override;
+ virtual sal_Bool SAL_CALL supportsANSI92EntryLevelSQL( ) override;
+ virtual sal_Bool SAL_CALL supportsANSI92IntermediateSQL( ) override;
+ virtual sal_Bool SAL_CALL supportsANSI92FullSQL( ) override;
+ virtual sal_Bool SAL_CALL supportsIntegrityEnhancementFacility( ) override;
+ virtual sal_Bool SAL_CALL supportsOuterJoins( ) override;
+ virtual sal_Bool SAL_CALL supportsFullOuterJoins( ) override;
+ virtual sal_Bool SAL_CALL supportsLimitedOuterJoins( ) override;
+ virtual OUString SAL_CALL getSchemaTerm( ) override;
+ virtual OUString SAL_CALL getProcedureTerm( ) override;
+ virtual OUString SAL_CALL getCatalogTerm( ) override;
+
+ virtual sal_Bool SAL_CALL supportsSchemasInProcedureCalls( ) override;
+ virtual sal_Bool SAL_CALL supportsSchemasInIndexDefinitions( ) override;
+ virtual sal_Bool SAL_CALL supportsSchemasInPrivilegeDefinitions( ) override;
+ virtual sal_Bool SAL_CALL supportsCatalogsInProcedureCalls( ) override;
+
+ virtual sal_Bool SAL_CALL supportsCatalogsInIndexDefinitions( ) override;
+ virtual sal_Bool SAL_CALL supportsCatalogsInPrivilegeDefinitions( ) override;
+ virtual sal_Bool SAL_CALL supportsPositionedDelete( ) override;
+ virtual sal_Bool SAL_CALL supportsPositionedUpdate( ) override;
+ virtual sal_Bool SAL_CALL supportsSelectForUpdate( ) override;
+ virtual sal_Bool SAL_CALL supportsStoredProcedures( ) override;
+ virtual sal_Bool SAL_CALL supportsSubqueriesInComparisons( ) override;
+ virtual sal_Bool SAL_CALL supportsSubqueriesInExists( ) override;
+ virtual sal_Bool SAL_CALL supportsSubqueriesInIns( ) override;
+ virtual sal_Bool SAL_CALL supportsSubqueriesInQuantifieds( ) override;
+ virtual sal_Bool SAL_CALL supportsCorrelatedSubqueries( ) override;
+ virtual sal_Bool SAL_CALL supportsUnion( ) override;
+ virtual sal_Bool SAL_CALL supportsUnionAll( ) override;
+ virtual sal_Bool SAL_CALL supportsOpenCursorsAcrossCommit( ) override;
+ virtual sal_Bool SAL_CALL supportsOpenCursorsAcrossRollback( ) override;
+ virtual sal_Bool SAL_CALL supportsOpenStatementsAcrossCommit( ) override;
+ virtual sal_Bool SAL_CALL supportsOpenStatementsAcrossRollback( ) override;
+ virtual sal_Int32 SAL_CALL getMaxBinaryLiteralLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxCharLiteralLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxColumnNameLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxColumnsInGroupBy( ) override;
+ virtual sal_Int32 SAL_CALL getMaxColumnsInIndex( ) override;
+ virtual sal_Int32 SAL_CALL getMaxColumnsInOrderBy( ) override;
+ virtual sal_Int32 SAL_CALL getMaxColumnsInSelect( ) override;
+ virtual sal_Int32 SAL_CALL getMaxColumnsInTable( ) override;
+ virtual sal_Int32 SAL_CALL getMaxConnections( ) override;
+ virtual sal_Int32 SAL_CALL getMaxCursorNameLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxIndexLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxSchemaNameLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxProcedureNameLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxCatalogNameLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxRowSize( ) override;
+ virtual sal_Bool SAL_CALL doesMaxRowSizeIncludeBlobs( ) override;
+ virtual sal_Int32 SAL_CALL getMaxStatementLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxTableNameLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxUserNameLength( ) override;
+ virtual sal_Int32 SAL_CALL getDefaultTransactionIsolation( ) override;
+ virtual sal_Bool SAL_CALL supportsTransactions( ) override;
+ virtual sal_Bool SAL_CALL supportsTransactionIsolationLevel( sal_Int32 level ) override;
+ virtual sal_Bool SAL_CALL supportsDataDefinitionAndDataManipulationTransactions( ) override;
+ virtual sal_Bool SAL_CALL supportsDataManipulationTransactionsOnly( ) override;
+ virtual sal_Bool SAL_CALL dataDefinitionCausesTransactionCommit( ) override;
+ virtual sal_Bool SAL_CALL dataDefinitionIgnoredInTransactions( ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getProcedures( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& procedureNamePattern ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getProcedureColumns( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& procedureNamePattern, const OUString& columnNamePattern ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getTables( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& tableNamePattern, const css::uno::Sequence< OUString >& types ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getSchemas( ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getCatalogs( ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getTableTypes( ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getColumns( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& tableNamePattern, const OUString& columnNamePattern ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getColumnPrivileges( const css::uno::Any& catalog, const OUString& schema, const OUString& table, const OUString& columnNamePattern ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getTablePrivileges( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& tableNamePattern ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getBestRowIdentifier( const css::uno::Any& catalog, const OUString& schema, const OUString& table, sal_Int32 scope, sal_Bool nullable ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getVersionColumns( const css::uno::Any& catalog, const OUString& schema, const OUString& table ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getPrimaryKeys( const css::uno::Any& catalog, const OUString& schema, const OUString& table ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getImportedKeys( const css::uno::Any& catalog, const OUString& schema, const OUString& table ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getExportedKeys( const css::uno::Any& catalog, const OUString& schema, const OUString& table ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getCrossReference( const css::uno::Any& primaryCatalog, const OUString& primarySchema, const OUString& primaryTable, const css::uno::Any& foreignCatalog, const OUString& foreignSchema, const OUString& foreignTable ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getIndexInfo( const css::uno::Any& catalog, const OUString& schema, const OUString& table, sal_Bool unique, sal_Bool approximate ) override;
+ virtual sal_Bool SAL_CALL supportsResultSetType( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL supportsResultSetConcurrency( sal_Int32 setType, sal_Int32 concurrency ) override;
+ virtual sal_Bool SAL_CALL ownUpdatesAreVisible( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL ownDeletesAreVisible( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL ownInsertsAreVisible( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL othersUpdatesAreVisible( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL othersDeletesAreVisible( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL othersInsertsAreVisible( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL updatesAreDetected( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL deletesAreDetected( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL insertsAreDetected( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL supportsBatchUpdates( ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getUDTs( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& typeNamePattern, const css::uno::Sequence< sal_Int32 >& types ) override;
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/odbc/ODatabaseMetaDataResultSet.hxx b/connectivity/source/inc/odbc/ODatabaseMetaDataResultSet.hxx
new file mode 100644
index 0000000000..5d6982807d
--- /dev/null
+++ b/connectivity/source/inc/odbc/ODatabaseMetaDataResultSet.hxx
@@ -0,0 +1,259 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/sdbc/ResultSetType.hpp>
+#include <com/sun/star/sdbc/FetchDirection.hpp>
+#include <com/sun/star/sdbc/ResultSetConcurrency.hpp>
+#include <com/sun/star/sdbc/XResultSet.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
+#include <com/sun/star/sdbc/XCloseable.hpp>
+#include <com/sun/star/sdbc/XColumnLocate.hpp>
+#include <com/sun/star/util/XCancellable.hpp>
+#include <com/sun/star/sdbc/XWarningsSupplier.hpp>
+#include <com/sun/star/sdbc/XResultSetUpdate.hpp>
+#include <com/sun/star/sdbc/XRowUpdate.hpp>
+#include <cppuhelper/compbase.hxx>
+#include <cppuhelper/basemutex.hxx>
+#include <comphelper/proparrhlp.hxx>
+#include <odbc/OStatement.hxx>
+#include <odbc/ODatabaseMetaData.hxx>
+#include <odbc/odbcbasedllapi.hxx>
+#include <memory>
+#include <string_view>
+
+namespace connectivity::odbc
+ {
+ /*
+ ** java_sql_ResultSet
+ */
+ typedef ::cppu::WeakComponentImplHelper< css::sdbc::XResultSet,
+ css::sdbc::XRow,
+ css::sdbc::XResultSetMetaDataSupplier,
+ css::util::XCancellable,
+ css::sdbc::XWarningsSupplier,
+ css::sdbc::XCloseable,
+ css::sdbc::XColumnLocate> ODatabaseMetaDataResultSet_BASE;
+
+ class OOO_DLLPUBLIC_ODBCBASE ODatabaseMetaDataResultSet :
+ public cppu::BaseMutex,
+ public ODatabaseMetaDataResultSet_BASE,
+ public ::cppu::OPropertySetHelper,
+ public ::comphelper::OPropertyArrayUsageHelper<ODatabaseMetaDataResultSet>
+ {
+ std::vector< sal_Int32> m_aColMapping; // pos 0 is unused so we don't have to decrement 1 every time
+
+ std::map<sal_Int32, ::std::map<sal_Int32,sal_Int32> >
+ m_aValueRange;
+
+ std::map<sal_Int32,SWORD> m_aODBCColumnTypes;
+
+ SQLHANDLE m_aStatementHandle; // ... until freed
+ css::uno::WeakReferenceHelper m_aStatement;
+ css::uno::Reference< css::sdbc::XResultSetMetaData>
+ m_xMetaData;
+ std::unique_ptr<SQLUSMALLINT[]> m_pRowStatusArray;
+ rtl::Reference<OConnection> m_pConnection;
+ rtl_TextEncoding m_nTextEncoding;
+ sal_Int32 m_nRowPos;
+ sal_Int32 m_nDriverColumnCount; // column count of the driver which can sometimes be less than the metadata count
+ SQLRETURN m_nCurrentFetchState;
+ bool m_bWasNull;
+ bool m_bEOF; // after last record
+
+ // set the columncount of the driver
+ void checkColumnCount();
+ static sal_Int32 getFetchDirection() { return css::sdbc::FetchDirection::FORWARD; }
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ static sal_Int32 getFetchSize();
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ static OUString getCursorName();
+ SWORD impl_getColumnType_nothrow(sal_Int32 columnIndex);
+
+ sal_Int32 mapColumn (sal_Int32 column);
+
+ protected:
+
+ // OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override;
+ // OPropertySetHelper
+ virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override;
+
+ virtual sal_Bool SAL_CALL convertFastPropertyValue(
+ css::uno::Any & rConvertedValue,
+ css::uno::Any & rOldValue,
+ sal_Int32 nHandle,
+ const css::uno::Any& rValue ) override;
+ virtual void SAL_CALL setFastPropertyValue_NoBroadcast( sal_Int32 nHandle, const css::uno::Any& rValue ) override;
+ virtual void SAL_CALL getFastPropertyValue( css::uno::Any& rValue, sal_Int32 nHandle ) const override;
+ virtual ~ODatabaseMetaDataResultSet() override;
+ template < typename T, SQLSMALLINT sqlTypeId > T getInteger ( sal_Int32 columnIndex );
+
+ public:
+ // A ctor needed for returning the object
+ ODatabaseMetaDataResultSet(OConnection* _pConnection);
+
+
+ oslGenericFunction getOdbcFunction(ODBC3SQLFunctionId _nIndex) const
+ {
+ return m_pConnection->getOdbcFunction(_nIndex);
+ }
+ // ::cppu::OComponentHelper
+ virtual void SAL_CALL disposing() override;
+ // XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+ //XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override;
+ // XPropertySet
+ virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override;
+ css::uno::Reference< css::uno::XInterface > operator *()
+ {
+ return css::uno::Reference< css::uno::XInterface >(*static_cast<ODatabaseMetaDataResultSet_BASE*>(this));
+ }
+ // XResultSet
+ virtual sal_Bool SAL_CALL next( ) override;
+ virtual sal_Bool SAL_CALL isBeforeFirst( ) override;
+ virtual sal_Bool SAL_CALL isAfterLast( ) override;
+ virtual sal_Bool SAL_CALL isFirst( ) override;
+ virtual sal_Bool SAL_CALL isLast( ) override;
+ virtual void SAL_CALL beforeFirst( ) override;
+ virtual void SAL_CALL afterLast( ) override;
+ virtual sal_Bool SAL_CALL first( ) override;
+ virtual sal_Bool SAL_CALL last( ) override;
+ virtual sal_Int32 SAL_CALL getRow( ) override;
+ virtual sal_Bool SAL_CALL absolute( sal_Int32 row ) override;
+ virtual sal_Bool SAL_CALL relative( sal_Int32 rows ) override;
+ virtual sal_Bool SAL_CALL previous( ) override;
+ virtual void SAL_CALL refreshRow( ) override;
+ virtual sal_Bool SAL_CALL rowUpdated( ) override;
+ virtual sal_Bool SAL_CALL rowInserted( ) override;
+ virtual sal_Bool SAL_CALL rowDeleted( ) override;
+ virtual css::uno::Reference< css::uno::XInterface > SAL_CALL getStatement( ) override;
+ // XRow
+ virtual sal_Bool SAL_CALL wasNull( ) override;
+ virtual OUString SAL_CALL getString( sal_Int32 columnIndex ) override;
+ virtual sal_Bool SAL_CALL getBoolean( sal_Int32 columnIndex ) override;
+ virtual sal_Int8 SAL_CALL getByte( sal_Int32 columnIndex ) override;
+ virtual sal_Int16 SAL_CALL getShort( sal_Int32 columnIndex ) override;
+ virtual sal_Int32 SAL_CALL getInt( sal_Int32 columnIndex ) override;
+ virtual sal_Int64 SAL_CALL getLong( sal_Int32 columnIndex ) override;
+ virtual float SAL_CALL getFloat( sal_Int32 columnIndex ) override;
+ virtual double SAL_CALL getDouble( sal_Int32 columnIndex ) override;
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getBytes( sal_Int32 columnIndex ) override;
+ virtual css::util::Date SAL_CALL getDate( sal_Int32 columnIndex ) override;
+ virtual css::util::Time SAL_CALL getTime( sal_Int32 columnIndex ) override;
+ virtual css::util::DateTime SAL_CALL getTimestamp( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getBinaryStream( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getCharacterStream( sal_Int32 columnIndex ) override;
+ virtual css::uno::Any SAL_CALL getObject( sal_Int32 columnIndex, const css::uno::Reference< css::container::XNameAccess >& typeMap ) override;
+ virtual css::uno::Reference< css::sdbc::XRef > SAL_CALL getRef( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XBlob > SAL_CALL getBlob( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XClob > SAL_CALL getClob( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XArray > SAL_CALL getArray( sal_Int32 columnIndex ) override;
+ // XResultSetMetaDataSupplier
+ virtual css::uno::Reference< css::sdbc::XResultSetMetaData > SAL_CALL getMetaData( ) override;
+ // XCancellable
+ virtual void SAL_CALL cancel( ) override;
+ // XCloseable
+ virtual void SAL_CALL close( ) override;
+ // XWarningsSupplier
+ virtual css::uno::Any SAL_CALL getWarnings( ) override;
+ virtual void SAL_CALL clearWarnings( ) override;
+ // XColumnLocate
+ virtual sal_Int32 SAL_CALL findColumn( const OUString& columnName ) override;
+
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void openTablesTypes( );
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void openTypeInfo();
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void openCatalogs();
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void openSchemas();
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void openTables(const css::uno::Any& catalog, const OUString& schemaPattern,
+ std::u16string_view tableNamePattern, const css::uno::Sequence< OUString >& types );
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void openColumnPrivileges( const css::uno::Any& catalog, const OUString& schema,
+ std::u16string_view table, std::u16string_view columnNamePattern );
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void openColumns( const css::uno::Any& catalog, const OUString& schemaPattern,
+ std::u16string_view tableNamePattern, std::u16string_view columnNamePattern );
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void openProcedureColumns( const css::uno::Any& catalog, const OUString& schemaPattern,
+ std::u16string_view procedureNamePattern,std::u16string_view columnNamePattern );
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void openProcedures( const css::uno::Any& catalog, const OUString& schemaPattern,
+ std::u16string_view procedureNamePattern);
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void openVersionColumns(const css::uno::Any& catalog, const OUString& schema,
+ std::u16string_view table);
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void openBestRowIdentifier( const css::uno::Any& catalog, const OUString& schema,
+ std::u16string_view table,sal_Int32 scope, bool nullable );
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void openForeignKeys( const css::uno::Any& catalog, const OUString* schema,const OUString* table,
+ const css::uno::Any& catalog2, const OUString* schema2,const OUString* table2);
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void openExportedKeys(const css::uno::Any& catalog, const OUString& schema,const OUString& table);
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void openImportedKeys(const css::uno::Any& catalog, const OUString& schema,const OUString& table);
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void openPrimaryKeys(const css::uno::Any& catalog, const OUString& schema,std::u16string_view table);
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void openTablePrivileges(const css::uno::Any& catalog, const OUString& schemaPattern,
+ std::u16string_view tableNamePattern);
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void openSpecialColumns(bool _bRowVer,const css::uno::Any& catalog, const OUString& schema,
+ std::u16string_view table,sal_Int32 scope, bool nullable );
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void openIndexInfo( const css::uno::Any& catalog, const OUString& schema,
+ std::u16string_view table,bool unique,bool approximate );
+
+ protected:
+ using OPropertySetHelper::getFastPropertyValue;
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/odbc/ODriver.hxx b/connectivity/source/inc/odbc/ODriver.hxx
new file mode 100644
index 0000000000..6cba90648d
--- /dev/null
+++ b/connectivity/source/inc/odbc/ODriver.hxx
@@ -0,0 +1,77 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/sdbc/XDriver.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <cppuhelper/compbase.hxx>
+#include <connectivity/odbc.hxx>
+#include <odbc/odbcbasedllapi.hxx>
+#include <connectivity/CommonTools.hxx>
+#include <osl/module.h>
+#include <odbc/OTools.hxx>
+
+namespace connectivity::odbc
+ {
+ typedef ::cppu::WeakComponentImplHelper< css::sdbc::XDriver, css::lang::XServiceInfo > ODriver_BASE;
+
+ class OOO_DLLPUBLIC_ODBCBASE SAL_NO_VTABLE ODBCDriver : public ODriver_BASE
+ {
+ protected:
+ ::osl::Mutex m_aMutex;
+
+ connectivity::OWeakRefArray m_xConnections; // vector containing a list
+ // of all the Connection objects
+ // for this Driver
+
+ css::uno::Reference< css::uno::XComponentContext > m_xContext;
+ SQLHANDLE m_pDriverHandle;
+
+ virtual SQLHANDLE EnvironmentHandle(OUString &_rPath) = 0;
+
+ public:
+
+ ODBCDriver(css::uno::Reference< css::uno::XComponentContext > xContext);
+
+ // only possibility to get the odbc functions
+ virtual oslGenericFunction getOdbcFunction(ODBC3SQLFunctionId _nIndex) const = 0;
+ // OComponentHelper
+ virtual void SAL_CALL disposing() override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+ // XDriver
+ virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL connect( const OUString& url, const css::uno::Sequence< css::beans::PropertyValue >& info ) override;
+ virtual sal_Bool SAL_CALL acceptsURL( const OUString& url ) override;
+ virtual css::uno::Sequence< css::sdbc::DriverPropertyInfo > SAL_CALL getPropertyInfo( const OUString& url, const css::uno::Sequence< css::beans::PropertyValue >& info ) override;
+ virtual sal_Int32 SAL_CALL getMajorVersion( ) override;
+ virtual sal_Int32 SAL_CALL getMinorVersion( ) override;
+
+ const css::uno::Reference< css::uno::XComponentContext >& getContext() const { return m_xContext; }
+ };
+
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/odbc/OFunctions.hxx b/connectivity/source/inc/odbc/OFunctions.hxx
new file mode 100644
index 0000000000..a44fe5a150
--- /dev/null
+++ b/connectivity/source/inc/odbc/OFunctions.hxx
@@ -0,0 +1,600 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <connectivity/odbc.hxx>
+#include <rtl/ustring.hxx>
+#include <osl/module.h>
+
+namespace connectivity
+{
+
+// sal_Bool LoadFunctions(oslModule pODBCso, sal_Bool _bDS=sal_True);
+bool LoadLibrary_ODBC3(OUString &_rPath);
+// sal_Bool LoadLibrary_ADABAS(OUString &_rPath);
+
+ // Connecting to a data source
+ typedef SQLRETURN (SQL_API *T3SQLAllocHandle) (SQLSMALLINT HandleType,SQLHANDLE InputHandle,SQLHANDLE * OutputHandlePtr);
+
+ #define N3SQLAllocHandle(a,b,c) (*reinterpret_cast<T3SQLAllocHandle>(getOdbcFunction(ODBC3SQLFunctionId::AllocHandle)))(a,b,c)
+
+ typedef SQLRETURN (SQL_API *T3SQLConnect) (SQLHDBC ConnectionHandle,SQLCHAR *ServerName,SQLSMALLINT NameLength1,SQLCHAR *UserName,SQLSMALLINT NameLength2,SQLCHAR *Authentication,SQLSMALLINT NameLength3);
+
+ #define N3SQLConnect(a,b,c,d,e,f,g) (*reinterpret_cast<T3SQLConnect>(getOdbcFunction(ODBC3SQLFunctionId::Connect)))(a,b,c,d,e,f,g)
+
+ typedef SQLRETURN (SQL_API *T3SQLDriverConnect) ( SQLHDBC ConnectionHandle,
+ HWND WindowHandle,
+ SQLCHAR * InConnectionString,
+ SQLSMALLINT StringLength1,
+ SQLCHAR * OutConnectionString,
+ SQLSMALLINT BufferLength,
+ SQLSMALLINT * StringLength2Ptr,
+ SQLUSMALLINT DriverCompletion);
+
+ #define N3SQLDriverConnect(a,b,c,d,e,f,g,h) (*reinterpret_cast<T3SQLDriverConnect>(getOdbcFunction(ODBC3SQLFunctionId::DriverConnect)))(a,b,c,d,e,f,g,h)
+
+ typedef SQLRETURN (SQL_API *T3SQLBrowseConnect) ( SQLHDBC ConnectionHandle,
+ SQLCHAR * InConnectionString,
+ SQLSMALLINT StringLength1,
+ SQLCHAR * OutConnectionString,
+ SQLSMALLINT BufferLength,
+ SQLSMALLINT * StringLength2Ptr);
+
+ #define N3SQLBrowseConnect(a,b,c,d,e,f) (*reinterpret_cast<T3SQLBrowseConnect>(getOdbcFunction(ODBC3SQLFunctionId::BrowseConnect)))(a,b,c,d,e,f)
+
+ // Obtaining information about a driver and data source
+ typedef SQLRETURN (SQL_API *T3SQLDataSources) ( SQLHENV EnvironmentHandle,
+ SQLUSMALLINT Direction,
+ SQLCHAR * ServerName,
+ SQLSMALLINT BufferLength1,
+ SQLSMALLINT * NameLength1Ptr,
+ SQLCHAR * Description,
+ SQLSMALLINT BufferLength2,
+ SQLSMALLINT * NameLength2Ptr);
+
+ #define N3SQLDataSources(a,b,c,d,e,f,g,h) (*reinterpret_cast<T3SQLDataSources>(getOdbcFunction(ODBC3SQLFunctionId::DataSources)))(a,b,c,d,e,f,g,h)
+
+ typedef SQLRETURN (SQL_API *T3SQLDrivers) ( SQLHENV EnvironmentHandle,
+ SQLUSMALLINT Direction,
+ SQLCHAR * DriverDescription,
+ SQLSMALLINT BufferLength1,
+ SQLSMALLINT * DescriptionLengthPtr,
+ SQLCHAR * DriverAttributes,
+ SQLSMALLINT BufferLength2,
+ SQLSMALLINT * AttributesLengthPtr);
+
+ #define N3SQLDrivers(a,b,c,d,e,f,g,h) (*reinterpret_cast<T3SQLDrivers>(getOdbcFunction(ODBC3SQLFunctionId::Drivers)))(a,b,c,d,e,f,g,h)
+
+ typedef SQLRETURN (SQL_API *T3SQLGetInfo) ( SQLHDBC ConnectionHandle,
+ SQLUSMALLINT InfoType,
+ SQLPOINTER InfoValuePtr,
+ SQLSMALLINT BufferLength,
+ SQLSMALLINT * StringLengthPtr);
+
+ #define N3SQLGetInfo(a,b,c,d,e) (*reinterpret_cast<T3SQLGetInfo>(getOdbcFunction(ODBC3SQLFunctionId::GetInfo)))(a,b,c,d,e)
+
+ typedef SQLRETURN (SQL_API *T3SQLGetFunctions) (SQLHDBC ConnectionHandle,
+ SQLUSMALLINT FunctionId,
+ SQLUSMALLINT * SupportedPtr);
+
+ #define N3SQLGetFunctions(a,b,c) (*reinterpret_cast<T3SQLGetFunctions>(getOdbcFunction(ODBC3SQLFunctionId::GetFunctions)))(a,b,c)
+
+ typedef SQLRETURN (SQL_API *T3SQLGetTypeInfo) ( SQLHSTMT StatementHandle,
+ SQLSMALLINT DataType);
+
+ #define N3SQLGetTypeInfo(a,b) (*reinterpret_cast<T3SQLGetTypeInfo>(getOdbcFunction(ODBC3SQLFunctionId::GetTypeInfo)))(a,b)
+
+ // Setting and retrieving driver attributes
+ typedef SQLRETURN (SQL_API *T3SQLSetConnectAttr)(SQLHDBC ConnectionHandle,
+ SQLINTEGER Attribute,
+ SQLPOINTER ValuePtr,
+ SQLINTEGER StringLength);
+
+ #define N3SQLSetConnectAttr(a,b,c,d) (*reinterpret_cast<T3SQLSetConnectAttr>(getOdbcFunction(ODBC3SQLFunctionId::SetConnectAttr)))(a,b,c,d)
+
+ typedef SQLRETURN (SQL_API *T3SQLGetConnectAttr) (SQLHDBC ConnectionHandle,
+ SQLINTEGER Attribute,
+ SQLPOINTER ValuePtr,
+ SQLINTEGER BufferLength,
+ SQLINTEGER* StringLength);
+
+ #define N3SQLGetConnectAttr(a,b,c,d,e) (*reinterpret_cast<T3SQLGetConnectAttr>(getOdbcFunction(ODBC3SQLFunctionId::GetConnectAttr)))(a,b,c,d,e)
+
+
+ typedef SQLRETURN (SQL_API *T3SQLSetEnvAttr) ( SQLHENV EnvironmentHandle,
+ SQLINTEGER Attribute,
+ SQLPOINTER ValuePtr,
+ SQLINTEGER StringLength);
+
+ #define N3SQLSetEnvAttr(a,b,c,d) (*reinterpret_cast<T3SQLSetEnvAttr>(getOdbcFunction(ODBC3SQLFunctionId::SetEnvAttr)))(a,b,c,d)
+
+ typedef SQLRETURN (SQL_API *T3SQLGetEnvAttr) ( SQLHENV EnvironmentHandle,
+ SQLINTEGER Attribute,
+ SQLPOINTER ValuePtr,
+ SQLINTEGER BufferLength,
+ SQLINTEGER* StringLength);
+
+ #define N3SQLGetEnvAttr(a,b,c,d,e) (*reinterpret_cast<T3SQLGetEnvAttr>(getOdbcFunction(ODBC3SQLFunctionId::GetEnvAttr)))(a,b,c,d,e)
+
+
+ typedef SQLRETURN (SQL_API *T3SQLSetStmtAttr) ( SQLHSTMT StatementHandle,
+ SQLINTEGER Attribute,
+ SQLPOINTER ValuePtr,
+ SQLINTEGER StringLength);
+
+ #define N3SQLSetStmtAttr(a,b,c,d) (*reinterpret_cast<T3SQLSetStmtAttr>(getOdbcFunction(ODBC3SQLFunctionId::SetStmtAttr)))(a,b,c,d)
+
+ typedef SQLRETURN (SQL_API *T3SQLGetStmtAttr) ( SQLHSTMT StatementHandle,
+ SQLINTEGER Attribute,
+ SQLPOINTER ValuePtr,
+ SQLINTEGER BufferLength,
+ SQLINTEGER* StringLength);
+
+ #define N3SQLGetStmtAttr(a,b,c,d,e) (*reinterpret_cast<T3SQLGetStmtAttr>(getOdbcFunction(ODBC3SQLFunctionId::GetStmtAttr)))(a,b,c,d,e)
+
+ // Setting and retrieving descriptor fields
+ /*typedef SQLRETURN (SQL_API *T3SQLSetDescField) (SQLHDESC DescriptorHandle,
+ SQLSMALLINT RecNumber,
+ SQLSMALLINT FieldIdentifier,
+ SQLPOINTER ValuePtr,
+ SQLINTEGER BufferLength);
+
+ #define N3SQLSetDescField(a,b,c,d,e) (*reinterpret_cast<T3SQLSetDescField>(getOdbcFunction(ODBC3SQLFunctionId::SetDescField)))(a,b,c,d,e)
+
+ typedef SQLRETURN (SQL_API *T3SQLGetDescField) ( SQLHDESC DescriptorHandle,
+ SQLSMALLINT RecNumber,
+ SQLSMALLINT FieldIdentifier,
+ SQLPOINTER ValuePtr,
+ SQLINTEGER BufferLength,
+ SQLINTEGER * StringLengthPtr);
+
+ #define N3SQLGetDescField(a,b,c,d,e,f) (*reinterpret_cast<T3SQLGetDescField>(getOdbcFunction(ODBC3SQLFunctionId::GetDescField)))(a,b,c,d,e,f)
+
+
+ typedef SQLRETURN (SQL_API *T3SQLGetDescRec) ( SQLHDESC DescriptorHandle,
+ SQLSMALLINT RecNumber,
+ SQLCHAR * Name,
+ SQLSMALLINT BufferLength,
+ SQLSMALLINT * StringLengthPtr,
+ SQLSMALLINT * TypePtr,
+ SQLSMALLINT * SubTypePtr,
+ SQLLEN * LengthPtr,
+ SQLSMALLINT * PrecisionPtr,
+ SQLSMALLINT * ScalePtr,
+ SQLSMALLINT * NullablePtr);
+
+ #define N3SQLGetDescRec(a,b,c,d,e,f,g,h,i,j,k) (*reinterpret_cast<T3SQLGetDescRec>(getOdbcFunction(ODBC3SQLFunctionId::GetDescRec)))(a,b,c,d,e,f,g,h,i,j,k)
+
+
+ typedef SQLRETURN (SQL_API *T3SQLSetDescRec) ( SQLHDESC DescriptorHandle,
+ SQLSMALLINT RecNumber,
+ SQLSMALLINT Type,
+ SQLSMALLINT SubType,
+ SQLLEN Length,
+ SQLSMALLINT Precision,
+ SQLSMALLINT Scale,
+ SQLPOINTER DataPtr,
+ SQLLEN * StringLengthPtr,
+ SQLLEN * IndicatorPtr);
+
+ #define N3SQLSetDescRec(a,b,c,d,e,f,g,h,i,j) (*reinterpret_cast<T3SQLSetDescRec>(getOdbcFunction(ODBC3SQLFunctionId::SetDescRec)))(a,b,c,d,e,f,g,h,i,j)
+ */
+
+ // Preparing SQL requests
+ typedef SQLRETURN (SQL_API *T3SQLPrepare) ( SQLHSTMT StatementHandle,
+ SQLCHAR * StatementText,
+ SQLINTEGER TextLength);
+
+ #define N3SQLPrepare(a,b,c) (*reinterpret_cast<T3SQLPrepare>(getOdbcFunction(ODBC3SQLFunctionId::Prepare)))(a,b,c)
+
+ typedef SQLRETURN (SQL_API *T3SQLBindParameter) (SQLHSTMT StatementHandle,
+ SQLUSMALLINT ParameterNumber,
+ SQLSMALLINT InputOutputType,
+ SQLSMALLINT ValueType,
+ SQLSMALLINT ParameterType,
+ SQLULEN ColumnSize,
+ SQLSMALLINT DecimalDigits,
+ SQLPOINTER ParameterValuePtr,
+ SQLLEN BufferLength,
+ SQLLEN * StrLen_or_IndPtr);
+
+ #define N3SQLBindParameter(a,b,c,d,e,f,g,h,i,j) (*reinterpret_cast<T3SQLBindParameter>(getOdbcFunction(ODBC3SQLFunctionId::BindParameter)))(a,b,c,d,e,f,g,h,i,j)
+
+ /*typedef SQLRETURN (SQL_API *T3SQLGetCursorName) (SQLHSTMT StatementHandle,
+ SQLCHAR * CursorName,
+ SQLSMALLINT BufferLength,
+ SQLSMALLINT * NameLengthPtr);
+
+ #define N3SQLGetCursorName(a,b,c,d) (*reinterpret_cast<T3SQLGetCursorName>(getOdbcFunction(ODBC3SQLFunctionId::GetCursorName)))(a,b,c,d)
+ */
+
+ typedef SQLRETURN (SQL_API *T3SQLSetCursorName) (SQLHSTMT StatementHandle,
+ SQLCHAR * CursorName,
+ SQLSMALLINT NameLength);
+
+ #define N3SQLSetCursorName(a,b,c) (*reinterpret_cast<T3SQLSetCursorName>(getOdbcFunction(ODBC3SQLFunctionId::SetCursorName)))(a,b,c)
+
+ // Submitting requests
+ typedef SQLRETURN (SQL_API *T3SQLExecute) ( SQLHSTMT StatementHandle);
+
+ #define N3SQLExecute(a) (*reinterpret_cast<T3SQLExecute>(getOdbcFunction(ODBC3SQLFunctionId::Execute)))(a)
+
+ typedef SQLRETURN (SQL_API *T3SQLExecDirect) ( SQLHSTMT StatementHandle,
+ SQLCHAR * StatementText,
+ SQLINTEGER TextLength);
+
+ #define N3SQLExecDirect(a,b,c) (*reinterpret_cast<T3SQLExecDirect>(getOdbcFunction(ODBC3SQLFunctionId::ExecDirect)))(a,b,c)
+
+ typedef SQLRETURN (SQL_API *T3SQLDescribeParam) (SQLHSTMT StatementHandle,
+ SQLUSMALLINT ParameterNumber,
+ SQLSMALLINT * DataTypePtr,
+ SQLULEN * ParameterSizePtr,
+ SQLSMALLINT * DecimalDigitsPtr,
+ SQLSMALLINT * NullablePtr);
+
+ #define N3SQLDescribeParam(a,b,c,d,e,f) (*reinterpret_cast<T3SQLDescribeParam>(getOdbcFunction(ODBC3SQLFunctionId::DescribeParam)))(a,b,c,d,e,f)
+
+ typedef SQLRETURN (SQL_API *T3SQLNumParams) ( SQLHSTMT StatementHandle,
+ SQLSMALLINT * ParameterCountPtr);
+
+ #define N3SQLNumParams(a,b) (*reinterpret_cast<T3SQLNumParams>(getOdbcFunction(ODBC3SQLFunctionId::NumParams)))(a,b)
+
+ typedef SQLRETURN (SQL_API *T3SQLParamData) ( SQLHSTMT StatementHandle,
+ SQLPOINTER * ValuePtrPtr);
+
+ #define N3SQLParamData(a,b) (*reinterpret_cast<T3SQLParamData>(getOdbcFunction(ODBC3SQLFunctionId::ParamData)))(a,b)
+
+ typedef SQLRETURN (SQL_API *T3SQLPutData) ( SQLHSTMT StatementHandle,
+ SQLPOINTER DataPtr,
+ SQLLEN StrLen_or_Ind);
+
+ #define N3SQLPutData(a,b,c) (*reinterpret_cast<T3SQLPutData>(getOdbcFunction(ODBC3SQLFunctionId::PutData)))(a,b,c)
+
+ // Retrieving results and information about results
+ typedef SQLRETURN (SQL_API *T3SQLRowCount) ( SQLHSTMT StatementHandle,
+ SQLLEN * RowCountPtr);
+
+ #define N3SQLRowCount(a,b) (*reinterpret_cast<T3SQLRowCount>(getOdbcFunction(ODBC3SQLFunctionId::RowCount)))(a,b)
+
+ typedef SQLRETURN (SQL_API *T3SQLNumResultCols) (SQLHSTMT StatementHandle,
+ SQLSMALLINT * ColumnCountPtr);
+
+ #define N3SQLNumResultCols(a,b) (*reinterpret_cast<T3SQLNumResultCols>(getOdbcFunction(ODBC3SQLFunctionId::NumResultCols)))(a,b)
+
+ typedef SQLRETURN (SQL_API *T3SQLDescribeCol) ( SQLHSTMT StatementHandle,
+ SQLUSMALLINT ColumnNumber,
+ SQLCHAR * ColumnName,
+ SQLSMALLINT BufferLength,
+ SQLSMALLINT * NameLengthPtr,
+ SQLSMALLINT * DataTypePtr,
+ SQLULEN * ColumnSizePtr,
+ SQLSMALLINT * DecimalDigitsPtr,
+ SQLSMALLINT * NullablePtr);
+
+ #define N3SQLDescribeCol(a,b,c,d,e,f,g,h,i) (*reinterpret_cast<T3SQLDescribeCol>(getOdbcFunction(ODBC3SQLFunctionId::DescribeCol)))(a,b,c,d,e,f,g,h,i)
+
+ typedef SQLRETURN (SQL_API *T3SQLColAttribute) (SQLHSTMT StatementHandle,
+ SQLUSMALLINT ColumnNumber,
+ SQLUSMALLINT FieldIdentifier,
+ SQLPOINTER CharacterAttributePtr,
+ SQLSMALLINT BufferLength,
+ SQLSMALLINT * StringLengthPtr,
+ SQLLEN * NumericAttributePtr);
+
+ #define N3SQLColAttribute(a,b,c,d,e,f,g) (*reinterpret_cast<T3SQLColAttribute>(getOdbcFunction(ODBC3SQLFunctionId::ColAttribute)))(a,b,c,d,e,f,g)
+
+ typedef SQLRETURN (SQL_API *T3SQLBindCol) ( SQLHSTMT StatementHandle,
+ SQLUSMALLINT ColumnNumber,
+ SQLSMALLINT TargetType,
+ SQLPOINTER TargetValuePtr,
+ SQLLEN BufferLength,
+ SQLLEN * StrLen_or_IndPtr);
+
+ #define N3SQLBindCol(a,b,c,d,e,f) (*reinterpret_cast<T3SQLBindCol>(getOdbcFunction(ODBC3SQLFunctionId::BindCol)))(a,b,c,d,e,f)
+
+ typedef SQLRETURN (SQL_API *T3SQLFetch) ( SQLHSTMT StatementHandle);
+
+ #define N3SQLFetch(a) (*reinterpret_cast<T3SQLFetch>(getOdbcFunction(ODBC3SQLFunctionId::Fetch)))(a)
+
+ typedef SQLRETURN (SQL_API *T3SQLFetchScroll) ( SQLHSTMT StatementHandle,
+ SQLSMALLINT FetchOrientation,
+ SQLLEN FetchOffset);
+
+ #define N3SQLFetchScroll(a,b,c) (*reinterpret_cast<T3SQLFetchScroll>(getOdbcFunction(ODBC3SQLFunctionId::FetchScroll)))(a,b,c)
+
+ typedef SQLRETURN (SQL_API *T3SQLGetData) ( SQLHSTMT StatementHandle,
+ SQLUSMALLINT ColumnNumber,
+ SQLSMALLINT TargetType,
+ SQLPOINTER TargetValuePtr,
+ SQLLEN BufferLength,
+ SQLLEN * StrLen_or_IndPtr);
+
+ #define N3SQLGetData(a,b,c,d,e,f) (*reinterpret_cast<T3SQLGetData>(getOdbcFunction(ODBC3SQLFunctionId::GetData)))(a,b,c,d,e,f)
+
+ typedef SQLRETURN (SQL_API *T3SQLSetPos) ( SQLHSTMT StatementHandle,
+ SQLSETPOSIROW RowNumber,
+ SQLUSMALLINT Operation,
+ SQLUSMALLINT LockType);
+
+ #define N3SQLSetPos(a,b,c,d) (*reinterpret_cast<T3SQLSetPos>(getOdbcFunction(ODBC3SQLFunctionId::SetPos)))(a,b,c,d)
+
+ typedef SQLRETURN (SQL_API *T3SQLBulkOperations) ( SQLHSTMT StatementHandle,
+ SQLSMALLINT Operation);
+
+ #define N3SQLBulkOperations(a,b) (*reinterpret_cast<T3SQLBulkOperations>(getOdbcFunction(ODBC3SQLFunctionId::BulkOperations)))(a,b)
+
+ typedef SQLRETURN (SQL_API *T3SQLMoreResults) ( SQLHSTMT StatementHandle);
+
+ #define N3SQLMoreResults(a) (*reinterpret_cast<T3SQLMoreResults>(getOdbcFunction(ODBC3SQLFunctionId::MoreResults)))(a)
+
+ /*typedef SQLRETURN (SQL_API *T3SQLGetDiagField) (SQLSMALLINT HandleType,
+ SQLHANDLE Handle,
+ SQLSMALLINT RecNumber,
+ SQLSMALLINT DiagIdentifier,
+ SQLPOINTER DiagInfoPtr,
+ SQLSMALLINT BufferLength,
+ SQLSMALLINT * StringLengthPtr);
+
+ #define N3SQLGetDiagField(a,b,c,d,e,f,g) (*reinterpret_cast<T3SQLGetDiagField>(getOdbcFunction(ODBC3SQLFunctionId::GetDiagField)))(a,b,c,d,e,f,g)*/
+
+ typedef SQLRETURN (SQL_API *T3SQLGetDiagRec) ( SQLSMALLINT HandleType,
+ SQLHANDLE Handle,
+ SQLSMALLINT RecNumber,
+ SQLCHAR * Sqlstate,
+ SQLINTEGER * NativeErrorPtr,
+ SQLCHAR * MessageText,
+ SQLSMALLINT BufferLength,
+ SQLSMALLINT * TextLengthPtr);
+
+
+ #define N3SQLGetDiagRec(a,b,c,d,e,f,g,h) (*reinterpret_cast<T3SQLGetDiagRec>(getOdbcFunction(ODBC3SQLFunctionId::GetDiagRec)))(a,b,c,d,e,f,g,h)
+
+ // Obtaining information about the data source's system tables (catalog functions)
+ typedef SQLRETURN (SQL_API *T3SQLColumnPrivileges) (SQLHSTMT StatementHandle,
+ SQLCHAR * CatalogName,
+ SQLSMALLINT NameLength1,
+ SQLCHAR * SchemaName,
+ SQLSMALLINT NameLength2,
+ SQLCHAR * TableName,
+ SQLSMALLINT NameLength3,
+ SQLCHAR * ColumnName,
+ SQLSMALLINT NameLength4);
+
+ #define N3SQLColumnPrivileges(a,b,c,d,e,f,g,h,i) (*reinterpret_cast<T3SQLColumnPrivileges>(getOdbcFunction(ODBC3SQLFunctionId::ColumnPrivileges)))(a,b,c,d,e,f,g,h,i)
+
+ typedef SQLRETURN (SQL_API *T3SQLColumns) ( SQLHSTMT StatementHandle,
+ SQLCHAR * CatalogName,
+ SQLSMALLINT NameLength1,
+ SQLCHAR * SchemaName,
+ SQLSMALLINT NameLength2,
+ SQLCHAR * TableName,
+ SQLSMALLINT NameLength3,
+ SQLCHAR * ColumnName,
+ SQLSMALLINT NameLength4);
+
+ #define N3SQLColumns(a,b,c,d,e,f,g,h,i) (*reinterpret_cast<T3SQLColumns>(getOdbcFunction(ODBC3SQLFunctionId::Columns)))(a,b,c,d,e,f,g,h,i)
+
+ typedef SQLRETURN (SQL_API *T3SQLForeignKeys) ( SQLHSTMT StatementHandle,
+ SQLCHAR * PKCatalogName,
+ SQLSMALLINT NameLength1,
+ SQLCHAR * PKSchemaName,
+ SQLSMALLINT NameLength2,
+ SQLCHAR * PKTableName,
+ SQLSMALLINT NameLength3,
+ SQLCHAR * FKCatalogName,
+ SQLSMALLINT NameLength4,
+ SQLCHAR * FKSchemaName,
+ SQLSMALLINT NameLength5,
+ SQLCHAR * FKTableName,
+ SQLSMALLINT NameLength6);
+
+ #define N3SQLForeignKeys(a,b,c,d,e,f,g,h,i,j,k,l,m) (*reinterpret_cast<T3SQLForeignKeys>(getOdbcFunction(ODBC3SQLFunctionId::ForeignKeys)))(a,b,c,d,e,f,g,h,i,j,k,l,m)
+
+ typedef SQLRETURN (SQL_API *T3SQLPrimaryKeys) ( SQLHSTMT StatementHandle,
+ SQLCHAR * CatalogName,
+ SQLSMALLINT NameLength1,
+ SQLCHAR * SchemaName,
+ SQLSMALLINT NameLength2,
+ SQLCHAR * TableName,
+ SQLSMALLINT NameLength3);
+
+ #define N3SQLPrimaryKeys(a,b,c,d,e,f,g) (*reinterpret_cast<T3SQLPrimaryKeys>(getOdbcFunction(ODBC3SQLFunctionId::PrimaryKeys)))(a,b,c,d,e,f,g)
+
+ typedef SQLRETURN (SQL_API *T3SQLProcedureColumns) (SQLHSTMT StatementHandle,
+ SQLCHAR * CatalogName,
+ SQLSMALLINT NameLength1,
+ SQLCHAR * SchemaName,
+ SQLSMALLINT NameLength2,
+ SQLCHAR * ProcName,
+ SQLSMALLINT NameLength3,
+ SQLCHAR * ColumnName,
+ SQLSMALLINT NameLength4);
+
+ #define N3SQLProcedureColumns(a,b,c,d,e,f,g,h,i) (*reinterpret_cast<T3SQLProcedureColumns>(getOdbcFunction(ODBC3SQLFunctionId::ProcedureColumns)))(a,b,c,d,e,f,g,h,i)
+
+ typedef SQLRETURN (SQL_API *T3SQLProcedures) ( SQLHSTMT StatementHandle,
+ SQLCHAR * CatalogName,
+ SQLSMALLINT NameLength1,
+ SQLCHAR * SchemaName,
+ SQLSMALLINT NameLength2,
+ SQLCHAR * ProcName,
+ SQLSMALLINT NameLength3);
+
+ #define N3SQLProcedures(a,b,c,d,e,f,g) (*reinterpret_cast<T3SQLProcedures>(getOdbcFunction(ODBC3SQLFunctionId::Procedures)))(a,b,c,d,e,f,g)
+
+ typedef SQLRETURN (SQL_API *T3SQLSpecialColumns) (SQLHSTMT StatementHandle,
+ SQLUSMALLINT IdentifierType,
+ SQLCHAR * CatalogName,
+ SQLSMALLINT NameLength1,
+ SQLCHAR * SchemaName,
+ SQLSMALLINT NameLength2,
+ SQLCHAR * TableName,
+ SQLSMALLINT NameLength3,
+ SQLUSMALLINT Scope,
+ SQLUSMALLINT Nullable);
+
+ #define N3SQLSpecialColumns(a,b,c,d,e,f,g,h,i,j) (*reinterpret_cast<T3SQLSpecialColumns>(getOdbcFunction(ODBC3SQLFunctionId::SpecialColumns)))(a,b,c,d,e,f,g,h,i,j)
+
+ typedef SQLRETURN (SQL_API *T3SQLStatistics) ( SQLHSTMT StatementHandle,
+ SQLCHAR * CatalogName,
+ SQLSMALLINT NameLength1,
+ SQLCHAR * SchemaName,
+ SQLSMALLINT NameLength2,
+ SQLCHAR * TableName,
+ SQLSMALLINT NameLength3,
+ SQLUSMALLINT Unique,
+ SQLUSMALLINT Reserved);
+
+ #define N3SQLStatistics(a,b,c,d,e,f,g,h,i) (*reinterpret_cast<T3SQLStatistics>(getOdbcFunction(ODBC3SQLFunctionId::Statistics)))(a,b,c,d,e,f,g,h,i)
+
+ typedef SQLRETURN (SQL_API *T3SQLTablePrivileges) (SQLHSTMT StatementHandle,
+ SQLCHAR * CatalogName,
+ SQLSMALLINT NameLength1,
+ SQLCHAR * SchemaName,
+ SQLSMALLINT NameLength2,
+ SQLCHAR * TableName,
+ SQLSMALLINT NameLength3);
+
+ #define N3SQLTablePrivileges(a,b,c,d,e,f,g) (*reinterpret_cast<T3SQLTablePrivileges>(getOdbcFunction(ODBC3SQLFunctionId::TablePrivileges)))(a,b,c,d,e,f,g)
+
+ typedef SQLRETURN (SQL_API *T3SQLTables) ( SQLHSTMT StatementHandle,
+ SQLCHAR * CatalogName,
+ SQLSMALLINT NameLength1,
+ SQLCHAR * SchemaName,
+ SQLSMALLINT NameLength2,
+ SQLCHAR * TableName,
+ SQLSMALLINT NameLength3,
+ SQLCHAR * TableType,
+ SQLSMALLINT NameLength4);
+
+ #define N3SQLTables(a,b,c,d,e,f,g,h,i) (*reinterpret_cast<T3SQLTables>(getOdbcFunction(ODBC3SQLFunctionId::Tables)))(a,b,c,d,e,f,g,h,i)
+
+ // Terminating a statement
+ typedef SQLRETURN (SQL_API *T3SQLFreeStmt) ( SQLHSTMT StatementHandle,
+ SQLUSMALLINT Option);
+
+ #define N3SQLFreeStmt(a,b) (*reinterpret_cast<T3SQLFreeStmt>(getOdbcFunction(ODBC3SQLFunctionId::FreeStmt)))(a,b)
+
+ typedef SQLRETURN (SQL_API *T3SQLCloseCursor) (SQLHSTMT StatementHandle);
+
+ #define N3SQLCloseCursor(a) (*reinterpret_cast<T3SQLCloseCursor>(getOdbcFunction(ODBC3SQLFunctionId::CloseCursor)))(a)
+
+ typedef SQLRETURN (SQL_API *T3SQLCancel) ( SQLHSTMT StatementHandle);
+
+ #define N3SQLCancel(a) (*reinterpret_cast<T3SQLCancel>(getOdbcFunction(ODBC3SQLFunctionId::Cancel)))(a)
+
+ typedef SQLRETURN (SQL_API *T3SQLEndTran) ( SQLSMALLINT HandleType,
+ SQLHANDLE Handle,
+ SQLSMALLINT CompletionType);
+
+ #define N3SQLEndTran(a,b,c) (*reinterpret_cast<T3SQLEndTran>(getOdbcFunction(ODBC3SQLFunctionId::EndTran)))(a,b,c)
+
+ // Terminating a connection
+ typedef SQLRETURN (SQL_API *T3SQLDisconnect) (SQLHDBC ConnectionHandle);
+
+ #define N3SQLDisconnect(a) (*reinterpret_cast<T3SQLDisconnect>(getOdbcFunction(ODBC3SQLFunctionId::Disconnect)))(a)
+
+ typedef SQLRETURN (SQL_API *T3SQLFreeHandle) (SQLSMALLINT HandleType,
+ SQLHANDLE Handle);
+
+ #define N3SQLFreeHandle(a,b) (*reinterpret_cast<T3SQLFreeHandle>(getOdbcFunction(ODBC3SQLFunctionId::FreeHandle)))(a,b)
+
+ typedef SQLRETURN (SQL_API *T3SQLGetCursorName) ( SQLHSTMT StatementHandle,
+ SQLCHAR * CursorName,
+ SQLSMALLINT BufferLength,
+ SQLSMALLINT* NameLength2);
+
+ #define N3SQLGetCursorName(a,b,c,d) (*reinterpret_cast<T3SQLGetCursorName>(getOdbcFunction(ODBC3SQLFunctionId::GetCursorName)))(a,b,c,d)
+
+ typedef SQLRETURN (SQL_API *T3SQLNativeSql) ( SQLHDBC ConnectionHandle,
+ SQLCHAR * InStatementText,
+ SQLINTEGER TextLength1,
+ SQLCHAR * OutStatementText,
+ SQLINTEGER BufferLength,
+ SQLINTEGER * TextLength2Ptr);
+
+ #define N3SQLNativeSql(a,b,c,d,e,f) (*reinterpret_cast<T3SQLNativeSql>(getOdbcFunction(ODBC3SQLFunctionId::NativeSql)))(a,b,c,d,e,f)
+
+ // extern declaration of the function pointer
+ extern T3SQLAllocHandle pODBC3SQLAllocHandle;
+ extern T3SQLConnect pODBC3SQLConnect;
+ extern T3SQLDriverConnect pODBC3SQLDriverConnect;
+ extern T3SQLBrowseConnect pODBC3SQLBrowseConnect;
+ extern T3SQLDataSources pODBC3SQLDataSources;
+ extern T3SQLDrivers pODBC3SQLDrivers;
+ extern T3SQLGetInfo pODBC3SQLGetInfo;
+ extern T3SQLGetFunctions pODBC3SQLGetFunctions;
+ extern T3SQLGetTypeInfo pODBC3SQLGetTypeInfo;
+ extern T3SQLSetConnectAttr pODBC3SQLSetConnectAttr;
+ extern T3SQLGetConnectAttr pODBC3SQLGetConnectAttr;
+ extern T3SQLSetEnvAttr pODBC3SQLSetEnvAttr;
+ extern T3SQLGetEnvAttr pODBC3SQLGetEnvAttr;
+ extern T3SQLSetStmtAttr pODBC3SQLSetStmtAttr;
+ extern T3SQLGetStmtAttr pODBC3SQLGetStmtAttr;
+ //extern T3SQLSetDescField pODBC3SQLSetDescField;
+ //extern T3SQLGetDescField pODBC3SQLGetDescField;
+ //extern T3SQLGetDescRec pODBC3SQLGetDescRec;
+ //extern T3SQLSetDescRec pODBC3SQLSetDescRec;
+ extern T3SQLPrepare pODBC3SQLPrepare;
+ extern T3SQLBindParameter pODBC3SQLBindParameter;
+ //extern T3SQLGetCursorName pODBC3SQLGetCursorName;
+ extern T3SQLSetCursorName pODBC3SQLSetCursorName;
+ extern T3SQLExecute pODBC3SQLExecute;
+ extern T3SQLExecDirect pODBC3SQLExecDirect;
+ //extern T3SQLNativeSql pODBC3SQLNativeSql;
+ extern T3SQLDescribeParam pODBC3SQLDescribeParam;
+ extern T3SQLNumParams pODBC3SQLNumParams;
+ extern T3SQLParamData pODBC3SQLParamData;
+ extern T3SQLPutData pODBC3SQLPutData;
+ extern T3SQLRowCount pODBC3SQLRowCount;
+ extern T3SQLNumResultCols pODBC3SQLNumResultCols;
+ extern T3SQLDescribeCol pODBC3SQLDescribeCol;
+ extern T3SQLColAttribute pODBC3SQLColAttribute;
+ extern T3SQLBindCol pODBC3SQLBindCol;
+ extern T3SQLFetch pODBC3SQLFetch;
+ extern T3SQLFetchScroll pODBC3SQLFetchScroll;
+ extern T3SQLGetData pODBC3SQLGetData;
+ extern T3SQLSetPos pODBC3SQLSetPos;
+ extern T3SQLBulkOperations pODBC3SQLBulkOperations;
+ extern T3SQLMoreResults pODBC3SQLMoreResults;
+ //extern T3SQLGetDiagField pODBC3SQLGetDiagField;
+ extern T3SQLGetDiagRec pODBC3SQLGetDiagRec;
+ extern T3SQLColumnPrivileges pODBC3SQLColumnPrivileges;
+ extern T3SQLColumns pODBC3SQLColumns;
+ extern T3SQLForeignKeys pODBC3SQLForeignKeys;
+ extern T3SQLPrimaryKeys pODBC3SQLPrimaryKeys;
+ extern T3SQLProcedureColumns pODBC3SQLProcedureColumns;
+ extern T3SQLProcedures pODBC3SQLProcedures;
+ extern T3SQLSpecialColumns pODBC3SQLSpecialColumns;
+ extern T3SQLStatistics pODBC3SQLStatistics;
+ extern T3SQLTablePrivileges pODBC3SQLTablePrivileges;
+ extern T3SQLTables pODBC3SQLTables;
+ extern T3SQLFreeStmt pODBC3SQLFreeStmt;
+ extern T3SQLCloseCursor pODBC3SQLCloseCursor;
+ extern T3SQLCancel pODBC3SQLCancel;
+ extern T3SQLEndTran pODBC3SQLEndTran;
+ extern T3SQLDisconnect pODBC3SQLDisconnect;
+ extern T3SQLFreeHandle pODBC3SQLFreeHandle;
+ extern T3SQLGetCursorName pODBC3SQLGetCursorName;
+ extern T3SQLNativeSql pODBC3SQLNativeSql;
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/odbc/OPreparedStatement.hxx b/connectivity/source/inc/odbc/OPreparedStatement.hxx
new file mode 100644
index 0000000000..37e29db9c5
--- /dev/null
+++ b/connectivity/source/inc/odbc/OPreparedStatement.hxx
@@ -0,0 +1,149 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <odbc/odbcbasedllapi.hxx>
+#include <odbc/OStatement.hxx>
+#include <com/sun/star/sdbc/XPreparedStatement.hpp>
+#include <com/sun/star/sdbc/XParameters.hpp>
+#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
+#include <com/sun/star/sdbc/XPreparedBatchExecution.hpp>
+#include <com/sun/star/io/XInputStream.hpp>
+#include <cppuhelper/implbase5.hxx>
+
+namespace connectivity::odbc
+ {
+
+ class OBoundParam;
+ typedef ::cppu::ImplHelper5< css::sdbc::XPreparedStatement,
+ css::sdbc::XParameters,
+ css::sdbc::XPreparedBatchExecution,
+ css::sdbc::XResultSetMetaDataSupplier,
+ css::lang::XServiceInfo> OPreparedStatement_BASE;
+
+ class OOO_DLLPUBLIC_ODBCBASE OPreparedStatement final :
+ public OStatement_BASE2,
+ public OPreparedStatement_BASE
+ {
+ static const short invalid_scale = -1;
+
+ // Data attributes
+
+ SQLSMALLINT numParams; // Number of parameter markers for the prepared statement
+
+ std::unique_ptr<OBoundParam[]> boundParams;
+ // Array of bound parameter objects. Each parameter marker will have a
+ // corresponding object to hold bind information, and resulting data.
+ css::uno::Reference< css::sdbc::XResultSetMetaData > m_xMetaData;
+ bool m_bPrepared;
+
+ void FreeParams();
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void putParamData (sal_Int32 index);
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void setStream (sal_Int32 ParameterIndex,const css::uno::Reference< css::io::XInputStream>& x,
+ SQLLEN length,sal_Int32 SQLtype);
+ SQLLEN* getLengthBuf (sal_Int32 index);
+ void* allocBindBuf ( sal_Int32 index, sal_Int32 bufLen);
+ /// @throws css::sdbc::SQLException
+ void initBoundParam ();
+ void setParameterPre(sal_Int32 parameterIndex);
+ template <typename T> void setScalarParameter(sal_Int32 parameterIndex, sal_Int32 _nType, SQLULEN _nColumnSize, const T i_Value);
+ template <typename T> void setScalarParameter(sal_Int32 parameterIndex, sal_Int32 _nType, SQLULEN _nColumnSize, sal_Int32 _nScale, const T i_Value);
+ void setParameter(sal_Int32 parameterIndex, sal_Int32 _nType, SQLULEN _nColumnSize, sal_Int32 _nScale, const void* _pData, SQLULEN _nDataLen, SQLLEN _nDataAllocLen);
+ // Wrappers for special cases
+ void setParameter(sal_Int32 parameterIndex, sal_Int32 _nType, sal_Int16 _nScale, const OUString &_sData);
+ void setParameter(sal_Int32 parameterIndex, sal_Int32 _nType, const css::uno::Sequence< sal_Int8 > &Data);
+
+ bool isPrepared() const { return m_bPrepared;}
+ void prepareStatement();
+ void checkParameterIndex(sal_Int32 _parameterIndex);
+
+ /**
+ creates the driver specific resultset (factory)
+ */
+ virtual rtl::Reference<OResultSet> createResultSet() override;
+
+ virtual void SAL_CALL setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,
+ const css::uno::Any& rValue) override;
+ public:
+ DECLARE_SERVICE_INFO();
+ // A ctor, needed to return the object
+ OPreparedStatement( OConnection* _pConnection,const OUString& sql);
+ virtual ~OPreparedStatement() override;
+ OPreparedStatement& operator=( OPreparedStatement const & ) = delete; // MSVC2015 workaround
+ OPreparedStatement( OPreparedStatement const & ) = delete; // MSVC2015 workaround
+
+ //XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+ //XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override;
+
+ // XPreparedStatement
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL executeQuery( ) override;
+ virtual sal_Int32 SAL_CALL executeUpdate( ) override;
+ virtual sal_Bool SAL_CALL execute( ) override;
+ virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL getConnection( ) override;
+ // XParameters
+ virtual void SAL_CALL setNull( sal_Int32 parameterIndex, sal_Int32 sqlType ) override;
+ virtual void SAL_CALL setObjectNull( sal_Int32 parameterIndex, sal_Int32 sqlType, const OUString& typeName ) override;
+ virtual void SAL_CALL setBoolean( sal_Int32 parameterIndex, sal_Bool x ) override;
+ virtual void SAL_CALL setByte( sal_Int32 parameterIndex, sal_Int8 x ) override;
+ virtual void SAL_CALL setShort( sal_Int32 parameterIndex, sal_Int16 x ) override;
+ virtual void SAL_CALL setInt( sal_Int32 parameterIndex, sal_Int32 x ) override;
+ virtual void SAL_CALL setLong( sal_Int32 parameterIndex, sal_Int64 x ) override;
+ virtual void SAL_CALL setFloat( sal_Int32 parameterIndex, float x ) override;
+ virtual void SAL_CALL setDouble( sal_Int32 parameterIndex, double x ) override;
+ virtual void SAL_CALL setString( sal_Int32 parameterIndex, const OUString& x ) override;
+ virtual void SAL_CALL setBytes( sal_Int32 parameterIndex, const css::uno::Sequence< sal_Int8 >& x ) override;
+ virtual void SAL_CALL setDate( sal_Int32 parameterIndex, const css::util::Date& x ) override;
+ virtual void SAL_CALL setTime( sal_Int32 parameterIndex, const css::util::Time& x ) override;
+ virtual void SAL_CALL setTimestamp( sal_Int32 parameterIndex, const css::util::DateTime& x ) override;
+ virtual void SAL_CALL setBinaryStream( sal_Int32 parameterIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override;
+ virtual void SAL_CALL setCharacterStream( sal_Int32 parameterIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override;
+ virtual void SAL_CALL setObject( sal_Int32 parameterIndex, const css::uno::Any& x ) override;
+ virtual void SAL_CALL setObjectWithInfo( sal_Int32 parameterIndex, const css::uno::Any& x, sal_Int32 targetSqlType, sal_Int32 scale ) override;
+ virtual void SAL_CALL setRef( sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XRef >& x ) override;
+ virtual void SAL_CALL setBlob( sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XBlob >& x ) override;
+ virtual void SAL_CALL setClob( sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XClob >& x ) override;
+ virtual void SAL_CALL setArray( sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XArray >& x ) override;
+ virtual void SAL_CALL clearParameters( ) override;
+ // XPreparedBatchExecution
+ virtual void SAL_CALL addBatch( ) override;
+ virtual void SAL_CALL clearBatch( ) override;
+ virtual css::uno::Sequence< sal_Int32 > SAL_CALL executeBatch( ) override;
+ // XCloseable
+ virtual void SAL_CALL close( ) override;
+ // XResultSetMetaDataSupplier
+ virtual css::uno::Reference< css::sdbc::XResultSetMetaData > SAL_CALL getMetaData( ) override;
+
+ public:
+ using OStatement_Base::executeQuery;
+ using OStatement_Base::executeUpdate;
+ using OStatement_Base::execute;
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/odbc/OResultSet.hxx b/connectivity/source/inc/odbc/OResultSet.hxx
new file mode 100644
index 0000000000..6de7adc281
--- /dev/null
+++ b/connectivity/source/inc/odbc/OResultSet.hxx
@@ -0,0 +1,354 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/sdbc/FetchDirection.hpp>
+#include <com/sun/star/sdbc/XResultSet.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
+#include <com/sun/star/sdbc/XCloseable.hpp>
+#include <com/sun/star/sdbc/XColumnLocate.hpp>
+#include <com/sun/star/util/XCancellable.hpp>
+#include <com/sun/star/sdbc/XWarningsSupplier.hpp>
+#include <com/sun/star/sdbc/XResultSetUpdate.hpp>
+#include <com/sun/star/sdbc/XRowUpdate.hpp>
+#include <com/sun/star/sdbcx/XRowLocate.hpp>
+#include <com/sun/star/sdbcx/XDeleteRows.hpp>
+#include <cppuhelper/compbase.hxx>
+#include <comphelper/proparrhlp.hxx>
+#include <odbc/OFunctions.hxx>
+#include <odbc/OStatement.hxx>
+#include <odbc/odbcbasedllapi.hxx>
+#include <connectivity/CommonTools.hxx>
+#include <connectivity/FValue.hxx>
+#include <TSkipDeletedSet.hxx>
+#include <memory>
+
+namespace connectivity::odbc
+ {
+
+ /*
+ ** java_sql_ResultSet
+ */
+ typedef ::cppu::WeakComponentImplHelper< css::sdbc::XResultSet,
+ css::sdbc::XRow,
+ css::sdbc::XResultSetMetaDataSupplier,
+ css::util::XCancellable,
+ css::sdbc::XWarningsSupplier,
+ css::sdbc::XResultSetUpdate,
+ css::sdbc::XRowUpdate,
+ css::sdbcx::XRowLocate,
+ css::sdbcx::XDeleteRows,
+ css::sdbc::XCloseable,
+ css::sdbc::XColumnLocate,
+ css::lang::XServiceInfo> OResultSet_BASE;
+
+
+ typedef std::pair<sal_Int64,sal_Int32> TVoidPtr;
+ typedef std::allocator< TVoidPtr > TVoidAlloc;
+ typedef std::vector<TVoidPtr> TVoidVector;
+ /// Functor object for class ZZ returntype is void
+ struct OOO_DLLPUBLIC_ODBCBASE TBookmarkPosMapCompare
+ {
+ bool operator()( const css::uno::Sequence<sal_Int8>& _rLH,
+ const css::uno::Sequence<sal_Int8>& _rRH) const
+ {
+ if(_rLH.getLength() == _rRH.getLength())
+ {
+ sal_Int32 nCount = _rLH.getLength();
+ if(nCount != 4)
+ {
+ const sal_Int8* pLHBack = _rLH.getConstArray() + nCount - 1;
+ const sal_Int8* pRHBack = _rRH.getConstArray() + nCount - 1;
+
+ sal_Int32 i;
+ for(i=0;i < nCount;++i,--pLHBack,--pRHBack)
+ {
+ if(!(*pLHBack) && *pRHBack)
+ return true;
+ else if(*pLHBack && !(*pRHBack))
+ return false;
+ }
+ for(i=0,++pLHBack,++pRHBack;i < nCount;++pLHBack,++pRHBack,++i)
+ if(*pLHBack < *pRHBack)
+ return true;
+ return false;
+ }
+ else
+ return *reinterpret_cast<const sal_Int32*>(_rLH.getConstArray()) < *reinterpret_cast<const sal_Int32*>(_rRH.getConstArray());
+
+ }
+ else
+ return _rLH.getLength() < _rRH.getLength();
+ }
+ };
+
+ typedef std::map< css::uno::Sequence<sal_Int8>, sal_Int32,TBookmarkPosMapCompare > TBookmarkPosMap;
+
+ class OOO_DLLPUBLIC_ODBCBASE OResultSet :
+ public cppu::BaseMutex,
+ public ::connectivity::IResultSetHelper,
+ public OResultSet_BASE,
+ public ::cppu::OPropertySetHelper,
+ public ::comphelper::OPropertyArrayUsageHelper<OResultSet>
+ {
+ protected:
+ TBookmarkPosMap m_aPosToBookmarks;
+ // used top hold the information about the value and the datatype to save calls to metadata
+ typedef std::vector<ORowSetValue> TDataRow;
+
+ TVoidVector m_aBindVector;
+ std::vector<SQLLEN> m_aLengthVector;
+ std::map<sal_Int32,SWORD> m_aODBCColumnTypes;
+
+ // In baseline ODBC, SQLGetData can only be called on monotonically increasing column numbers.
+ // additionally, any variable-length data can be fetched only once (possibly in parts);
+ // after that, SQLGetData returns SQL_NO_DATA.
+ // In order to insulate our callers from these restrictions,
+ // we cache the current row in m_aRow.
+ // If the driver claims to support the GD_ANY_ORDER extension,
+ // we read and cache only the columns requested by a caller.
+ // Else, we read and cache all columns whose number is <= a requested column.
+ // m_aRow[colNumber].getBound() says if it contains an up-to-date value or not.
+ TDataRow m_aRow;
+ bool m_bFetchDataInOrder;
+ SQLHANDLE m_aStatementHandle;
+ SQLHANDLE m_aConnectionHandle;
+ OStatement_Base* m_pStatement;
+ std::unique_ptr<OSkipDeletedSet> m_pSkipDeletedSet;
+ css::uno::Reference< css::uno::XInterface> m_xStatement;
+ css::uno::Reference< css::sdbc::XResultSetMetaData> m_xMetaData;
+ std::unique_ptr<SQLUSMALLINT[]> m_pRowStatusArray;
+ rtl_TextEncoding m_nTextEncoding;
+ sal_Int32 m_nRowPos;
+ mutable sal_uInt32 m_nUseBookmarks;
+ SQLRETURN m_nCurrentFetchState;
+ bool m_bWasNull;
+ bool m_bEOF; // after last record
+ bool m_bRowInserted;
+ bool m_bRowDeleted;
+ bool m_bUseFetchScroll;
+
+ bool isBookmarkable() const;
+ sal_Int32 getResultSetConcurrency() const;
+ sal_Int32 getResultSetType() const;
+ static sal_Int32 getFetchDirection() { return css::sdbc::FetchDirection::FORWARD; }
+ sal_Int32 getFetchSize() const;
+ OUString getCursorName() const;
+ template < typename T, SQLINTEGER BufferLength > T getStmtOption (SQLINTEGER fOption) const;
+
+ void setFetchDirection(sal_Int32 _par0);
+ void setFetchSize(sal_Int32 _par0);
+ template < typename T, SQLINTEGER BufferLength > SQLRETURN setStmtOption (SQLINTEGER fOption, T value) const;
+
+
+ void ensureCacheForColumn(sal_Int32 columnIndex);
+ void invalidateCache();
+ void fillColumn(sal_Int32 _nToColumn);
+ void allocBuffer();
+ void releaseBuffer();
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void updateValue(sal_Int32 columnIndex, SQLSMALLINT _nType, void const * _pValue);
+ void fillNeededData(SQLRETURN _nRet);
+ bool moveImpl(IResultSetHelper::Movement _eCursorPosition, sal_Int32 _nOffset);
+ TVoidPtr allocBindColumn(sal_Int32 _nType,sal_Int32 _nColumnIndex);
+ SQLRETURN unbind(bool _bUnbindHandle = true);
+ SWORD impl_getColumnType_nothrow(sal_Int32 columnIndex);
+
+ // helper to implement XRow::getXXX in simple cases
+ template < typename T > T getValue( sal_Int32 columnIndex );
+ // impl_getXXX are the functions that do the actual fetching from ODBC, ignoring the cache
+ // for simple cases
+ template < typename T > T impl_getValue( const sal_Int32 _nColumnIndex, SQLSMALLINT nType );
+ // these cases need some special treatment
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ bool impl_getBoolean( sal_Int32 columnIndex );
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ css::uno::Sequence< sal_Int8 > impl_getBytes( sal_Int32 columnIndex );
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ css::util::Date impl_getDate( sal_Int32 columnIndex );
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ css::util::Time impl_getTime( sal_Int32 columnIndex );
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ css::util::DateTime impl_getTimestamp( sal_Int32 columnIndex );
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ sal_Int64 impl_getLong( sal_Int32 columnIndex );
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ OUString impl_getString( sal_Int32 columnIndex );
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ css::uno::Sequence<sal_Int8> impl_getBookmark( );
+
+
+ // OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override;
+ // OPropertySetHelper
+ virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override;
+
+ virtual sal_Bool SAL_CALL convertFastPropertyValue(
+ css::uno::Any & rConvertedValue,
+ css::uno::Any & rOldValue,
+ sal_Int32 nHandle,
+ const css::uno::Any& rValue ) override;
+ virtual void SAL_CALL setFastPropertyValue_NoBroadcast(
+ sal_Int32 nHandle,
+ const css::uno::Any& rValue
+ ) override;
+ virtual void SAL_CALL getFastPropertyValue(
+ css::uno::Any& rValue,
+ sal_Int32 nHandle
+ ) const override;
+ public:
+ DECLARE_SERVICE_INFO();
+ // A ctor that is needed for returning the object
+ OResultSet( SQLHANDLE _pStatementHandle,OStatement_Base* pStmt);
+ virtual ~OResultSet() override;
+
+ void construct();
+
+ oslGenericFunction getOdbcFunction(ODBC3SQLFunctionId _nIndex) const
+ {
+ return m_pStatement->getOdbcFunction(_nIndex);
+ }
+
+ css::uno::Reference< css::uno::XInterface > operator *()
+ {
+ return css::uno::Reference< css::uno::XInterface >(*static_cast<OResultSet_BASE*>(this));
+ }
+
+ void setMetaData(const css::uno::Reference< css::sdbc::XResultSetMetaData>& _xMetaData) { m_xMetaData = _xMetaData;}
+
+ // ::cppu::OComponentHelper
+ virtual void SAL_CALL disposing() override;
+ // XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+ //XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override;
+ // XPropertySet
+ virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override;
+ // XResultSet
+ virtual sal_Bool SAL_CALL next( ) override;
+ virtual sal_Bool SAL_CALL isBeforeFirst( ) override;
+ virtual sal_Bool SAL_CALL isAfterLast( ) override;
+ virtual sal_Bool SAL_CALL isFirst( ) override;
+ virtual sal_Bool SAL_CALL isLast( ) override;
+ virtual void SAL_CALL beforeFirst( ) override;
+ virtual void SAL_CALL afterLast( ) override;
+ virtual sal_Bool SAL_CALL first( ) override;
+ virtual sal_Bool SAL_CALL last( ) override;
+ virtual sal_Int32 SAL_CALL getRow( ) override;
+ virtual sal_Bool SAL_CALL absolute( sal_Int32 row ) override;
+ virtual sal_Bool SAL_CALL relative( sal_Int32 rows ) override;
+ virtual sal_Bool SAL_CALL previous( ) override;
+ virtual void SAL_CALL refreshRow( ) override;
+ virtual sal_Bool SAL_CALL rowUpdated( ) override;
+ virtual sal_Bool SAL_CALL rowInserted( ) override;
+ virtual sal_Bool SAL_CALL rowDeleted( ) override;
+ virtual css::uno::Reference< css::uno::XInterface > SAL_CALL getStatement( ) override;
+ // XRow
+ virtual sal_Bool SAL_CALL wasNull( ) override;
+ virtual OUString SAL_CALL getString( sal_Int32 columnIndex ) override;
+ virtual sal_Bool SAL_CALL getBoolean( sal_Int32 columnIndex ) override;
+ virtual sal_Int8 SAL_CALL getByte( sal_Int32 columnIndex ) override;
+ virtual sal_Int16 SAL_CALL getShort( sal_Int32 columnIndex ) override;
+ virtual sal_Int32 SAL_CALL getInt( sal_Int32 columnIndex ) override;
+ virtual sal_Int64 SAL_CALL getLong( sal_Int32 columnIndex ) override;
+ virtual float SAL_CALL getFloat( sal_Int32 columnIndex ) override;
+ virtual double SAL_CALL getDouble( sal_Int32 columnIndex ) override;
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getBytes( sal_Int32 columnIndex ) override;
+ virtual css::util::Date SAL_CALL getDate( sal_Int32 columnIndex ) override;
+ virtual css::util::Time SAL_CALL getTime( sal_Int32 columnIndex ) override;
+ virtual css::util::DateTime SAL_CALL getTimestamp( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getBinaryStream( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getCharacterStream( sal_Int32 columnIndex ) override;
+ virtual css::uno::Any SAL_CALL getObject( sal_Int32 columnIndex, const css::uno::Reference< css::container::XNameAccess >& typeMap ) override;
+ virtual css::uno::Reference< css::sdbc::XRef > SAL_CALL getRef( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XBlob > SAL_CALL getBlob( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XClob > SAL_CALL getClob( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XArray > SAL_CALL getArray( sal_Int32 columnIndex ) override;
+ // XResultSetMetaDataSupplier
+ virtual css::uno::Reference< css::sdbc::XResultSetMetaData > SAL_CALL getMetaData( ) override;
+ // XCancellable
+ virtual void SAL_CALL cancel( ) override;
+ // XCloseable
+ virtual void SAL_CALL close( ) override;
+ // XWarningsSupplier
+ virtual css::uno::Any SAL_CALL getWarnings( ) override;
+ virtual void SAL_CALL clearWarnings( ) override;
+ // XResultSetUpdate
+ virtual void SAL_CALL insertRow( ) override;
+ virtual void SAL_CALL updateRow( ) override;
+ virtual void SAL_CALL deleteRow( ) override;
+ virtual void SAL_CALL cancelRowUpdates( ) override;
+ virtual void SAL_CALL moveToInsertRow( ) override;
+ virtual void SAL_CALL moveToCurrentRow( ) override;
+ // XRowUpdate
+ virtual void SAL_CALL updateNull( sal_Int32 columnIndex ) override;
+ virtual void SAL_CALL updateBoolean( sal_Int32 columnIndex, sal_Bool x ) override;
+ virtual void SAL_CALL updateByte( sal_Int32 columnIndex, sal_Int8 x ) override;
+ virtual void SAL_CALL updateShort( sal_Int32 columnIndex, sal_Int16 x ) override;
+ virtual void SAL_CALL updateInt( sal_Int32 columnIndex, sal_Int32 x ) override;
+ virtual void SAL_CALL updateLong( sal_Int32 columnIndex, sal_Int64 x ) override;
+ virtual void SAL_CALL updateFloat( sal_Int32 columnIndex, float x ) override;
+ virtual void SAL_CALL updateDouble( sal_Int32 columnIndex, double x ) override;
+ virtual void SAL_CALL updateString( sal_Int32 columnIndex, const OUString& x ) override;
+ virtual void SAL_CALL updateBytes( sal_Int32 columnIndex, const css::uno::Sequence< sal_Int8 >& x ) override;
+ virtual void SAL_CALL updateDate( sal_Int32 columnIndex, const css::util::Date& x ) override;
+ virtual void SAL_CALL updateTime( sal_Int32 columnIndex, const css::util::Time& x ) override;
+ virtual void SAL_CALL updateTimestamp( sal_Int32 columnIndex, const css::util::DateTime& x ) override;
+ virtual void SAL_CALL updateBinaryStream( sal_Int32 columnIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override;
+ virtual void SAL_CALL updateCharacterStream( sal_Int32 columnIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override;
+ virtual void SAL_CALL updateObject( sal_Int32 columnIndex, const css::uno::Any& x ) override;
+ virtual void SAL_CALL updateNumericObject( sal_Int32 columnIndex, const css::uno::Any& x, sal_Int32 scale ) override;
+ // XColumnLocate
+ virtual sal_Int32 SAL_CALL findColumn( const OUString& columnName ) override;
+ // XRowLocate
+ virtual css::uno::Any SAL_CALL getBookmark( ) override;
+ virtual sal_Bool SAL_CALL moveToBookmark( const css::uno::Any& bookmark ) override;
+ virtual sal_Bool SAL_CALL moveRelativeToBookmark( const css::uno::Any& bookmark, sal_Int32 rows ) override;
+ virtual sal_Int32 SAL_CALL compareBookmarks( const css::uno::Any& first, const css::uno::Any& second ) override;
+ virtual sal_Bool SAL_CALL hasOrderedBookmarks( ) override;
+ virtual sal_Int32 SAL_CALL hashBookmark( const css::uno::Any& bookmark ) override;
+ // XDeleteRows
+ virtual css::uno::Sequence< sal_Int32 > SAL_CALL deleteRows( const css::uno::Sequence< css::uno::Any >& rows ) override;
+
+ // IResultSetHelper
+ virtual bool move(IResultSetHelper::Movement _eCursorPosition, sal_Int32 _nOffset, bool _bRetrieveData) override;
+ virtual sal_Int32 getDriverPos() const override;
+ virtual bool isRowDeleted() const override;
+
+ protected:
+ using OPropertySetHelper::getFastPropertyValue;
+ };
+
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/odbc/OResultSetMetaData.hxx b/connectivity/source/inc/odbc/OResultSetMetaData.hxx
new file mode 100644
index 0000000000..ea32a453e9
--- /dev/null
+++ b/connectivity/source/inc/odbc/OResultSetMetaData.hxx
@@ -0,0 +1,116 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/sdbc/XResultSetMetaData.hpp>
+#include <cppuhelper/implbase.hxx>
+#include <odbc/OFunctions.hxx>
+#include <odbc/odbcbasedllapi.hxx>
+#include <vector>
+#include <odbc/OConnection.hxx>
+
+namespace connectivity::odbc
+ {
+
+ //************ Class: ResultSetMetaData
+
+ typedef ::cppu::WeakImplHelper< css::sdbc::XResultSetMetaData> OResultSetMetaData_BASE;
+
+ class OOO_DLLPUBLIC_ODBCBASE OResultSetMetaData final :
+ public OResultSetMetaData_BASE
+ {
+ std::vector<sal_Int32> m_vMapping; // when not every column is needed
+ std::map<sal_Int32,sal_Int32> m_aColumnTypes;
+
+ SQLHANDLE m_aStatementHandle;
+ OConnection* m_pConnection;
+ sal_Int32 m_nColCount;
+ bool m_bUseODBC2Types;
+
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ OUString getCharColAttrib(sal_Int32 column,sal_Int32 ident);
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ sal_Int32 getNumColAttrib(sal_Int32 column,sal_Int32 ident);
+ public:
+ // A ctor that is needed for returning the object
+ OResultSetMetaData(OConnection* _pConnection, SQLHANDLE _pStmt )
+ :m_aStatementHandle( _pStmt )
+ ,m_pConnection(_pConnection)
+ ,m_nColCount(-1)
+ ,m_bUseODBC2Types(false)
+ {}
+ OResultSetMetaData(OConnection* _pConnection, SQLHANDLE _pStmt, std::vector<sal_Int32>&& _vMapping)
+ :m_vMapping(std::move(_vMapping))
+ ,m_aStatementHandle( _pStmt )
+ ,m_pConnection(_pConnection)
+ ,m_nColCount(m_vMapping.size()-1)
+ ,m_bUseODBC2Types(false)
+ {}
+ virtual ~OResultSetMetaData() override;
+
+
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ static SQLLEN getNumColAttrib(OConnection const * _pConnection
+ ,SQLHANDLE _aStatementHandle
+ ,const css::uno::Reference< css::uno::XInterface >& _xInterface
+ ,sal_Int32 _column
+ ,sal_Int32 ident);
+
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ static SQLSMALLINT getColumnODBCType(OConnection const * _pConnection
+ ,SQLHANDLE _aStatementHandle
+ ,const css::uno::Reference< css::uno::XInterface >& _xInterface
+ ,sal_Int32 column);
+
+ oslGenericFunction getOdbcFunction(ODBC3SQLFunctionId _nIndex) const
+ {
+ return m_pConnection->getOdbcFunction(_nIndex);
+ }
+
+ virtual sal_Int32 SAL_CALL getColumnCount( ) override;
+ virtual sal_Bool SAL_CALL isAutoIncrement( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isCaseSensitive( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isSearchable( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isCurrency( sal_Int32 column ) override;
+ virtual sal_Int32 SAL_CALL isNullable( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isSigned( sal_Int32 column ) override;
+ virtual sal_Int32 SAL_CALL getColumnDisplaySize( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getColumnLabel( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getColumnName( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getSchemaName( sal_Int32 column ) override;
+ virtual sal_Int32 SAL_CALL getPrecision( sal_Int32 column ) override;
+ virtual sal_Int32 SAL_CALL getScale( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getTableName( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getCatalogName( sal_Int32 column ) override;
+ virtual sal_Int32 SAL_CALL getColumnType( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getColumnTypeName( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isReadOnly( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isWritable( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isDefinitelyWritable( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getColumnServiceName( sal_Int32 column ) override;
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/odbc/OStatement.hxx b/connectivity/source/inc/odbc/OStatement.hxx
new file mode 100644
index 0000000000..1e48310873
--- /dev/null
+++ b/connectivity/source/inc/odbc/OStatement.hxx
@@ -0,0 +1,244 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/sdbc/XStatement.hpp>
+#include <com/sun/star/sdbc/XWarningsSupplier.hpp>
+#include <com/sun/star/sdbc/XMultipleResults.hpp>
+#include <com/sun/star/sdbc/XBatchExecution.hpp>
+#include <com/sun/star/sdbc/XCloseable.hpp>
+#include <com/sun/star/sdbc/SQLWarning.hpp>
+#include <com/sun/star/sdbc/XGeneratedResultSet.hpp>
+#include <com/sun/star/util/XCancellable.hpp>
+#include <comphelper/proparrhlp.hxx>
+#include <cppuhelper/compbase.hxx>
+#include <cppuhelper/basemutex.hxx>
+#include <connectivity/CommonTools.hxx>
+#include <odbc/OFunctions.hxx>
+#include <odbc/OConnection.hxx>
+#include <odbc/odbcbasedllapi.hxx>
+#include <string_view>
+#include <vector>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+
+namespace connectivity::odbc
+ {
+
+ typedef ::cppu::WeakComponentImplHelper< css::sdbc::XStatement,
+ css::sdbc::XWarningsSupplier,
+ css::util::XCancellable,
+ css::sdbc::XCloseable,
+ css::sdbc::XGeneratedResultSet,
+ css::sdbc::XMultipleResults> OStatement_BASE;
+
+ class OResultSet;
+
+ //************ Class: java.sql.Statement
+
+ class OOO_DLLPUBLIC_ODBCBASE OStatement_Base :
+ public cppu::BaseMutex,
+ public OStatement_BASE,
+ public ::cppu::OPropertySetHelper,
+ public ::comphelper::OPropertyArrayUsageHelper<OStatement_Base>
+
+ {
+ css::sdbc::SQLWarning m_aLastWarning;
+ protected:
+ css::uno::WeakReference< css::sdbc::XResultSet> m_xResultSet; // The last ResultSet created
+ css::uno::Reference< css::sdbc::XStatement> m_xGeneratedStatement;
+ // for this Statement
+
+ std::vector< OUString> m_aBatchVector;
+ OUString m_sSqlStatement;
+
+ rtl::Reference<OConnection> m_pConnection;// The owning Connection object
+ SQLHANDLE m_aStatementHandle;
+ SQLUSMALLINT* m_pRowStatusArray;
+
+ protected:
+
+ sal_Int64 getQueryTimeOut() const;
+ sal_Int64 getMaxFieldSize() const;
+ sal_Int64 getMaxRows() const;
+ sal_Int32 getResultSetConcurrency() const;
+ sal_Int32 getResultSetType() const;
+ sal_Int32 getFetchDirection() const;
+ sal_Int32 getFetchSize() const;
+ OUString getCursorName() const;
+ bool isUsingBookmarks() const;
+ bool getEscapeProcessing() const;
+ template < typename T, SQLINTEGER BufferLength > T getStmtOption (SQLINTEGER fOption) const;
+
+ void setQueryTimeOut(sal_Int64 _par0) ;
+ void setMaxFieldSize(sal_Int64 _par0) ;
+ void setMaxRows(sal_Int64 _par0) ;
+ void setFetchDirection(sal_Int32 _par0) ;
+ void setFetchSize(sal_Int32 _par0) ;
+ void setCursorName(std::u16string_view _par0);
+ void setEscapeProcessing( const bool _bEscapeProc );
+ template < typename T, SQLINTEGER BufferLength > SQLRETURN setStmtOption (SQLINTEGER fOption, T value) const;
+
+ void setResultSetConcurrency(sal_Int32 _par0) ;
+ void setResultSetType(sal_Int32 _par0) ;
+ void setUsingBookmarks(bool _bUseBookmark) ;
+
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void reset();
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void clearMyResultSet();
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void setWarning (const css::sdbc::SQLWarning &ex);
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ bool lockIfNecessary (const OUString& sql);
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ sal_Int32 getColumnCount();
+
+
+ // getResultSet
+ // getResultSet returns the current result as a ResultSet. It
+ // returns NULL if the current result is not a ResultSet.
+
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ css::uno::Reference<css::sdbc::XResultSet> getResultSet(bool checkCount);
+ /**
+ creates the driver specific resultset (factory)
+ */
+ virtual rtl::Reference<OResultSet> createResultSet();
+
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ SQLLEN getRowCount();
+
+
+ void disposeResultSet();
+
+ // OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override;
+ // OPropertySetHelper
+ virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override;
+ virtual sal_Bool SAL_CALL convertFastPropertyValue(
+ css::uno::Any & rConvertedValue,
+ css::uno::Any & rOldValue,
+ sal_Int32 nHandle,
+ const css::uno::Any& rValue ) override;
+ virtual void SAL_CALL setFastPropertyValue_NoBroadcast(
+ sal_Int32 nHandle,
+ const css::uno::Any& rValue
+ ) override;
+ virtual void SAL_CALL getFastPropertyValue(
+ css::uno::Any& rValue,
+ sal_Int32 nHandle
+ ) const override;
+ virtual ~OStatement_Base() override;
+
+ public:
+ OStatement_Base(OConnection* _pConnection );
+ using OStatement_BASE::operator css::uno::Reference< css::uno::XInterface >;
+
+ oslGenericFunction getOdbcFunction(ODBC3SQLFunctionId _nIndex) const
+ {
+ return m_pConnection->getOdbcFunction(_nIndex);
+ }
+ // OComponentHelper
+ virtual void SAL_CALL disposing() override;
+ // XInterface
+ virtual void SAL_CALL release() noexcept override;
+ virtual void SAL_CALL acquire() noexcept override;
+ // XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ //XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override;
+
+ // XPropertySet
+ virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override;
+ // XStatement
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL executeQuery( const OUString& sql ) override ;
+ virtual sal_Int32 SAL_CALL executeUpdate( const OUString& sql ) override ;
+ virtual sal_Bool SAL_CALL execute( const OUString& sql ) override ;
+ virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL getConnection( ) override ;
+ // XWarningsSupplier
+ virtual css::uno::Any SAL_CALL getWarnings( ) override;
+ virtual void SAL_CALL clearWarnings( ) override;
+ // XCancellable
+ virtual void SAL_CALL cancel( ) override;
+ // XCloseable
+ virtual void SAL_CALL close( ) override;
+ // XMultipleResults
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getResultSet( ) override;
+ virtual sal_Int32 SAL_CALL getUpdateCount( ) override;
+ virtual sal_Bool SAL_CALL getMoreResults( ) override;
+ //XGeneratedResultSet
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getGeneratedValues( ) override;
+
+ // other methods
+ SQLHANDLE getConnectionHandle() { return m_pConnection->getConnection(); }
+ OConnection* getOwnConnection() const { return m_pConnection.get();}
+ /** getCursorProperties return the properties for a specific cursor type
+ @param _nCursorType the CursorType
+ @param bFirst when true the first property set is returned
+
+ @return the cursor properties
+ */
+ SQLUINTEGER getCursorProperties(SQLINTEGER _nCursorType, bool bFirst);
+
+ protected:
+ using OPropertySetHelper::getFastPropertyValue;
+ };
+
+ class OOO_DLLPUBLIC_ODBCBASE OStatement_BASE2 : public OStatement_Base
+ {
+ public:
+ OStatement_BASE2(OConnection* _pConnection ) :
+ OStatement_Base(_pConnection )
+ {}
+ // OComponentHelper
+ virtual void SAL_CALL disposing() override;
+ };
+
+ class OOO_DLLPUBLIC_ODBCBASE OStatement :
+ public OStatement_BASE2,
+ public css::sdbc::XBatchExecution,
+ public css::lang::XServiceInfo
+ {
+ protected:
+ virtual ~OStatement() override {}
+ public:
+ // A ctor that is needed for returning the object
+ OStatement( OConnection* _pConnection) : OStatement_BASE2( _pConnection){}
+ DECLARE_SERVICE_INFO();
+
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+ // XBatchExecution
+ virtual void SAL_CALL addBatch( const OUString& sql ) override;
+ virtual void SAL_CALL clearBatch( ) override;
+ virtual css::uno::Sequence< sal_Int32 > SAL_CALL executeBatch( ) override;
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/odbc/OTools.hxx b/connectivity/source/inc/odbc/OTools.hxx
new file mode 100644
index 0000000000..b03db91dce
--- /dev/null
+++ b/connectivity/source/inc/odbc/OTools.hxx
@@ -0,0 +1,245 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <connectivity/odbc.hxx>
+#include <odbc/odbcbasedllapi.hxx>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <com/sun/star/util/Date.hpp>
+#include <com/sun/star/util/Time.hpp>
+#include <com/sun/star/util/DateTime.hpp>
+#include <osl/thread.h>
+#include <rtl/ustring.hxx>
+#include <com/sun/star/uno/Sequence.hxx>
+#include <rtl/textenc.h>
+
+enum class ODBC3SQLFunctionId
+{
+ AllocHandle = 1,
+ Connect = 2,
+ DriverConnect = 3,
+ BrowseConnect = 4,
+ DataSources = 5,
+ Drivers = 6,
+ GetInfo = 7,
+ GetFunctions = 8,
+ GetTypeInfo = 9,
+ SetConnectAttr = 10,
+ GetConnectAttr = 11,
+ SetEnvAttr = 12,
+ GetEnvAttr = 13,
+ SetStmtAttr = 14,
+ GetStmtAttr = 15,
+ Prepare = 16,
+ BindParameter = 17,
+ SetCursorName = 18,
+ Execute = 19,
+ ExecDirect = 20,
+ DescribeParam = 21,
+ NumParams = 22,
+ ParamData = 23,
+ PutData = 24,
+ RowCount = 25,
+ NumResultCols = 26,
+ DescribeCol = 27,
+ ColAttribute = 28,
+ BindCol = 29,
+ Fetch = 30,
+ FetchScroll = 31,
+ GetData = 32,
+ SetPos = 33,
+ BulkOperations = 34,
+ MoreResults = 35,
+ GetDiagRec = 36,
+ ColumnPrivileges = 37,
+ Columns = 38,
+ ForeignKeys = 39,
+ PrimaryKeys = 40,
+ ProcedureColumns = 41,
+ Procedures = 42,
+ SpecialColumns = 43,
+ Statistics = 44,
+ TablePrivileges = 45,
+ Tables = 46,
+ FreeStmt = 47,
+ CloseCursor = 48,
+ Cancel = 49,
+ EndTran = 50,
+ Disconnect = 51,
+ FreeHandle = 52,
+ GetCursorName = 53,
+ NativeSql = 54,
+};
+
+namespace connectivity::odbc
+ {
+ class OConnection;
+
+ const sal_Int32 MAX_PUT_DATA_LENGTH = 2000;
+
+ class OOO_DLLPUBLIC_ODBCBASE OTools
+ {
+ public:
+ /// @throws css::sdbc::SQLException
+ static void ThrowException( const OConnection* _pConnection,
+ SQLRETURN _rRetCode,
+ SQLHANDLE _pContext,
+ SQLSMALLINT _nHandleType,
+ const css::uno::Reference< css::uno::XInterface >& _xInterface,
+ bool _bNoFound=true);
+
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ static void GetInfo(OConnection const * _pConnection,
+ SQLHANDLE _aConnectionHandle,
+ SQLUSMALLINT _nInfo,
+ OUString &_rValue,
+ const css::uno::Reference< css::uno::XInterface >& _xInterface,
+ rtl_TextEncoding _nTextEncoding);
+
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ static void GetInfo(OConnection const * _pConnection,
+ SQLHANDLE _aConnectionHandle,
+ SQLUSMALLINT _nInfo,
+ sal_Int32 &_rValue,
+ const css::uno::Reference< css::uno::XInterface >& _xInterface);
+
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ static void GetInfo(OConnection const * _pConnection,
+ SQLHANDLE _aConnectionHandle,
+ SQLUSMALLINT _nInfo,
+ SQLUSMALLINT &_rValue,
+ const css::uno::Reference< css::uno::XInterface >& _xInterface);
+
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ static void GetInfo(OConnection const * _pConnection,
+ SQLHANDLE _aConnectionHandle,
+ SQLUSMALLINT _nInfo,
+ SQLUINTEGER &_rValue,
+ const css::uno::Reference< css::uno::XInterface >& _xInterface);
+
+ static sal_Int32 MapOdbcType2Jdbc(SQLSMALLINT _nType);
+ static SQLSMALLINT jdbcTypeToOdbc(sal_Int32 jdbcType);
+
+ static DATE_STRUCT DateToOdbcDate(const css::util::Date& x)
+ {
+ DATE_STRUCT aVal;
+ aVal.year = x.Year;
+ aVal.month = x.Month;
+ aVal.day = x.Day;
+ return aVal;
+ }
+ static TIME_STRUCT TimeToOdbcTime(const css::util::Time& x)
+ {
+ TIME_STRUCT aVal;
+ aVal.hour = x.Hours;
+ aVal.minute = x.Minutes;
+ aVal.second = x.Seconds;
+ return aVal;
+ }
+ static TIMESTAMP_STRUCT DateTimeToTimestamp(const css::util::DateTime& x)
+ {
+ TIMESTAMP_STRUCT aVal;
+ aVal.year = x.Year;
+ aVal.month = x.Month;
+ aVal.day = x.Day;
+ aVal.hour = x.Hours;
+ aVal.minute = x.Minutes;
+ aVal.second = x.Seconds;
+ aVal.fraction = x.NanoSeconds;
+ return aVal;
+ }
+ /**
+ getBindTypes set the ODBC type for C
+ @param _bUseWChar true when Unicode should be used
+ @param _bUseOldTimeDate true when the old datetime format should be used
+ @param _nOdbcType the ODBC sql type
+ @param fCType the C type for the ODBC type
+ @param fSqlType the SQL type for the ODBC type
+ */
+ static void getBindTypes(bool _bUseWChar,
+ bool _bUseOldTimeDate,
+ SQLSMALLINT _nOdbcType,
+ SQLSMALLINT& fCType,
+ SQLSMALLINT& fSqlType);
+
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ static OUString getStringValue( OConnection const * _pConnection,
+ SQLHANDLE _aStatementHandle,
+ sal_Int32 columnIndex,
+ SQLSMALLINT _fSqlType,
+ bool &_bWasNull,
+ const css::uno::Reference< css::uno::XInterface >& _xInterface,
+ rtl_TextEncoding _nTextEncoding);
+
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ static css::uno::Sequence<sal_Int8> getBytesValue(const OConnection* _pConnection,
+ SQLHANDLE _aStatementHandle,
+ sal_Int32 columnIndex,
+ SQLSMALLINT _fSqlType,
+ bool &_bWasNull,
+ const css::uno::Reference< css::uno::XInterface >& _xInterface);
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ static void getValue( OConnection const * _pConnection,
+ SQLHANDLE _aStatementHandle,
+ sal_Int32 columnIndex,
+ SQLSMALLINT _nType,
+ bool &_bWasNull,
+ const css::uno::Reference< css::uno::XInterface >& _xInterface,
+ void* _pValue,
+ SQLLEN _nSize);
+
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ static void bindValue( OConnection const * _pConnection,
+ SQLHANDLE _aStatementHandle,
+ sal_Int32 columnIndex,
+ SQLSMALLINT _nType,
+ SQLSMALLINT _nMaxLen,
+ const void* _pValue,
+ void* _pData,
+ SQLLEN *pLen,
+ const css::uno::Reference< css::uno::XInterface >& _xInterface,
+ rtl_TextEncoding _nTextEncoding,
+ bool _bUseOldTimeDate);
+ };
+
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ template <class T> void getValue( const OConnection* _pConnection,
+ SQLHANDLE _aStatementHandle,
+ sal_Int32 columnIndex,
+ SQLSMALLINT _nType,
+ bool &_bWasNull,
+ const css::uno::Reference< css::uno::XInterface >& _xInterface,
+ T& _rValue)
+ {
+ OTools::getValue(_pConnection,_aStatementHandle,columnIndex,_nType,_bWasNull,_xInterface,&_rValue,sizeof _rValue);
+ }
+
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/odbc/odbcbasedllapi.hxx b/connectivity/source/inc/odbc/odbcbasedllapi.hxx
new file mode 100644
index 0000000000..bf7f5a486d
--- /dev/null
+++ b/connectivity/source/inc/odbc/odbcbasedllapi.hxx
@@ -0,0 +1,32 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <sal/types.h>
+
+#if defined OOO_DLLIMPLEMENTATION_ODBCBASE
+#define OOO_DLLPUBLIC_ODBCBASE SAL_DLLPUBLIC_EXPORT
+#else
+#define OOO_DLLPUBLIC_ODBCBASE SAL_DLLPUBLIC_IMPORT
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/propertyids.hxx b/connectivity/source/inc/propertyids.hxx
new file mode 100644
index 0000000000..1a9e3720f9
--- /dev/null
+++ b/connectivity/source/inc/propertyids.hxx
@@ -0,0 +1,109 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+// this define has to be set to split the names into different dll's or so's
+// every dll has his own set of property names
+#include <rtl/ustring.hxx>
+#include <map>
+#include <connectivity/dbtoolsdllapi.hxx>
+
+namespace dbtools
+{
+ class OOO_DLLPUBLIC_DBTOOLS OPropertyMap
+ {
+ std::map<sal_Int32, OUString> m_aPropertyMap;
+ public:
+ OPropertyMap();
+ const OUString& getNameByIndex(sal_Int32 _nIndex) const;
+ };
+}
+
+#define PROPERTY_ID_QUERYTIMEOUT 1
+#define PROPERTY_ID_MAXFIELDSIZE 2
+#define PROPERTY_ID_MAXROWS 3
+#define PROPERTY_ID_CURSORNAME 4
+#define PROPERTY_ID_RESULTSETCONCURRENCY 5
+#define PROPERTY_ID_RESULTSETTYPE 6
+#define PROPERTY_ID_FETCHDIRECTION 7
+#define PROPERTY_ID_FETCHSIZE 8
+#define PROPERTY_ID_ESCAPEPROCESSING 9
+#define PROPERTY_ID_USEBOOKMARKS 10
+// Column
+#define PROPERTY_ID_NAME 11
+#define PROPERTY_ID_TYPE 12
+#define PROPERTY_ID_TYPENAME 13
+#define PROPERTY_ID_PRECISION 14
+#define PROPERTY_ID_SCALE 15
+#define PROPERTY_ID_ISNULLABLE 16
+#define PROPERTY_ID_ISAUTOINCREMENT 17
+#define PROPERTY_ID_ISROWVERSION 18
+#define PROPERTY_ID_DESCRIPTION 19
+#define PROPERTY_ID_DEFAULTVALUE 20
+
+#define PROPERTY_ID_REFERENCEDTABLE 21
+#define PROPERTY_ID_UPDATERULE 22
+#define PROPERTY_ID_DELETERULE 23
+#define PROPERTY_ID_CATALOG 24
+#define PROPERTY_ID_ISUNIQUE 25
+#define PROPERTY_ID_ISPRIMARYKEYINDEX 26
+#define PROPERTY_ID_ISCLUSTERED 27
+#define PROPERTY_ID_ISASCENDING 28
+#define PROPERTY_ID_SCHEMANAME 29
+#define PROPERTY_ID_CATALOGNAME 30
+
+#define PROPERTY_ID_COMMAND 31
+#define PROPERTY_ID_CHECKOPTION 32
+#define PROPERTY_ID_PASSWORD 33
+#define PROPERTY_ID_RELATEDCOLUMN 34
+
+#define PROPERTY_ID_FUNCTION 35
+#define PROPERTY_ID_TABLENAME 36
+#define PROPERTY_ID_REALNAME 37
+#define PROPERTY_ID_DBASEPRECISIONCHANGED 38
+#define PROPERTY_ID_ISCURRENCY 39
+#define PROPERTY_ID_ISBOOKMARKABLE 40
+
+#define PROPERTY_ID_INVALID_INDEX 41
+#define PROPERTY_ID_HY010 43
+#define PROPERTY_ID_LABEL 44
+#define PROPERTY_ID_DELIMITER 45
+#define PROPERTY_ID_FORMATKEY 46
+#define PROPERTY_ID_LOCALE 47
+#define PROPERTY_ID_IM001 48
+
+#define PROPERTY_ID_AUTOINCREMENTCREATION 49
+
+#define PROPERTY_ID_PRIVILEGES 50
+#define PROPERTY_ID_HAVINGCLAUSE 51
+
+#define PROPERTY_ID_ISSIGNED 52
+#define PROPERTY_ID_AGGREGATEFUNCTION 53
+#define PROPERTY_ID_ISSEARCHABLE 54
+
+#define PROPERTY_ID_APPLYFILTER 55
+#define PROPERTY_ID_FILTER 56
+#define PROPERTY_ID_MASTERFIELDS 57
+#define PROPERTY_ID_DETAILFIELDS 58
+#define PROPERTY_ID_FIELDTYPE 59
+#define PROPERTY_ID_VALUE 60
+#define PROPERTY_ID_ACTIVE_CONNECTION 61
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/resource/sharedresources.hxx b/connectivity/source/inc/resource/sharedresources.hxx
new file mode 100644
index 0000000000..0c439cdf24
--- /dev/null
+++ b/connectivity/source/inc/resource/sharedresources.hxx
@@ -0,0 +1,149 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <rtl/ustring.hxx>
+#include <vector>
+#include <connectivity/dbtoolsdllapi.hxx>
+#include <unotools/resmgr.hxx>
+
+namespace connectivity
+{
+
+
+ typedef sal_uInt16 ResourceId;
+
+ /** helper class for accessing resources shared by different libraries
+ in the connectivity module
+ */
+ class OOO_DLLPUBLIC_DBTOOLS SharedResources
+ {
+ public:
+ SharedResources();
+ ~SharedResources();
+
+ /** loads a string from the shared resource file
+ @param pResId
+ the resource ID of the string
+ @return
+ the string from the resource file
+ */
+ OUString
+ getResourceString(
+ TranslateId pResId
+ ) const;
+
+ /** loads a string from the shared resource file, and replaces
+ a given ASCII pattern with a given string
+
+ @param pResId
+ the resource ID of the string to load
+ @param _pAsciiPatternToReplace
+ the ASCII string which is to search in the string. Must not be <NULL/>.
+ @param _rStringToSubstitute
+ the String which should substitute the ASCII pattern.
+
+ @return
+ the string from the resource file, with applied string substitution
+ */
+ OUString
+ getResourceStringWithSubstitution(
+ TranslateId pResId,
+ const char* _pAsciiPatternToReplace,
+ const OUString& _rStringToSubstitute
+ ) const;
+
+ /** loads a string from the shared resource file, and replaces
+ a given ASCII pattern with a given string
+
+ @param pResId
+ the resource ID of the string to load
+ @param _pAsciiPatternToReplace1
+ the ASCII string (1) which is to search in the string. Must not be <NULL/>.
+ @param _rStringToSubstitute1
+ the String which should substitute the ASCII pattern (1)
+ @param _pAsciiPatternToReplace2
+ the ASCII string (2) which is to search in the string. Must not be <NULL/>.
+ @param _rStringToSubstitute2
+ the String which should substitute the ASCII pattern (2)
+
+ @return
+ the string from the resource file, with applied string substitution
+ */
+ OUString
+ getResourceStringWithSubstitution(
+ TranslateId pResId,
+ const char* _pAsciiPatternToReplace1,
+ const OUString& _rStringToSubstitute1,
+ const char* _pAsciiPatternToReplace2,
+ const OUString& _rStringToSubstitute2
+ ) const;
+
+ /** loads a string from the shared resource file, and replaces
+ a given ASCII pattern with a given string
+
+ @param pResId
+ the resource ID of the string to load
+ @param _pAsciiPatternToReplace1
+ the ASCII string (1) which is to search in the string. Must not be <NULL/>.
+ @param _rStringToSubstitute1
+ the String which should substitute the ASCII pattern (1)
+ @param _pAsciiPatternToReplace2
+ the ASCII string (2) which is to search in the string. Must not be <NULL/>.
+ @param _rStringToSubstitute2
+ the String which should substitute the ASCII pattern (2)
+ @param _pAsciiPatternToReplace3
+ the ASCII string (3) which is to search in the string. Must not be <NULL/>.
+ @param _rStringToSubstitute3
+ the String which should substitute the ASCII pattern (3)
+
+ @return
+ the string from the resource file, with applied string substitution
+ */
+ OUString
+ getResourceStringWithSubstitution(
+ TranslateId pResId,
+ const char* _pAsciiPatternToReplace1,
+ const OUString& _rStringToSubstitute1,
+ const char* _pAsciiPatternToReplace2,
+ const OUString& _rStringToSubstitute2,
+ const char* _pAsciiPatternToReplace3,
+ const OUString& _rStringToSubstitute3
+ ) const;
+
+ /** loads a string from the shared resource file, and replaces a given ASCII pattern with a given string
+
+ @param pResId
+ the resource ID of the string to load
+ @param _aStringToSubstitutes
+ A list of substitutions.
+
+ @return
+ the string from the resource file, with applied string substitution
+ */
+ OUString getResourceStringWithSubstitution( TranslateId pResId,
+ const std::vector< std::pair<const char* , OUString > >& _rStringToSubstitutes) const;
+ };
+
+
+} // namespace connectivity
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/writer/WCatalog.hxx b/connectivity/source/inc/writer/WCatalog.hxx
new file mode 100644
index 0000000000..be61dbabd1
--- /dev/null
+++ b/connectivity/source/inc/writer/WCatalog.hxx
@@ -0,0 +1,37 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <file/FCatalog.hxx>
+
+namespace connectivity::writer
+{
+class OWriterConnection;
+class OWriterCatalog : public file::OFileCatalog
+{
+public:
+ void refreshTables() override;
+
+ OWriterCatalog(OWriterConnection* pConnection);
+};
+
+} // namespace connectivity::writer
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/writer/WConnection.hxx b/connectivity/source/inc/writer/WConnection.hxx
new file mode 100644
index 0000000000..5ae8b2818e
--- /dev/null
+++ b/connectivity/source/inc/writer/WConnection.hxx
@@ -0,0 +1,154 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <memory>
+#include <file/FConnection.hxx>
+#include <com/sun/star/frame/XDesktop2.hpp>
+#include <com/sun/star/frame/XTerminateListener.hpp>
+#include <rtl/ref.hxx>
+#include <unotools/closeveto.hxx>
+
+namespace com::sun::star::text
+{
+class XTextDocument;
+}
+namespace utl
+{
+class CloseVeto;
+}
+
+namespace connectivity::writer
+{
+class ODriver;
+class OWriterConnection : public file::OConnection
+{
+ // the text document:
+ css::uno::Reference<css::text::XTextDocument> m_xDoc;
+ OUString m_sPassword;
+ OUString m_aFileName;
+ oslInterlockedCount m_nDocCount = 0;
+
+ class CloseVetoButTerminateListener
+ : public cppu::WeakComponentImplHelper<css::frame::XTerminateListener>
+ {
+ private:
+ /// close listener that vetoes so nobody else disposes m_xDoc
+ std::unique_ptr<utl::CloseVeto> m_pCloseListener;
+ /// but also listen to XDesktop and if app is terminating anyway, dispose m_xDoc while
+ /// its still possible to do so properly
+ css::uno::Reference<css::frame::XDesktop2> m_xDesktop;
+ osl::Mutex m_aMutex;
+
+ public:
+ CloseVetoButTerminateListener()
+ : cppu::WeakComponentImplHelper<css::frame::XTerminateListener>(m_aMutex)
+ {
+ }
+
+ void start(const css::uno::Reference<css::uno::XInterface>& rCloseable,
+ const css::uno::Reference<css::frame::XDesktop2>& rDesktop)
+ {
+ m_xDesktop = rDesktop;
+ m_xDesktop->addTerminateListener(this);
+ m_pCloseListener = std::make_unique<utl::CloseVeto>(rCloseable, true);
+ }
+
+ void stop()
+ {
+ m_pCloseListener.reset();
+ if (!m_xDesktop.is())
+ return;
+ m_xDesktop->removeTerminateListener(this);
+ m_xDesktop.clear();
+ }
+
+ // XTerminateListener
+ void SAL_CALL queryTermination(const css::lang::EventObject& /*rEvent*/) override {}
+
+ void SAL_CALL notifyTermination(const css::lang::EventObject& /*rEvent*/) override
+ {
+ stop();
+ }
+
+ void SAL_CALL disposing() override
+ {
+ stop();
+ cppu::WeakComponentImplHelperBase::disposing();
+ }
+
+ void SAL_CALL disposing(const css::lang::EventObject& rEvent) override
+ {
+ const bool bShutDown = (rEvent.Source == m_xDesktop);
+ if (bShutDown)
+ stop();
+ }
+ };
+
+ rtl::Reference<CloseVetoButTerminateListener> m_xCloseVetoButTerminateListener;
+
+public:
+ OWriterConnection(ODriver* _pDriver);
+ ~OWriterConnection() override;
+
+ void construct(const OUString& rURL,
+ const css::uno::Sequence<css::beans::PropertyValue>& rInfo) override;
+
+ // XServiceInfo
+ DECLARE_SERVICE_INFO();
+
+ // OComponentHelper
+ void SAL_CALL disposing() override;
+
+ // XConnection
+ css::uno::Reference<css::sdbc::XDatabaseMetaData> SAL_CALL getMetaData() override;
+ css::uno::Reference<css::sdbcx::XTablesSupplier> createCatalog() override;
+ css::uno::Reference<css::sdbc::XStatement> SAL_CALL createStatement() override;
+ css::uno::Reference<css::sdbc::XPreparedStatement>
+ SAL_CALL prepareStatement(const OUString& sql) override;
+ css::uno::Reference<css::sdbc::XPreparedStatement>
+ SAL_CALL prepareCall(const OUString& sql) override;
+
+ // no interface methods
+ css::uno::Reference<css::text::XTextDocument> const& acquireDoc();
+ void releaseDoc();
+
+ class ODocHolder
+ {
+ OWriterConnection* m_pConnection;
+ css::uno::Reference<css::text::XTextDocument> m_xDoc;
+
+ public:
+ ODocHolder(OWriterConnection* _pConnection)
+ : m_pConnection(_pConnection)
+ {
+ m_xDoc = m_pConnection->acquireDoc();
+ }
+ ~ODocHolder()
+ {
+ m_xDoc.clear();
+ m_pConnection->releaseDoc();
+ }
+ const css::uno::Reference<css::text::XTextDocument>& getDoc() const { return m_xDoc; }
+ };
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/writer/WDatabaseMetaData.hxx b/connectivity/source/inc/writer/WDatabaseMetaData.hxx
new file mode 100644
index 0000000000..b464be11c4
--- /dev/null
+++ b/connectivity/source/inc/writer/WDatabaseMetaData.hxx
@@ -0,0 +1,43 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <component/CDatabaseMetaData.hxx>
+
+namespace connectivity::writer
+{
+class OWriterDatabaseMetaData : public component::OComponentDatabaseMetaData
+{
+ OUString SAL_CALL getURL() override;
+ css::uno::Reference<css::sdbc::XResultSet>
+ SAL_CALL getTables(const css::uno::Any& catalog, const OUString& schemaPattern,
+ const OUString& tableNamePattern,
+ const css::uno::Sequence<OUString>& types) override;
+
+protected:
+ ~OWriterDatabaseMetaData() override;
+
+public:
+ OWriterDatabaseMetaData(file::OConnection* pConnection);
+};
+
+} // namespace connectivity::writer
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/writer/WDriver.hxx b/connectivity/source/inc/writer/WDriver.hxx
new file mode 100644
index 0000000000..b43168eac9
--- /dev/null
+++ b/connectivity/source/inc/writer/WDriver.hxx
@@ -0,0 +1,52 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <file/FDriver.hxx>
+
+namespace com::sun::star::lang
+{
+class XMultiServiceFactory;
+}
+
+namespace connectivity::writer
+{
+class ODriver : public file::OFileDriver
+{
+public:
+ ODriver(const css::uno::Reference<css::uno::XComponentContext>& _rxContext)
+ : file::OFileDriver(_rxContext)
+ {
+ }
+
+ /// @throws css::uno::RuntimeException
+ OUString SAL_CALL getImplementationName() override;
+
+ // XDriver
+ css::uno::Reference<css::sdbc::XConnection>
+ SAL_CALL connect(const OUString& url,
+ const css::uno::Sequence<css::beans::PropertyValue>& info) override;
+ sal_Bool SAL_CALL acceptsURL(const OUString& url) override;
+ css::uno::Sequence<css::sdbc::DriverPropertyInfo> SAL_CALL getPropertyInfo(
+ const OUString& url, const css::uno::Sequence<css::beans::PropertyValue>& info) override;
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/writer/WTable.hxx b/connectivity/source/inc/writer/WTable.hxx
new file mode 100644
index 0000000000..46ee5412e0
--- /dev/null
+++ b/connectivity/source/inc/writer/WTable.hxx
@@ -0,0 +1,62 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <component/CTable.hxx>
+
+namespace com::sun::star::text
+{
+class XTextTable;
+}
+namespace com::sun::star::util
+{
+class XNumberFormats;
+}
+
+namespace connectivity::writer
+{
+using OWriterTable_BASE = component::OComponentTable;
+class OWriterConnection;
+
+class OWriterTable : public OWriterTable_BASE
+{
+private:
+ css::uno::Reference<css::text::XTextTable> m_xTable;
+ OWriterConnection* m_pWriterConnection;
+ sal_Int32 m_nStartCol = 0;
+ sal_Int32 m_nDataCols = 0;
+ bool m_bHasHeaders = false;
+
+ void fillColumns();
+
+public:
+ OWriterTable(sdbcx::OCollection* _pTables, OWriterConnection* _pConnection,
+ const OUString& Name, const OUString& Type);
+
+ bool fetchRow(OValueRefRow& _rRow, const OSQLColumns& _rCols, bool bRetrieveData) override;
+
+ void SAL_CALL disposing() override;
+
+ void construct() override;
+};
+
+} // namespace connectivity::writer
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/writer/WTables.hxx b/connectivity/source/inc/writer/WTables.hxx
new file mode 100644
index 0000000000..df39cc1c22
--- /dev/null
+++ b/connectivity/source/inc/writer/WTables.hxx
@@ -0,0 +1,43 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <file/FTables.hxx>
+
+namespace connectivity::writer
+{
+using OWriterTables_BASE = file::OTables;
+
+class OWriterTables : public OWriterTables_BASE
+{
+protected:
+ sdbcx::ObjectType createObject(const OUString& rName) override;
+
+public:
+ OWriterTables(const css::uno::Reference<css::sdbc::XDatabaseMetaData>& _rMetaData,
+ ::cppu::OWeakObject& _rParent, ::osl::Mutex& _rMutex,
+ const ::std::vector<OUString>& _rVector)
+ : OWriterTables_BASE(_rMetaData, _rParent, _rMutex, _rVector)
+ {
+ }
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/manager/mdrivermanager.cxx b/connectivity/source/manager/mdrivermanager.cxx
new file mode 100644
index 0000000000..5c283be5d8
--- /dev/null
+++ b/connectivity/source/manager/mdrivermanager.cxx
@@ -0,0 +1,656 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <config_fuzzers.h>
+
+#include "mdrivermanager.hxx"
+#include <com/sun/star/configuration/theDefaultProvider.hpp>
+#include <com/sun/star/sdbc/XDriver.hpp>
+#include <com/sun/star/container/XContentEnumerationAccess.hpp>
+#include <com/sun/star/container/ElementExistException.hpp>
+#include <com/sun/star/beans/NamedValue.hpp>
+#include <com/sun/star/logging/LogLevel.hpp>
+
+#include <comphelper/diagnose_ex.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <cppuhelper/weak.hxx>
+#include <osl/diagnose.h>
+
+#include <algorithm>
+#include <iterator>
+#include <utility>
+#include <vector>
+
+namespace drivermanager
+{
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::logging;
+using namespace ::osl;
+
+constexpr OUStringLiteral SERVICE_SDBC_DRIVER = u"com.sun.star.sdbc.Driver";
+
+class ODriverEnumeration : public ::cppu::WeakImplHelper< XEnumeration >
+{
+ friend class OSDBCDriverManager;
+
+ typedef std::vector< Reference< XDriver > > DriverArray;
+ DriverArray m_aDrivers;
+ DriverArray::const_iterator m_aPos;
+ // order matters!
+
+protected:
+ virtual ~ODriverEnumeration() override;
+public:
+ explicit ODriverEnumeration(DriverArray&& _rDriverSequence);
+
+// XEnumeration
+ virtual sal_Bool SAL_CALL hasMoreElements( ) override;
+ virtual Any SAL_CALL nextElement( ) override;
+};
+
+
+ODriverEnumeration::ODriverEnumeration(DriverArray&& _rDriverSequence)
+ :m_aDrivers( std::move(_rDriverSequence) )
+ ,m_aPos( m_aDrivers.begin() )
+{
+}
+
+
+ODriverEnumeration::~ODriverEnumeration()
+{
+}
+
+
+sal_Bool SAL_CALL ODriverEnumeration::hasMoreElements( )
+{
+ return m_aPos != m_aDrivers.end();
+}
+
+
+Any SAL_CALL ODriverEnumeration::nextElement( )
+{
+ if ( !hasMoreElements() )
+ throw NoSuchElementException();
+
+ return Any( *m_aPos++ );
+}
+
+namespace
+{
+ /// an STL functor which ensures that a SdbcDriver described by a DriverAccess is loaded
+ struct EnsureDriver
+ {
+ explicit EnsureDriver( const Reference< XComponentContext > &rxContext )
+ : mxContext( rxContext ) {}
+
+ const DriverAccess& operator()( const DriverAccess& _rDescriptor ) const
+ {
+ // we did not load this driver, yet
+ if (_rDescriptor.xDriver.is())
+ return _rDescriptor;
+
+ // we have a factory for it
+ if (_rDescriptor.xComponentFactory.is())
+ {
+ DriverAccess& rDesc = const_cast<DriverAccess&>(_rDescriptor);
+ try
+ {
+ //load driver
+ rDesc.xDriver.set(
+ rDesc.xComponentFactory->createInstanceWithContext(mxContext), css::uno::UNO_QUERY);
+ }
+ catch (const Exception&)
+ {
+ //failure, abandon driver
+ rDesc.xComponentFactory.clear();
+ }
+ }
+ return _rDescriptor;
+ }
+
+ private:
+ Reference< XComponentContext > mxContext;
+ };
+
+ /// an STL functor which extracts a SdbcDriver from a DriverAccess
+ struct ExtractDriverFromAccess
+ {
+ const Reference<XDriver>& operator()( const DriverAccess& _rAccess ) const
+ {
+ return _rAccess.xDriver;
+ }
+ };
+
+ struct ExtractDriverFromCollectionElement
+ {
+ const Reference<XDriver>& operator()( const DriverCollection::value_type& _rElement ) const
+ {
+ return _rElement.second;
+ }
+ };
+
+ // predicate for checking whether or not a driver accepts a given URL
+ bool AcceptsURL( const OUString& _rURL, const Reference<XDriver>& _rDriver )
+ {
+ // ask the driver
+ return _rDriver.is() && _rDriver->acceptsURL( _rURL );
+ }
+
+#if !ENABLE_FUZZERS
+ sal_Int32 lcl_getDriverPrecedence( const Reference<XComponentContext>& _rContext, Sequence< OUString >& _rPrecedence )
+ {
+ _rPrecedence.realloc( 0 );
+ try
+ {
+ // create a configuration provider
+ Reference< XMultiServiceFactory > xConfigurationProvider(
+ css::configuration::theDefaultProvider::get( _rContext ) );
+
+ // one argument for creating the node access: the path to the configuration node
+ Sequence< Any > aCreationArgs{ Any(NamedValue(
+ "nodepath", Any( OUString("org.openoffice.Office.DataAccess/DriverManager") ) )) };
+
+ // create the node access
+ Reference< XNameAccess > xDriverManagerNode(
+ xConfigurationProvider->createInstanceWithArguments("com.sun.star.configuration.ConfigurationAccess", aCreationArgs),
+ UNO_QUERY);
+
+ OSL_ENSURE(xDriverManagerNode.is(), "lcl_getDriverPrecedence: could not open my configuration node!");
+ if (xDriverManagerNode.is())
+ {
+ // obtain the preference list
+ Any aPreferences = xDriverManagerNode->getByName("DriverPrecedence");
+ bool bSuccess = aPreferences >>= _rPrecedence;
+ OSL_ENSURE(bSuccess || !aPreferences.hasValue(), "lcl_getDriverPrecedence: invalid value for the preferences node (no string sequence but not NULL)!");
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("connectivity.manager");
+ }
+
+ return _rPrecedence.getLength();
+ }
+#endif
+
+ /// an STL algorithm compatible predicate comparing two DriverAccess instances by their implementation names
+ struct CompareDriverAccessByName
+ {
+
+ bool operator()( const DriverAccess& lhs, const DriverAccess& rhs )
+ {
+ return lhs.sImplementationName < rhs.sImplementationName;
+ }
+ };
+
+ /// and an STL algorithm compatible predicate comparing the impl name of a DriverAccess to a string
+ struct EqualDriverAccessToName
+ {
+ OUString m_sImplName;
+ explicit EqualDriverAccessToName(OUString _sImplName) : m_sImplName(std::move(_sImplName)){}
+
+ bool operator()( const DriverAccess& lhs)
+ {
+ return lhs.sImplementationName == m_sImplName;
+ }
+ };
+}
+
+OSDBCDriverManager::OSDBCDriverManager( const Reference< XComponentContext >& _rxContext )
+ :OSDBCDriverManager_Base(m_aMutex)
+ ,m_xContext( _rxContext )
+ ,m_aEventLogger( _rxContext, "org.openoffice.logging.sdbc.DriverManager" )
+ ,m_aDriverConfig(m_xContext)
+ ,m_nLoginTimeout(0)
+{
+ // bootstrap all objects supporting the .sdb.Driver service
+ bootstrapDrivers();
+
+ // initialize the drivers order
+ initializeDriverPrecedence();
+}
+
+
+OSDBCDriverManager::~OSDBCDriverManager()
+{
+}
+
+void OSDBCDriverManager::bootstrapDrivers()
+{
+ Reference< XContentEnumerationAccess > xEnumAccess( m_xContext->getServiceManager(), UNO_QUERY );
+ Reference< XEnumeration > xEnumDrivers;
+ if (xEnumAccess.is())
+ xEnumDrivers = xEnumAccess->createContentEnumeration(SERVICE_SDBC_DRIVER);
+
+ OSL_ENSURE( xEnumDrivers.is(), "OSDBCDriverManager::bootstrapDrivers: no enumeration for the drivers available!" );
+ if (!xEnumDrivers.is())
+ return;
+
+ Reference< XSingleComponentFactory > xFactory;
+ Reference< XServiceInfo > xSI;
+ while (xEnumDrivers->hasMoreElements())
+ {
+ xFactory.set(xEnumDrivers->nextElement(), css::uno::UNO_QUERY);
+ OSL_ENSURE( xFactory.is(), "OSDBCDriverManager::bootstrapDrivers: no factory extracted" );
+
+ if ( xFactory.is() )
+ {
+ // we got a factory for the driver
+ DriverAccess aDriverDescriptor;
+ bool bValidDescriptor = false;
+
+ // can it tell us something about the implementation name?
+ xSI.set(xFactory, css::uno::UNO_QUERY);
+ if ( xSI.is() )
+ { // yes -> no need to load the driver immediately (load it later when needed)
+ aDriverDescriptor.sImplementationName = xSI->getImplementationName();
+ aDriverDescriptor.xComponentFactory = xFactory;
+ bValidDescriptor = true;
+
+ m_aEventLogger.log( LogLevel::CONFIG,
+ "found SDBC driver $1$, no need to load it",
+ aDriverDescriptor.sImplementationName
+ );
+ }
+ else
+ {
+ // no -> create the driver
+ Reference< XDriver > xDriver( xFactory->createInstanceWithContext( m_xContext ), UNO_QUERY );
+ OSL_ENSURE( xDriver.is(), "OSDBCDriverManager::bootstrapDrivers: a driver which is no driver?!" );
+
+ if ( xDriver.is() )
+ {
+ aDriverDescriptor.xDriver = xDriver;
+ // and obtain its implementation name
+ xSI.set(xDriver, css::uno::UNO_QUERY);
+ OSL_ENSURE( xSI.is(), "OSDBCDriverManager::bootstrapDrivers: a driver without service info?" );
+ if ( xSI.is() )
+ {
+ aDriverDescriptor.sImplementationName = xSI->getImplementationName();
+ bValidDescriptor = true;
+
+ m_aEventLogger.log( LogLevel::CONFIG,
+ "found SDBC driver $1$, needed to load it",
+ aDriverDescriptor.sImplementationName
+ );
+ }
+ }
+ }
+
+ if ( bValidDescriptor )
+ {
+ m_aDriversBS.push_back( aDriverDescriptor );
+ }
+ }
+ }
+}
+
+
+void OSDBCDriverManager::initializeDriverPrecedence()
+{
+#if !ENABLE_FUZZERS
+ if ( m_aDriversBS.empty() )
+ // nothing to do
+ return;
+
+ try
+ {
+ // get the precedence of the drivers from the configuration
+ Sequence< OUString > aDriverOrder;
+ if ( 0 == lcl_getDriverPrecedence( m_xContext, aDriverOrder ) )
+ // nothing to do
+ return;
+
+ // aDriverOrder now is the list of driver implementation names in the order they should be used
+
+ if ( m_aEventLogger.isLoggable( LogLevel::CONFIG ) )
+ {
+ sal_Int32 nOrderedCount = aDriverOrder.getLength();
+ for ( sal_Int32 i=0; i<nOrderedCount; ++i )
+ m_aEventLogger.log( LogLevel::CONFIG,
+ "configuration's driver order: driver $1$ of $2$: $3$",
+ static_cast<sal_Int32>(i + 1), nOrderedCount, aDriverOrder[i]
+ );
+ }
+
+ // sort our bootstrapped drivers
+ std::sort( m_aDriversBS.begin(), m_aDriversBS.end(), CompareDriverAccessByName() );
+
+ // the first driver for which there is no preference
+ DriverAccessArray::iterator aNoPrefDriversStart = m_aDriversBS.begin();
+ // at the moment this is the first of all drivers we know
+
+ // loop through the names in the precedence order
+ for ( const OUString& rDriverOrder : std::as_const(aDriverOrder) )
+ {
+ if (aNoPrefDriversStart == m_aDriversBS.end())
+ break;
+
+ DriverAccess driver_order;
+ driver_order.sImplementationName = rDriverOrder;
+
+ // look for the impl name in the DriverAccess array
+ std::pair< DriverAccessArray::iterator, DriverAccessArray::iterator > aPos =
+ std::equal_range( aNoPrefDriversStart, m_aDriversBS.end(), driver_order, CompareDriverAccessByName() );
+
+ if ( aPos.first != aPos.second )
+ { // we have a DriverAccess with this impl name
+
+ OSL_ENSURE( std::distance( aPos.first, aPos.second ) == 1,
+ "OSDBCDriverManager::initializeDriverPrecedence: more than one driver with this impl name? How this?" );
+ // move the DriverAccess pointed to by aPos.first to the position pointed to by aNoPrefDriversStart
+
+ if ( aPos.first != aNoPrefDriversStart )
+ { // if this does not hold, the DriverAccess already has the correct position
+
+ // rotate the range [aNoPrefDriversStart, aPos.second) right 1 element
+ std::rotate( aNoPrefDriversStart, aPos.second - 1, aPos.second );
+ }
+
+ // next round we start searching and pos right
+ ++aNoPrefDriversStart;
+ }
+ }
+ }
+ catch (Exception&)
+ {
+ TOOLS_WARN_EXCEPTION( "connectivity.hsqldb", "OSDBCDriverManager::initializeDriverPrecedence: caught an exception while sorting the drivers!");
+ }
+#endif
+}
+
+
+Reference< XConnection > SAL_CALL OSDBCDriverManager::getConnection( const OUString& _rURL )
+{
+ MutexGuard aGuard(m_aMutex);
+
+ m_aEventLogger.log( LogLevel::INFO,
+ "connection requested for URL $1$",
+ _rURL
+ );
+
+ Reference< XConnection > xConnection;
+ Reference< XDriver > xDriver = implGetDriverForURL(_rURL);
+ if (xDriver.is())
+ {
+ // TODO : handle the login timeout
+ xConnection = xDriver->connect(_rURL, Sequence< PropertyValue >());
+ // may throw an exception
+ m_aEventLogger.log( LogLevel::INFO,
+ "connection retrieved for URL $1$",
+ _rURL
+ );
+ }
+
+ return xConnection;
+}
+
+
+Reference< XConnection > SAL_CALL OSDBCDriverManager::getConnectionWithInfo( const OUString& _rURL, const Sequence< PropertyValue >& _rInfo )
+{
+ MutexGuard aGuard(m_aMutex);
+
+ m_aEventLogger.log( LogLevel::INFO,
+ "connection with info requested for URL $1$",
+ _rURL
+ );
+
+ Reference< XConnection > xConnection;
+ Reference< XDriver > xDriver = implGetDriverForURL(_rURL);
+ if (xDriver.is())
+ {
+ // TODO : handle the login timeout
+ xConnection = xDriver->connect(_rURL, _rInfo);
+ // may throw an exception
+ m_aEventLogger.log( LogLevel::INFO,
+ "connection with info retrieved for URL $1$",
+ _rURL
+ );
+ }
+
+ return xConnection;
+}
+
+
+void SAL_CALL OSDBCDriverManager::setLoginTimeout( sal_Int32 seconds )
+{
+ MutexGuard aGuard(m_aMutex);
+ m_nLoginTimeout = seconds;
+}
+
+
+sal_Int32 SAL_CALL OSDBCDriverManager::getLoginTimeout( )
+{
+ MutexGuard aGuard(m_aMutex);
+ return m_nLoginTimeout;
+}
+
+
+Reference< XEnumeration > SAL_CALL OSDBCDriverManager::createEnumeration( )
+{
+ MutexGuard aGuard(m_aMutex);
+
+ ODriverEnumeration::DriverArray aDrivers;
+
+ // ensure that all our bootstrapped drivers are instantiated
+ std::for_each( m_aDriversBS.begin(), m_aDriversBS.end(), EnsureDriver( m_xContext ) );
+
+ // copy the bootstrapped drivers
+ std::transform(
+ m_aDriversBS.begin(), // "copy from" start
+ m_aDriversBS.end(), // "copy from" end
+ std::back_inserter( aDrivers ), // insert into
+ ExtractDriverFromAccess() // transformation to apply (extract a driver from a driver access)
+ );
+
+ // append the runtime drivers
+ std::transform(
+ m_aDriversRT.begin(), // "copy from" start
+ m_aDriversRT.end(), // "copy from" end
+ std::back_inserter( aDrivers ), // insert into
+ ExtractDriverFromCollectionElement() // transformation to apply (extract a driver from a driver access)
+ );
+
+ return new ODriverEnumeration( std::move(aDrivers) );
+}
+
+
+css::uno::Type SAL_CALL OSDBCDriverManager::getElementType( )
+{
+ return cppu::UnoType<XDriver>::get();
+}
+
+
+sal_Bool SAL_CALL OSDBCDriverManager::hasElements( )
+{
+ MutexGuard aGuard(m_aMutex);
+ return !(m_aDriversBS.empty() && m_aDriversRT.empty());
+}
+
+
+OUString SAL_CALL OSDBCDriverManager::getImplementationName( )
+{
+ return "com.sun.star.comp.sdbc.OSDBCDriverManager";
+}
+
+sal_Bool SAL_CALL OSDBCDriverManager::supportsService( const OUString& _rServiceName )
+{
+ return cppu::supportsService(this, _rServiceName);
+}
+
+
+Sequence< OUString > SAL_CALL OSDBCDriverManager::getSupportedServiceNames( )
+{
+ return { "com.sun.star.sdbc.DriverManager" };
+}
+
+
+Reference< XInterface > SAL_CALL OSDBCDriverManager::getRegisteredObject( const OUString& _rName )
+{
+ MutexGuard aGuard(m_aMutex);
+ DriverCollection::const_iterator aSearch = m_aDriversRT.find(_rName);
+ if (aSearch == m_aDriversRT.end())
+ throw NoSuchElementException();
+
+ return aSearch->second;
+}
+
+
+void SAL_CALL OSDBCDriverManager::registerObject( const OUString& _rName, const Reference< XInterface >& _rxObject )
+{
+ MutexGuard aGuard(m_aMutex);
+
+ m_aEventLogger.log( LogLevel::INFO,
+ "attempt to register new driver for name $1$",
+ _rName
+ );
+
+ DriverCollection::const_iterator aSearch = m_aDriversRT.find(_rName);
+ if (aSearch != m_aDriversRT.end())
+ throw ElementExistException();
+ Reference< XDriver > xNewDriver(_rxObject, UNO_QUERY);
+ if (!xNewDriver.is())
+ throw IllegalArgumentException();
+
+ m_aDriversRT.emplace(_rName, xNewDriver);
+
+ m_aEventLogger.log( LogLevel::INFO,
+ "new driver registered for name $1$",
+ _rName
+ );
+}
+
+
+void SAL_CALL OSDBCDriverManager::revokeObject( const OUString& _rName )
+{
+ MutexGuard aGuard(m_aMutex);
+
+ m_aEventLogger.log( LogLevel::INFO,
+ "attempt to revoke driver for name $1$",
+ _rName
+ );
+
+ DriverCollection::iterator aSearch = m_aDriversRT.find(_rName);
+ if (aSearch == m_aDriversRT.end())
+ throw NoSuchElementException();
+
+ m_aDriversRT.erase(aSearch); // we already have the iterator so we could use it
+
+ m_aEventLogger.log( LogLevel::INFO,
+ "driver revoked for name $1$",
+ _rName
+ );
+}
+
+
+Reference< XDriver > SAL_CALL OSDBCDriverManager::getDriverByURL( const OUString& _rURL )
+{
+ m_aEventLogger.log( LogLevel::INFO,
+ "driver requested for URL $1$",
+ _rURL
+ );
+
+ Reference< XDriver > xDriver( implGetDriverForURL( _rURL ) );
+
+ if ( xDriver.is() )
+ m_aEventLogger.log( LogLevel::INFO,
+ "driver obtained for URL $1$",
+ _rURL
+ );
+
+ return xDriver;
+}
+
+
+Reference< XDriver > OSDBCDriverManager::implGetDriverForURL(const OUString& _rURL)
+{
+ Reference< XDriver > xReturn;
+
+ {
+ const OUString sDriverFactoryName = m_aDriverConfig.getDriverFactoryName(_rURL);
+
+ EqualDriverAccessToName aEqual(sDriverFactoryName);
+ DriverAccessArray::const_iterator aFind = std::find_if(m_aDriversBS.begin(),m_aDriversBS.end(),aEqual);
+ if ( aFind == m_aDriversBS.end() )
+ {
+ // search all bootstrapped drivers
+ aFind = std::find_if(
+ m_aDriversBS.begin(), // begin of search range
+ m_aDriversBS.end(), // end of search range
+ [&_rURL, this] (const DriverAccessArray::value_type& driverAccess) {
+ // extract the driver from the access, then ask the resulting driver for acceptance
+#if defined __GNUC__ && !defined __clang__ && __GNUC__ == 13
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wdangling-reference"
+#endif
+ const DriverAccess& ensuredAccess = EnsureDriver(m_xContext)(driverAccess);
+#if defined __GNUC__ && !defined __clang__ && __GNUC__ == 13
+#pragma GCC diagnostic pop
+#endif
+ const Reference<XDriver> driver = ExtractDriverFromAccess()(ensuredAccess);
+ return AcceptsURL(_rURL, driver);
+ });
+ } // if ( m_aDriversBS.find(sDriverFactoryName ) == m_aDriversBS.end() )
+ else
+ {
+ EnsureDriver aEnsure( m_xContext );
+ aEnsure(*aFind);
+ }
+
+ // found something?
+ if ( m_aDriversBS.end() != aFind && aFind->xDriver.is() && aFind->xDriver->acceptsURL(_rURL) )
+ xReturn = aFind->xDriver;
+ }
+
+ if ( !xReturn.is() )
+ {
+ // no -> search the runtime drivers
+ DriverCollection::const_iterator aPos = std::find_if(
+ m_aDriversRT.begin(), // begin of search range
+ m_aDriversRT.end(), // end of search range
+ [&_rURL] (const DriverCollection::value_type& element) {
+ // extract the driver from the collection element, then ask the resulting driver for acceptance
+ const Reference<XDriver> driver = ExtractDriverFromCollectionElement()(element);
+ return AcceptsURL(_rURL, driver);
+ });
+
+ if ( m_aDriversRT.end() != aPos )
+ xReturn = aPos->second;
+ }
+
+ return xReturn;
+}
+
+} // namespace drivermanager
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+connectivity_OSDBCDriverManager_get_implementation(
+ css::uno::XComponentContext* context , css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new drivermanager::OSDBCDriverManager(context));
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/manager/mdrivermanager.hxx b/connectivity/source/manager/mdrivermanager.hxx
new file mode 100644
index 0000000000..239116f1cc
--- /dev/null
+++ b/connectivity/source/manager/mdrivermanager.hxx
@@ -0,0 +1,121 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <map>
+#include <vector>
+
+#include <com/sun/star/sdbc/XDriverManager2.hpp>
+#include <com/sun/star/uno/XNamingService.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/lang/XSingleComponentFactory.hpp>
+
+#include <cppuhelper/basemutex.hxx>
+#include <cppuhelper/compbase.hxx>
+#include <comphelper/logging.hxx>
+#include <connectivity/DriversConfig.hxx>
+
+namespace drivermanager
+{
+
+ typedef std::map< OUString, css::uno::Reference< css::sdbc::XDriver > > DriverCollection;
+
+ struct DriverAccess
+ {
+ OUString sImplementationName; /// the implementation name of the driver
+ css::uno::Reference< css::sdbc::XDriver > xDriver; /// the driver itself
+ css::uno::Reference< css::lang::XSingleComponentFactory > xComponentFactory; /// the factory to create the driver component (if not already done so)
+ };
+
+
+ // OSDBCDriverManager - the one-instance service for managing SDBC drivers
+
+ typedef ::cppu::WeakComponentImplHelper< css::sdbc::XDriverManager2
+ , css::lang::XServiceInfo
+ , css::uno::XNamingService
+ > OSDBCDriverManager_Base;
+
+ class OSDBCDriverManager final : public cppu::BaseMutex, public OSDBCDriverManager_Base
+ {
+ friend class ODriverEnumeration;
+
+ css::uno::Reference<css::uno::XComponentContext> m_xContext;
+ ::comphelper::EventLogger m_aEventLogger;
+
+ typedef std::vector<DriverAccess> DriverAccessArray;
+ DriverAccessArray m_aDriversBS;
+
+ // for drivers registered at runtime (not bootstrapped) we don't require an XServiceInfo interface,
+ // so we have to remember their impl-name in another way
+ typedef std::map< OUString, css::uno::Reference< css::sdbc::XDriver > > DriverCollection;
+ DriverCollection m_aDriversRT;
+
+ ::connectivity::DriversConfig m_aDriverConfig;
+ sal_Int32 m_nLoginTimeout;
+
+ public:
+
+ explicit OSDBCDriverManager(
+ const css::uno::Reference< css::uno::XComponentContext >& _rxContext );
+ virtual ~OSDBCDriverManager() override;
+
+ // XDriverManager
+ virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL getConnection( const OUString& url ) override;
+ virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL getConnectionWithInfo( const OUString& url, const css::uno::Sequence< css::beans::PropertyValue >& info ) override;
+ virtual void SAL_CALL setLoginTimeout( sal_Int32 seconds ) override;
+ virtual sal_Int32 SAL_CALL getLoginTimeout( ) override;
+
+ // XDriverAccess
+ virtual css::uno::Reference< css::sdbc::XDriver > SAL_CALL getDriverByURL( const OUString& url ) override;
+
+ // XEnumerationAccess
+ virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL createEnumeration( ) override;
+
+ // XElementAccess
+ virtual css::uno::Type SAL_CALL getElementType( ) override;
+ virtual sal_Bool SAL_CALL hasElements( ) override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+ // XNamingService
+ virtual css::uno::Reference< css::uno::XInterface > SAL_CALL getRegisteredObject( const OUString& Name ) override;
+ virtual void SAL_CALL registerObject( const OUString& Name, const css::uno::Reference< css::uno::XInterface >& Object ) override;
+ virtual void SAL_CALL revokeObject( const OUString& Name ) override;
+
+ private:
+ css::uno::Reference< css::sdbc::XDriver > implGetDriverForURL(const OUString& _rURL);
+
+ /** retrieve the driver order preferences from the configuration and
+ sort m_aDriversBS accordingly.
+ */
+ void initializeDriverPrecedence();
+
+ void bootstrapDrivers();
+ };
+
+} // namespace drivermanager
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/manager/sdbc2.component b/connectivity/source/manager/sdbc2.component
new file mode 100644
index 0000000000..b9433256aa
--- /dev/null
+++ b/connectivity/source/manager/sdbc2.component
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ -->
+
+<component loader="com.sun.star.loader.SharedLibrary" environment="@CPPU_ENV@"
+ xmlns="http://openoffice.org/2010/uno-components">
+ <implementation name="com.sun.star.comp.sdbc.OSDBCDriverManager"
+ constructor="connectivity_OSDBCDriverManager_get_implementation" single-instance="true">
+ <service name="com.sun.star.sdbc.DriverManager"/>
+ </implementation>
+</component>
diff --git a/connectivity/source/parse/PColumn.cxx b/connectivity/source/parse/PColumn.cxx
new file mode 100644
index 0000000000..5ada4136cc
--- /dev/null
+++ b/connectivity/source/parse/PColumn.cxx
@@ -0,0 +1,271 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <connectivity/PColumn.hxx>
+#include <TConnection.hxx>
+
+#include <comphelper/types.hxx>
+
+#include <com/sun/star/sdbc/XResultSetMetaData.hpp>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+
+using namespace ::comphelper;
+using namespace connectivity;
+using namespace dbtools;
+using namespace connectivity::parse;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::container;
+
+
+OParseColumn::OParseColumn(const Reference<XPropertySet>& _xColumn, bool _bCase)
+ : connectivity::sdbcx::OColumn( getString(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME)))
+ , getString(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPENAME)))
+ , getString(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DEFAULTVALUE)))
+ , getString(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DESCRIPTION)))
+ , getINT32(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISNULLABLE)))
+ , getINT32(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PRECISION)))
+ , getINT32(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCALE)))
+ , getINT32(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE)))
+ , getBOOL(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISAUTOINCREMENT)))
+ , false
+ , getBOOL(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISCURRENCY)))
+ , _bCase
+ , getString(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_CATALOGNAME)))
+ , getString(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCHEMANAME)))
+ , getString(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TABLENAME)))
+ )
+ , m_bFunction(false)
+ , m_bDbasePrecisionChanged(false)
+ , m_bAggregateFunction(false)
+ , m_bIsSearchable( true )
+{
+ construct();
+}
+
+
+OParseColumn::OParseColumn( const OUString& Name,
+ const OUString& TypeName,
+ const OUString& DefaultValue,
+ const OUString& Description,
+ sal_Int32 IsNullable,
+ sal_Int32 Precision,
+ sal_Int32 Scale,
+ sal_Int32 Type,
+ bool IsAutoIncrement,
+ bool IsCurrency,
+ bool _bCase,
+ const OUString& CatalogName,
+ const OUString& SchemaName,
+ const OUString& TableName
+ ) : connectivity::sdbcx::OColumn(Name,
+ TypeName,
+ DefaultValue,
+ Description,
+ IsNullable,
+ Precision,
+ Scale,
+ Type,
+ IsAutoIncrement,
+ false,
+ IsCurrency,
+ _bCase,
+ CatalogName,
+ SchemaName,
+ TableName)
+ , m_bFunction(false)
+ , m_bDbasePrecisionChanged(false)
+ , m_bAggregateFunction(false)
+ , m_bIsSearchable( true )
+{
+ construct();
+}
+
+
+::rtl::Reference< OSQLColumns > OParseColumn::createColumnsForResultSet( const Reference< XResultSetMetaData >& _rxResMetaData,
+ const Reference< XDatabaseMetaData >& _rxDBMetaData,const Reference< XNameAccess>& i_xQueryColumns )
+{
+ sal_Int32 nColumnCount = _rxResMetaData->getColumnCount();
+ ::rtl::Reference aReturn( new OSQLColumns ); aReturn->reserve( nColumnCount );
+
+ StringMap aColumnMap;
+ for ( sal_Int32 i = 1; i <= nColumnCount; ++i )
+ {
+ rtl::Reference<OParseColumn> pColumn = createColumnForResultSet( _rxResMetaData, _rxDBMetaData, i,aColumnMap );
+ aReturn->push_back( pColumn );
+ if ( i_xQueryColumns.is() && i_xQueryColumns->hasByName(pColumn->getRealName()) )
+ {
+ Reference<XPropertySet> xColumn(i_xQueryColumns->getByName(pColumn->getRealName()),UNO_QUERY_THROW);
+ OUString sLabel;
+ xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_LABEL)) >>= sLabel;
+ if ( !sLabel.isEmpty() )
+ pColumn->setLabel(sLabel);
+ }
+ }
+
+ return aReturn;
+}
+
+
+rtl::Reference<OParseColumn> OParseColumn::createColumnForResultSet( const Reference< XResultSetMetaData >& _rxResMetaData,
+ const Reference< XDatabaseMetaData >& _rxDBMetaData, sal_Int32 _nColumnPos, StringMap& _rColumns )
+{
+ OUString sLabel = _rxResMetaData->getColumnLabel( _nColumnPos );
+ // retrieve the name of the column
+ // check for duplicate entries
+ if(_rColumns.find(sLabel) != _rColumns.end())
+ {
+ OUString sAlias(sLabel);
+ sal_Int32 searchIndex=1;
+ while(_rColumns.find(sAlias) != _rColumns.end())
+ {
+ sAlias = sLabel + OUString::number(searchIndex++);
+ }
+ sLabel = sAlias;
+ }
+ _rColumns.emplace(sLabel,0);
+ rtl::Reference<OParseColumn> pColumn = new OParseColumn(
+ sLabel,
+ _rxResMetaData->getColumnTypeName( _nColumnPos ),
+ OUString(),
+ OUString(),
+ _rxResMetaData->isNullable( _nColumnPos ),
+ _rxResMetaData->getPrecision( _nColumnPos ),
+ _rxResMetaData->getScale( _nColumnPos ),
+ _rxResMetaData->getColumnType( _nColumnPos ),
+ _rxResMetaData->isAutoIncrement( _nColumnPos ),
+ _rxResMetaData->isCurrency( _nColumnPos ),
+ _rxDBMetaData->supportsMixedCaseQuotedIdentifiers(),
+ _rxResMetaData->getCatalogName( _nColumnPos ),
+ _rxResMetaData->getSchemaName( _nColumnPos ),
+ _rxResMetaData->getTableName( _nColumnPos )
+ );
+ pColumn->setIsSearchable( _rxResMetaData->isSearchable( _nColumnPos ) );
+ pColumn->setRealName(_rxResMetaData->getColumnName( _nColumnPos ));
+ pColumn->setLabel(sLabel);
+ return pColumn;
+}
+
+
+OParseColumn::~OParseColumn()
+{
+}
+
+void OParseColumn::construct()
+{
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FUNCTION), PROPERTY_ID_FUNCTION, 0, &m_bFunction, cppu::UnoType<decltype(m_bFunction)>::get());
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_AGGREGATEFUNCTION), PROPERTY_ID_AGGREGATEFUNCTION, 0, &m_bAggregateFunction, cppu::UnoType<decltype(m_bAggregateFunction)>::get());
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_REALNAME), PROPERTY_ID_REALNAME, 0, &m_aRealName, cppu::UnoType<decltype(m_aRealName)>::get());
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DBASEPRECISIONCHANGED), PROPERTY_ID_DBASEPRECISIONCHANGED, 0, &m_bDbasePrecisionChanged, cppu::UnoType<decltype(m_bDbasePrecisionChanged)>::get());
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISSEARCHABLE), PROPERTY_ID_ISSEARCHABLE, 0, &m_bIsSearchable, cppu::UnoType<decltype(m_bIsSearchable)>::get());
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_LABEL), PROPERTY_ID_LABEL, 0, &m_sLabel, cppu::UnoType<decltype(m_sLabel)>::get());
+}
+
+::cppu::IPropertyArrayHelper* OParseColumn::createArrayHelper() const
+{
+ return doCreateArrayHelper();
+}
+
+::cppu::IPropertyArrayHelper & SAL_CALL OParseColumn::getInfoHelper()
+{
+ OSL_ENSURE( !isNew(), "OParseColumn::getInfoHelper: a *new* ParseColumn?" );
+ return *OParseColumn_PROP::getArrayHelper();
+}
+
+
+OOrderColumn::OOrderColumn( const Reference<XPropertySet>& _xColumn, const OUString& i_rOriginatingTableName,
+ bool _bCase, bool _bAscending )
+ : connectivity::sdbcx::OColumn(
+ getString(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME))),
+ getString(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPENAME))),
+ getString(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DEFAULTVALUE))),
+ getString(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DESCRIPTION))),
+ getINT32(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISNULLABLE))),
+ getINT32(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PRECISION))),
+ getINT32(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCALE))),
+ getINT32(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE))),
+ getBOOL(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISAUTOINCREMENT))),
+ false,
+ getBOOL(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISCURRENCY))),
+ _bCase,
+ getString(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_CATALOGNAME))),
+ getString(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCHEMANAME))),
+ i_rOriginatingTableName
+ )
+ ,m_bAscending(_bAscending)
+{
+ construct();
+}
+
+
+OOrderColumn::OOrderColumn( const Reference<XPropertySet>& _xColumn, bool _bCase, bool _bAscending )
+ : connectivity::sdbcx::OColumn(
+ getString(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME))),
+ getString(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPENAME))),
+ getString(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DEFAULTVALUE))),
+ getString(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DESCRIPTION))),
+ getINT32(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISNULLABLE))),
+ getINT32(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PRECISION))),
+ getINT32(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCALE))),
+ getINT32(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE))),
+ getBOOL(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISAUTOINCREMENT))),
+ false,
+ getBOOL(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISCURRENCY))),
+ _bCase,
+ getString(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_CATALOGNAME))),
+ getString(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCHEMANAME))),
+ getString(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TABLENAME)))
+ )
+ ,m_bAscending(_bAscending)
+{
+ construct();
+}
+
+
+OOrderColumn::~OOrderColumn()
+{
+}
+
+
+void OOrderColumn::construct()
+{
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISASCENDING), PROPERTY_ID_ISASCENDING,
+ PropertyAttribute::READONLY, const_cast< bool* >( &m_bAscending ), cppu::UnoType<decltype(m_bAscending)>::get() );
+}
+
+::cppu::IPropertyArrayHelper* OOrderColumn::createArrayHelper() const
+{
+ return doCreateArrayHelper();
+}
+
+::cppu::IPropertyArrayHelper & SAL_CALL OOrderColumn::getInfoHelper()
+{
+ OSL_ENSURE( !isNew(), "OOrderColumn::getInfoHelper: a *new* OrderColumn?" );
+ return *OOrderColumn_PROP::getArrayHelper();
+}
+
+css::uno::Sequence< OUString > SAL_CALL OOrderColumn::getSupportedServiceNames( )
+{
+ return { "com.sun.star.sdb.OrderColumn" };
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/parse/internalnode.cxx b/connectivity/source/parse/internalnode.cxx
new file mode 100644
index 0000000000..1906ad3d46
--- /dev/null
+++ b/connectivity/source/parse/internalnode.cxx
@@ -0,0 +1,64 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <connectivity/sqlparse.hxx>
+#include <connectivity/internalnode.hxx>
+
+using namespace connectivity;
+
+
+OSQLInternalNode::OSQLInternalNode(const char* pNewValue,
+ SQLNodeType eNodeType,
+ sal_uInt32 nNodeID)
+ : OSQLParseNode(pNewValue,eNodeType,nNodeID)
+{
+ OSL_ENSURE(OSQLParser::s_pGarbageCollector, "Collector not initialized");
+ (*OSQLParser::s_pGarbageCollector)->push_back(this);
+}
+
+
+OSQLInternalNode::OSQLInternalNode(std::string_view NewValue,
+ SQLNodeType eNodeType,
+ sal_uInt32 nNodeID)
+ :OSQLParseNode(NewValue,eNodeType,nNodeID)
+{
+ OSL_ENSURE(OSQLParser::s_pGarbageCollector, "Collector not initialized");
+ (*OSQLParser::s_pGarbageCollector)->push_back(this);
+}
+
+
+OSQLInternalNode::OSQLInternalNode(const OUString &NewValue,
+ SQLNodeType eNodeType,
+ sal_uInt32 nNodeID)
+ :OSQLParseNode(NewValue,eNodeType,nNodeID)
+{
+ OSL_ENSURE(OSQLParser::s_pGarbageCollector, "Collector not initialized");
+ (*OSQLParser::s_pGarbageCollector)->push_back(this);
+}
+
+
+OSQLInternalNode::~OSQLInternalNode()
+{
+ // remove the node from the garbage list
+
+ OSL_ENSURE(OSQLParser::s_pGarbageCollector, "Collector not initialized");
+ (*OSQLParser::s_pGarbageCollector)->erase(this);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/parse/sqlbison.y b/connectivity/source/parse/sqlbison.y
new file mode 100644
index 0000000000..00666ed87a
--- /dev/null
+++ b/connectivity/source/parse/sqlbison.y
@@ -0,0 +1,4857 @@
+%glr-parser
+%token-table
+%{
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <vector>
+#include <string.h>
+
+#include <connectivity/sqlnode.hxx>
+#include <connectivity/sqlparse.hxx>
+#include <connectivity/sqlbison_exports.hxx>
+#include <connectivity/sqlscan.hxx>
+#include <connectivity/internalnode.hxx>
+#include <com/sun/star/lang/Locale.hpp>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <com/sun/star/util/Date.hpp>
+#include <com/sun/star/util/DateTime.hpp>
+#include <com/sun/star/util/Time.hpp>
+#include <com/sun/star/util/XNumberFormatter.hpp>
+#include <com/sun/star/util/XNumberFormatsSupplier.hpp>
+#include <com/sun/star/util/XNumberFormats.hpp>
+#include <com/sun/star/util/NumberFormat.hpp>
+#include <com/sun/star/util/XNumberFormatTypes.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/i18n/KParseType.hpp>
+#include <com/sun/star/i18n/KParseTokens.hpp>
+
+#include <osl/diagnose.h>
+#include "connectivity/dbconversion.hxx"
+#include <rtl/ustrbuf.hxx>
+#include <sal/log.hxx>
+
+#if defined _MSC_VER
+#pragma warning(push)
+#pragma warning(disable: 4324) // structure was padded due to alignment specifier
+#pragma warning(disable: 4065) // switch statement contains 'default' but no 'case' labels
+#pragma warning(disable: 4702) // unreachable code
+#endif
+
+#ifdef __GNUC__
+# pragma GCC diagnostic ignored "-Wwrite-strings"
+# pragma GCC diagnostic ignored "-Wunused-function"
+#endif
+
+inline connectivity::OSQLInternalNode* newNode(const char* pNewValue,
+ const connectivity::SQLNodeType eNodeType,
+ const sal_uInt32 nNodeID = 0);
+
+inline connectivity::OSQLInternalNode* newNode(const OString& _newValue,
+ const connectivity::SQLNodeType eNodeType,
+ const sal_uInt32 nNodeID = 0);
+
+inline connectivity::OSQLInternalNode* newNode(const OUString& _newValue,
+ const connectivity::SQLNodeType eNodeType,
+ const sal_uInt32 nNodeID = 0);
+
+
+// yyi is the internal number of the rule that is currently being reduced
+// This can be mapped to external rule number via the yyrmap.
+#if defined YYBISON && YYBISON >= 30800
+#define SQL_NEW_RULE newNode("", SQLNodeType::Rule, yyr1[yyrule])
+#define SQL_NEW_LISTRULE newNode("", SQLNodeType::ListRule, yyr1[yyrule])
+#define SQL_NEW_COMMALISTRULE newNode("", SQLNodeType::CommaListRule, yyr1[yyrule])
+#else
+#define SQL_NEW_RULE newNode("", SQLNodeType::Rule, yyr1[yyn])
+#define SQL_NEW_LISTRULE newNode("", SQLNodeType::ListRule, yyr1[yyn])
+#define SQL_NEW_COMMALISTRULE newNode("", SQLNodeType::CommaListRule, yyr1[yyn])
+#endif
+
+
+extern connectivity::OSQLParser* xxx_pGLOBAL_SQLPARSER;
+
+#define YYERROR_VERBOSE
+
+#define SQLyyerror(s) \
+{ \
+ xxx_pGLOBAL_SQLPARSER->error(s); \
+}
+
+using namespace connectivity;
+#define SQLyylex xxx_pGLOBAL_SQLPARSER->SQLlex
+%}
+ /* symbolic tokens */
+
+%union {
+ connectivity::OSQLParseNode * pParseNode;
+}
+%type <pParseNode> '(' ')' ',' ':' ';' '?' '[' ']' '{' '}' '.' 'K' 'M' 'G' 'T' 'P'
+
+%token <pParseNode> SQL_TOKEN_STRING SQL_TOKEN_ACCESS_DATE SQL_TOKEN_INT SQL_TOKEN_REAL_NUM
+%token <pParseNode> SQL_TOKEN_INTNUM SQL_TOKEN_APPROXNUM SQL_TOKEN_NOT SQL_TOKEN_NAME
+
+
+%nonassoc <pParseNode> SQL_TOKEN_UMINUS
+
+
+
+ /* literal keyword tokens */
+
+%token <pParseNode> SQL_TOKEN_ALL SQL_TOKEN_ALTER SQL_TOKEN_AMMSC SQL_TOKEN_ANY SQL_TOKEN_AS SQL_TOKEN_ASC SQL_TOKEN_AT SQL_TOKEN_AUTHORIZATION SQL_TOKEN_AVG
+
+%token <pParseNode> SQL_TOKEN_BETWEEN SQL_TOKEN_BIT SQL_TOKEN_BOTH SQL_TOKEN_BY
+
+%token <pParseNode> SQL_TOKEN_CAST SQL_TOKEN_CHARACTER SQL_TOKEN_CHECK SQL_TOKEN_COLLATE SQL_TOKEN_COMMIT SQL_TOKEN_CONTINUE SQL_TOKEN_CONVERT SQL_TOKEN_COUNT SQL_TOKEN_CREATE SQL_TOKEN_CROSS
+%token <pParseNode> SQL_TOKEN_CURRENT SQL_TOKEN_CURSOR
+
+%token <pParseNode> SQL_TOKEN_DATE SQL_TOKEN_DATEVALUE SQL_TOKEN_DAY SQL_TOKEN_DEC SQL_TOKEN_DECIMAL SQL_TOKEN_DECLARE SQL_TOKEN_DEFAULT SQL_TOKEN_DELETE SQL_TOKEN_DESC
+%token <pParseNode> SQL_TOKEN_DISTINCT SQL_TOKEN_DOUBLE SQL_TOKEN_DROP
+
+%token <pParseNode> SQL_TOKEN_ESCAPE SQL_TOKEN_EXCEPT SQL_TOKEN_EXISTS SQL_TOKEN_FALSE SQL_TOKEN_FETCH SQL_TOKEN_FLOAT SQL_TOKEN_FOR SQL_TOKEN_FOREIGN SQL_TOKEN_FOUND SQL_TOKEN_FROM SQL_TOKEN_FULL
+
+%token <pParseNode> SQL_TOKEN_GRANT SQL_TOKEN_GROUP SQL_TOKEN_HAVING SQL_TOKEN_IN SQL_TOKEN_INDICATOR SQL_TOKEN_INNER SQL_TOKEN_INTEGER SQL_TOKEN_INTO SQL_TOKEN_IS SQL_TOKEN_INTERSECT
+
+%left <pParseNode> SQL_TOKEN_JOIN
+%token <pParseNode> SQL_TOKEN_KEY SQL_TOKEN_LEADING SQL_TOKEN_LIKE SQL_TOKEN_LOCAL SQL_TOKEN_LOWER
+%token <pParseNode> SQL_TOKEN_MAX SQL_TOKEN_MIN SQL_TOKEN_NATURAL SQL_TOKEN_NCHAR SQL_TOKEN_NULL SQL_TOKEN_NUMERIC
+
+%token <pParseNode> SQL_TOKEN_OCTET_LENGTH SQL_TOKEN_OF SQL_TOKEN_ON SQL_TOKEN_OPTION SQL_TOKEN_ORDER SQL_TOKEN_OUTER
+
+%token <pParseNode> SQL_TOKEN_PRECISION SQL_TOKEN_PRIMARY SQL_TOKEN_PRIVILEGES SQL_TOKEN_PROCEDURE SQL_TOKEN_PUBLIC
+%token <pParseNode> SQL_TOKEN_REAL SQL_TOKEN_REFERENCES SQL_TOKEN_ROLLBACK
+
+%token <pParseNode> SQL_TOKEN_SCHEMA SQL_TOKEN_SELECT SQL_TOKEN_SET SQL_TOKEN_SIZE SQL_TOKEN_SMALLINT SQL_TOKEN_SOME SQL_TOKEN_SQLCODE SQL_TOKEN_SQLERROR SQL_TOKEN_SUM
+
+%token <pParseNode> SQL_TOKEN_TABLE SQL_TOKEN_TIME SQL_TOKEN_TIMESTAMP SQL_TOKEN_TIMEZONE_HOUR SQL_TOKEN_TIMEZONE_MINUTE SQL_TOKEN_TO SQL_TOKEN_TRAILING SQL_TOKEN_TRANSLATE SQL_TOKEN_TRIM SQL_TOKEN_TRUE SQL_TOKEN_UNION
+%token <pParseNode> SQL_TOKEN_UNIQUE SQL_TOKEN_UNKNOWN SQL_TOKEN_UPDATE SQL_TOKEN_UPPER SQL_TOKEN_USAGE SQL_TOKEN_USER SQL_TOKEN_USING SQL_TOKEN_VALUES SQL_TOKEN_VIEW
+%token <pParseNode> SQL_TOKEN_WHERE SQL_TOKEN_WITH SQL_TOKEN_WORK SQL_TOKEN_ZONE
+
+/* ODBC KEYWORDS */
+%token <pParseNode> SQL_TOKEN_CALL SQL_TOKEN_D SQL_TOKEN_FN SQL_TOKEN_T SQL_TOKEN_TS SQL_TOKEN_OJ
+/* string functions */
+%token <pParseNode> SQL_TOKEN_ASCII SQL_TOKEN_BIT_LENGTH SQL_TOKEN_CHAR SQL_TOKEN_CHAR_LENGTH SQL_TOKEN_SQL_TOKEN_INTNUM
+%token <pParseNode> SQL_TOKEN_CONCAT
+%token <pParseNode> SQL_TOKEN_DIFFERENCE SQL_TOKEN_INSERT SQL_TOKEN_LCASE SQL_TOKEN_LEFT SQL_TOKEN_LENGTH SQL_TOKEN_LOCATE
+%token <pParseNode> SQL_TOKEN_LOCATE_2 SQL_TOKEN_LTRIM SQL_TOKEN_POSITION SQL_TOKEN_REPEAT SQL_TOKEN_REPLACE
+%token <pParseNode> SQL_TOKEN_RIGHT SQL_TOKEN_RTRIM SQL_TOKEN_SOUNDEX SQL_TOKEN_SPACE SQL_TOKEN_SUBSTRING SQL_TOKEN_UCASE
+
+/* time and date functions */
+%token <pParseNode> SQL_TOKEN_CURRENT_DATE SQL_TOKEN_CURRENT_TIME SQL_TOKEN_CURRENT_TIMESTAMP SQL_TOKEN_CURDATE SQL_TOKEN_CURTIME
+%token <pParseNode> SQL_TOKEN_DAYNAME SQL_TOKEN_DAYOFMONTH SQL_TOKEN_DAYOFWEEK SQL_TOKEN_DAYOFYEAR SQL_TOKEN_EXTRACT
+%token <pParseNode> SQL_TOKEN_HOUR SQL_TOKEN_MILLISECOND SQL_TOKEN_MINUTE SQL_TOKEN_MONTH SQL_TOKEN_MONTHNAME SQL_TOKEN_NOW SQL_TOKEN_QUARTER SQL_TOKEN_DATEDIFF
+%token <pParseNode> SQL_TOKEN_SECOND SQL_TOKEN_TIMESTAMPADD SQL_TOKEN_TIMESTAMPDIFF SQL_TOKEN_TIMEVALUE SQL_TOKEN_WEEK SQL_TOKEN_WEEKDAY SQL_TOKEN_YEAR SQL_TOKEN_YEARDAY
+%token <pParseNode> SQL_TOKEN_DATEADD
+
+/* numeric functions */
+%token <pParseNode> SQL_TOKEN_ABS SQL_TOKEN_ACOS SQL_TOKEN_ASIN SQL_TOKEN_ATAN SQL_TOKEN_ATAN2 SQL_TOKEN_CEILING
+%token <pParseNode> SQL_TOKEN_COS SQL_TOKEN_COT SQL_TOKEN_DEGREES SQL_TOKEN_EXP SQL_TOKEN_FLOOR SQL_TOKEN_LOGF SQL_TOKEN_LOG SQL_TOKEN_LN
+%token <pParseNode> SQL_TOKEN_LOG10 SQL_TOKEN_MOD SQL_TOKEN_PI SQL_TOKEN_POWER SQL_TOKEN_RADIANS SQL_TOKEN_RAND SQL_TOKEN_ROUNDMAGIC
+%token <pParseNode> SQL_TOKEN_ROUND SQL_TOKEN_SIGN SQL_TOKEN_SIN SQL_TOKEN_SQRT SQL_TOKEN_TAN SQL_TOKEN_TRUNCATE
+
+// computational operation
+%token <pParseNode> SQL_TOKEN_EVERY SQL_TOKEN_INTERSECTION SQL_TOKEN_FUSION SQL_TOKEN_COLLECT SQL_TOKEN_VAR_POP SQL_TOKEN_VAR_SAMP
+%token <pParseNode> SQL_TOKEN_STDDEV_SAMP SQL_TOKEN_STDDEV_POP
+
+%token <pParseNode> SQL_TOKEN_RANK SQL_TOKEN_DENSE_RANK SQL_TOKEN_PERCENT_RANK SQL_TOKEN_CUME_DIST SQL_TOKEN_PERCENTILE_CONT SQL_TOKEN_PERCENTILE_DISC SQL_TOKEN_WITHIN SQL_TOKEN_ARRAY_AGG
+%token <pParseNode> SQL_TOKEN_CASE SQL_TOKEN_THEN SQL_TOKEN_END SQL_TOKEN_NULLIF SQL_TOKEN_COALESCE SQL_TOKEN_WHEN SQL_TOKEN_ELSE
+%token <pParseNode> SQL_TOKEN_BEFORE SQL_TOKEN_AFTER SQL_TOKEN_INSTEAD SQL_TOKEN_EACH SQL_TOKEN_REFERENCING SQL_TOKEN_BEGIN SQL_TOKEN_ATOMIC SQL_TOKEN_TRIGGER SQL_TOKEN_ROW SQL_TOKEN_STATEMENT
+%token <pParseNode> SQL_TOKEN_NEW SQL_TOKEN_OLD
+%token <pParseNode> SQL_TOKEN_VALUE SQL_TOKEN_CURRENT_CATALOG SQL_TOKEN_CURRENT_DEFAULT_TRANSFORM_GROUP SQL_TOKEN_CURRENT_PATH SQL_TOKEN_CURRENT_ROLE SQL_TOKEN_CURRENT_SCHEMA SQL_TOKEN_CURRENT_USER
+%token <pParseNode> SQL_TOKEN_SESSION_USER SQL_TOKEN_SYSTEM_USER SQL_TOKEN_VARCHAR SQL_TOKEN_VARBINARY SQL_TOKEN_VARYING SQL_TOKEN_OBJECT SQL_TOKEN_NCLOB SQL_TOKEN_NATIONAL
+%token <pParseNode> SQL_TOKEN_LARGE SQL_TOKEN_CLOB SQL_TOKEN_BLOB SQL_TOKEN_BIGINT SQL_TOKEN_BINARY SQL_TOKEN_WITHOUT SQL_TOKEN_BOOLEAN SQL_TOKEN_INTERVAL
+// window function
+%token <pParseNode> SQL_TOKEN_OVER SQL_TOKEN_ROW_NUMBER SQL_TOKEN_NTILE SQL_TOKEN_LEAD SQL_TOKEN_LAG SQL_TOKEN_RESPECT SQL_TOKEN_IGNORE SQL_TOKEN_NULLS
+%token <pParseNode> SQL_TOKEN_FIRST_VALUE SQL_TOKEN_LAST_VALUE SQL_TOKEN_NTH_VALUE SQL_TOKEN_FIRST SQL_TOKEN_LAST
+%token <pParseNode> SQL_TOKEN_EXCLUDE SQL_TOKEN_OTHERS SQL_TOKEN_TIES SQL_TOKEN_FOLLOWING SQL_TOKEN_UNBOUNDED SQL_TOKEN_PRECEDING SQL_TOKEN_RANGE SQL_TOKEN_ROWS
+%token <pParseNode> SQL_TOKEN_PARTITION SQL_TOKEN_WINDOW SQL_TOKEN_NO
+// LIMIT and OFFSEt
+%token <pParseNode> SQL_TOKEN_LIMIT SQL_TOKEN_OFFSET SQL_TOKEN_NEXT SQL_TOKEN_ONLY
+
+ /* operators */
+%left SQL_TOKEN_NAME
+%left <pParseNode> SQL_TOKEN_OR
+%left <pParseNode> SQL_TOKEN_AND
+
+%left <pParseNode> SQL_LESSEQ SQL_GREATEQ SQL_NOTEQUAL SQL_LESS SQL_GREAT SQL_EQUAL /* '<' '>' = <> < > <= >= != */
+%left <pParseNode> '+' '-' SQL_CONCAT
+%left <pParseNode> '*' '/'
+%left SQL_TOKEN_NATURAL SQL_TOKEN_CROSS SQL_TOKEN_FULL SQL_TOKEN_LEFT SQL_TOKEN_RIGHT
+%left ')'
+%right '='
+%right '.'
+%right '('
+
+
+%token <pParseNode> SQL_TOKEN_INVALIDSYMBOL
+
+/*%type <pParseNode> sql_single_statement */
+
+%type <pParseNode> sql /*schema */
+%type <pParseNode> column_def_opt_list column_def_opt table_constraint_def column_commalist
+%type <pParseNode> view_def opt_with_check_option opt_column_commalist privilege_def
+%type <pParseNode> opt_with_grant_option privileges operation_commalist operation
+%type <pParseNode> grantee_commalist grantee opt_order_by_clause ordering_spec_commalist
+%type <pParseNode> ordering_spec opt_asc_desc manipulative_statement commit_statement
+%type <pParseNode> /*delete_statement_positioned*/ delete_statement_searched fetch_statement
+%type <pParseNode> insert_statement values_or_query_spec
+%type <pParseNode> rollback_statement select_statement_into opt_all_distinct
+%type <pParseNode> /*update_statement_positioned*/ assignment_commalist assignment
+%type <pParseNode> update_statement_searched target_commalist target opt_where_clause
+%type <pParseNode> select_statement selection table_exp from_clause table_ref_commalist table_ref
+%type <pParseNode> where_clause opt_group_by_clause column_ref_commalist opt_having_clause
+%type <pParseNode> search_condition predicate comparison_predicate comparison_predicate_part_2 between_predicate between_predicate_part_2
+%type <pParseNode> like_predicate opt_escape test_for_null null_predicate_part_2 in_predicate in_predicate_part_2 character_like_predicate_part_2 other_like_predicate_part_2
+%type <pParseNode> all_or_any_predicate any_all_some existence_test subquery quantified_comparison_predicate_part_2
+%type <pParseNode> scalar_exp_commalist parameter_ref literal parenthesized_boolean_value_expression
+%type <pParseNode> column_ref data_type column cursor parameter range_variable user /*like_check*/ datetime_unit
+/* new rules at OJ */
+%type <pParseNode> derived_column as_clause table_name num_primary term num_value_exp
+%type <pParseNode> value_exp_primary num_value_fct unsigned_value_spec cast_spec set_fct_spec scalar_subquery
+%type <pParseNode> position_exp extract_exp length_exp general_value_spec
+%type <pParseNode> general_set_fct set_fct_type query_exp non_join_query_exp joined_table
+%type <pParseNode> non_join_query_term non_join_query_primary simple_table
+%type <pParseNode> table_value_const_list row_value_constructor /*row_value_const_list*/ row_value_constructor_elem
+%type <pParseNode> qualified_join value_exp query_term join_type outer_join_type join_condition boolean_term
+%type <pParseNode> boolean_factor boolean_primary named_columns_join join_spec
+%type <pParseNode> cast_operand cast_target factor datetime_value_exp /*interval_value_exp*/ datetime_term datetime_factor
+%type <pParseNode> datetime_primary datetime_value_fct time_zone time_zone_specifier /*interval_term*/ interval_qualifier
+%type <pParseNode> start_field non_second_datetime_field end_field single_datetime_field extract_field datetime_field time_zone_field
+%type <pParseNode> char_length_exp octet_length_exp bit_length_exp select_sublist string_value_exp
+%type <pParseNode> char_value_exp concatenation char_factor char_primary string_value_fct char_substring_fct fold
+%type <pParseNode> form_conversion char_translation trim_fct trim_operands trim_spec bit_value_fct bit_substring_fct op_column_commalist
+%type <pParseNode> /*bit_concatenation*/ bit_value_exp bit_factor bit_primary collate_clause char_value_fct unique_spec value_exp_commalist in_predicate_value unique_test update_source
+%type <pParseNode> function_arg_commalist3 string_function_3Argument function_arg_commalist4 string_function_4Argument function_arg_commalist2 string_function_1Argument string_function_2Argument
+%type <pParseNode> date_function_0Argument date_function_1Argument function_name12 function_name23 function_name1 function_name2 function_name3 function_name0 numeric_function_0Argument numeric_function_1Argument numeric_function_2Argument
+%type <pParseNode> all query_primary sql_not for_length upper_lower comparison column_val cross_union /*opt_schema_element_list*/
+%type <pParseNode> /*op_authorization op_schema*/ nil_fkt schema_element base_table_def base_table_element base_table_element_commalist
+%type <pParseNode> column_def odbc_fct_spec odbc_call_spec odbc_fct_type op_parameter union_statement
+%type <pParseNode> op_odbc_call_parameter odbc_parameter_commalist odbc_parameter function_args_commalist function_arg
+%type <pParseNode> catalog_name schema_name table_node numeric_function string_function function_name date_function table_primary_as_range_column opt_as
+%type <pParseNode> ordered_set_function inverse_distribution_function hypothetical_set_function hypothetical_set_function_value_expression_list rank_function_type within_group_specification inverse_distribution_function_type array_aggregate_function inverse_distribution_function_argument
+%type <pParseNode> case_expression else_clause result_expression result case_abbreviation case_specification searched_when_clause simple_when_clause searched_case simple_case
+%type <pParseNode> when_operand_list when_operand case_operand
+%type <pParseNode> trigger_definition trigger_name trigger_action_time trigger_event transition_table_or_variable_list triggered_action trigger_column_list triggered_when_clause triggered_SQL_statement SQL_procedure_statement old_transition_variable_name new_transition_variable_name
+%type <pParseNode> op_referencing op_trigger_columnlist op_triggered_action_for opt_row trigger_for SQL_procedure_statement_list transition_table_or_variable old_transition_table_name new_transition_table_name transition_table_name
+%type <pParseNode> searched_when_clause_list simple_when_clause_list predefined_type opt_char_set_spec opt_collate_clause character_string_type national_character_string_type
+%type <pParseNode> binary_string_type numeric_type boolean_type datetime_type interval_type opt_paren_precision paren_char_length opt_paren_char_large_length paren_character_large_object_length
+%type <pParseNode> large_object_length opt_multiplier character_large_object_type national_character_large_object_type binary_large_object_string_type opt_with_or_without_time_zone
+%type <pParseNode> approximate_numeric_type exact_numeric_type opt_paren_precision_scale
+/* window function rules */
+%type <pParseNode> window_function window_function_type ntile_function number_of_tiles lead_or_lag_function lead_or_lag lead_or_lag_extent offset default_expression null_treatment
+%type <pParseNode> first_or_last_value_function first_or_last_value nth_value_function nth_row from_first_or_last window_name_or_specification in_line_window_specification opt_lead_or_lag_function
+%type <pParseNode> opt_null_treatment opt_from_first_or_last simple_value_specification dynamic_parameter_specification window_name window_clause window_definition_list window_definition
+%type <pParseNode> new_window_name existing_window_name window_partition_clause window_partition_column_reference_list window_partition_column_reference window_frame_clause
+%type <pParseNode> window_frame_units window_frame_extent window_frame_start window_frame_preceding window_frame_between window_frame_bound_1 window_frame_bound_2 window_frame_bound window_frame_following window_frame_exclusion
+%type <pParseNode> opt_window_frame_clause opt_window_partition_clause opt_existing_window_name window_specification opt_window_frame_exclusion opt_window_clause opt_offset
+%type <pParseNode> opt_fetch_first_row_count fetch_first_clause offset_row_count fetch_first_row_count first_or_next row_or_rows opt_result_offset_clause result_offset_clause
+/* LIMIT and OFFSET */
+%type <pParseNode> opt_limit_offset_clause limit_offset_clause opt_fetch_first_clause
+%%
+
+/* Return Parse Tree to OSQLParser
+ * (the access over yyval after calling the parser fails,
+ *
+ */
+sql_single_statement:
+ sql
+ { xxx_pGLOBAL_SQLPARSER->setParseTree( $1 ); }
+ | sql ';'
+ { xxx_pGLOBAL_SQLPARSER->setParseTree( $1 ); }
+ ;
+
+ /* schema definition language */
+ /* Note: other ``sql:sal_Unicode() rules appear later in the grammar */
+
+sql:
+ manipulative_statement
+ | schema_element
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+ ;
+
+/***
+
+op_authorization:
+ {$$ = SQL_NEW_RULE;}
+ | SQL_TOKEN_AUTHORIZATION user
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+op_schema:
+ {$$ = SQL_NEW_RULE;}
+ | SQL_TOKEN_NAME
+ | SQL_TOKEN_NAME '.' SQL_TOKEN_NAME
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode(".", SQLNodeType::Punctuation));
+ $$->append($3);
+ }
+ ;
+
+schema:
+ SQL_TOKEN_CREATE SQL_TOKEN_SCHEMA op_schema op_authorization opt_schema_element_list
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ $$->append($5);
+ }
+ ;
+
+opt_schema_element_list:
+ {$$ = SQL_NEW_RULE;}
+ | schema_element_list
+ ;
+
+schema_element_list:
+ schema_element
+ {$$ = SQL_NEW_LISTRULE;
+ $$->append($1);}
+ | schema_element_list schema_element
+ {$1->append($2);
+ $$ = $1;}
+ ;
+*/
+
+schema_element:
+ base_table_def
+ | view_def
+ | privilege_def
+ | trigger_definition
+ ;
+
+base_table_def:
+ SQL_TOKEN_CREATE SQL_TOKEN_TABLE table_node '(' base_table_element_commalist ')'
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($5);
+ $$->append(newNode(")", SQLNodeType::Punctuation));}
+ ;
+
+base_table_element_commalist:
+ base_table_element
+ {$$ = SQL_NEW_COMMALISTRULE;
+ $$->append($1);}
+ | base_table_element_commalist ',' base_table_element
+ {$1->append($3);
+ $$ = $1;}
+ ;
+
+base_table_element:
+ column_def
+ | table_constraint_def
+ ;
+
+column_def:
+ column data_type column_def_opt_list
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ ;
+
+column_def_opt_list:
+ /* empty */ {$$ = SQL_NEW_LISTRULE;}
+ | column_def_opt_list column_def_opt
+ {$1->append($2);
+ $$ = $1;}
+ ;
+
+nil_fkt:
+ datetime_value_fct
+ ;
+unique_spec:
+ SQL_TOKEN_UNIQUE
+ | SQL_TOKEN_PRIMARY SQL_TOKEN_KEY
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+column_def_opt:
+ SQL_TOKEN_NOT SQL_TOKEN_NULL
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);}
+ | unique_spec
+ | SQL_TOKEN_DEFAULT literal
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);}
+ | SQL_TOKEN_DEFAULT SQL_TOKEN_NULL
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);}
+ | SQL_TOKEN_DEFAULT SQL_TOKEN_USER
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);}
+ | SQL_TOKEN_DEFAULT nil_fkt
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ | SQL_TOKEN_CHECK
+ | SQL_TOKEN_CHECK '(' search_condition ')'
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(")", SQLNodeType::Punctuation));}
+ | SQL_TOKEN_REFERENCES table_node
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);}
+ | SQL_TOKEN_REFERENCES table_node '(' column_commalist ')'
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($4);
+ $$->append(newNode(")", SQLNodeType::Punctuation));}
+ ;
+
+table_constraint_def:
+ unique_spec '(' column_commalist ')'
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(")", SQLNodeType::Punctuation));}
+ | SQL_TOKEN_FOREIGN SQL_TOKEN_KEY '(' column_commalist ')' SQL_TOKEN_REFERENCES table_node
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($4);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ $$->append($6);
+ $$->append($7);}
+ | SQL_TOKEN_FOREIGN SQL_TOKEN_KEY '(' column_commalist ')' SQL_TOKEN_REFERENCES table_node '(' column_commalist ')'
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($4);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ $$->append($6);
+ $$->append($7);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($9);
+ $$->append(newNode(")", SQLNodeType::Punctuation));}
+ | SQL_TOKEN_CHECK '(' search_condition ')'
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(")", SQLNodeType::Punctuation));}
+ ;
+op_column_commalist:
+ /* empty */ {$$ = SQL_NEW_RULE;}
+ | '(' column_commalist ')'
+ {$$ = SQL_NEW_RULE;
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($2);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ ;
+column_commalist:
+ column_commalist ',' column
+ {$1->append($3);
+ $$ = $1;}
+ | column
+ {$$ = SQL_NEW_COMMALISTRULE;
+ $$->append($1);}
+ ;
+
+view_def:
+ SQL_TOKEN_CREATE SQL_TOKEN_VIEW table_node opt_column_commalist SQL_TOKEN_AS select_statement opt_with_check_option
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ $$->append($5);
+ $$->append($6);
+ $$->append($7);}
+ ;
+
+opt_with_check_option:
+ /* empty */ {$$ = SQL_NEW_RULE;}
+ | SQL_TOKEN_WITH SQL_TOKEN_CHECK SQL_TOKEN_OPTION
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);}
+ ;
+
+opt_column_commalist:
+ /* empty */ {$$ = SQL_NEW_RULE;}
+ | '(' column_commalist ')'
+ {$$ = SQL_NEW_RULE;
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($2);
+ $$->append(newNode(")", SQLNodeType::Punctuation));}
+ ;
+
+privilege_def:
+ SQL_TOKEN_GRANT privileges SQL_TOKEN_ON table_node SQL_TOKEN_TO grantee_commalist
+ opt_with_grant_option
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ $$->append($5);
+ $$->append($6);
+ $$->append($7);}
+ ;
+
+opt_with_grant_option:
+ /* empty */ {$$ = SQL_NEW_RULE;}
+ | SQL_TOKEN_WITH SQL_TOKEN_GRANT SQL_TOKEN_OPTION
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);}
+ ;
+
+privileges:
+ SQL_TOKEN_ALL SQL_TOKEN_PRIVILEGES
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);}
+ | operation_commalist
+ ;
+
+operation_commalist:
+ operation
+ {$$ = SQL_NEW_COMMALISTRULE;
+ $$->append($1);}
+ | operation_commalist ',' operation
+ {$1->append($3);
+ $$ = $1;}
+ ;
+
+operation:
+ SQL_TOKEN_SELECT
+ | SQL_TOKEN_INSERT opt_column_commalist
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);}
+ | SQL_TOKEN_DELETE
+ | SQL_TOKEN_UPDATE opt_column_commalist
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);}
+ | SQL_TOKEN_REFERENCES opt_column_commalist
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);}
+ | SQL_TOKEN_USAGE
+ ;
+
+
+grantee_commalist:
+ grantee
+ {$$ = SQL_NEW_COMMALISTRULE;
+ $$->append($1);}
+ | grantee_commalist ',' grantee
+ {$1->append($3);
+ $$ = $1;}
+ ;
+
+grantee:
+ SQL_TOKEN_PUBLIC
+ | user
+ ;
+
+ /* module language */
+
+opt_order_by_clause:
+ /* empty */ {$$ = SQL_NEW_RULE;}
+ | SQL_TOKEN_ORDER SQL_TOKEN_BY ordering_spec_commalist
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);}
+ ;
+
+ordering_spec_commalist:
+ ordering_spec
+ {$$ = SQL_NEW_COMMALISTRULE;
+ $$->append($1);}
+ | ordering_spec_commalist ',' ordering_spec
+ {$1->append($3);
+ $$ = $1;}
+ ;
+
+ordering_spec:
+/* SQL_TOKEN_INTNUM opt_asc_desc
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);}
+*/
+ predicate opt_asc_desc
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);}
+
+ | row_value_constructor_elem opt_asc_desc
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);}
+ ;
+
+opt_asc_desc:
+ {$$ = SQL_NEW_RULE;}
+ | SQL_TOKEN_ASC
+ | SQL_TOKEN_DESC
+ ;
+
+
+/***
+manipulative_statement_list:
+ manipulative_statement
+ {$$ = SQL_NEW_LISTRULE;
+ $$->append($1);}
+ | manipulative_statement_list manipulative_statement
+ {$1->append($2);
+ $$ = $1;}
+ ;
+***/
+
+sql_not:
+/* vide */
+ {$$ = SQL_NEW_RULE;}
+ | SQL_TOKEN_NOT
+ ;
+
+/* manipulative statements */
+
+manipulative_statement:
+ commit_statement
+/* | delete_statement_positioned*/
+ | delete_statement_searched
+ | fetch_statement
+ | insert_statement
+ | rollback_statement
+ | select_statement_into
+/* | update_statement_positioned*/
+ | update_statement_searched
+ | union_statement
+ | '{' odbc_call_spec '}'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append(newNode("{", SQLNodeType::Punctuation));
+ $$->append($2);
+ $$->append(newNode("}", SQLNodeType::Punctuation));
+ }
+ ;
+
+union_statement:
+ select_statement
+ | union_statement SQL_TOKEN_UNION all select_statement
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ }
+ ;
+commit_statement:
+ SQL_TOKEN_COMMIT SQL_TOKEN_WORK
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);}
+ ;
+/*
+delete_statement_positioned:
+ SQL_TOKEN_DELETE SQL_TOKEN_FROM table_node SQL_TOKEN_WHERE SQL_TOKEN_CURRENT SQL_TOKEN_OF cursor
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ $$->append($5);
+ $$->append($6);
+ $$->append($7);}
+ ;
+*/
+delete_statement_searched:
+ SQL_TOKEN_DELETE SQL_TOKEN_FROM table_node opt_where_clause
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);}
+ ;
+
+fetch_statement:
+ SQL_TOKEN_FETCH cursor SQL_TOKEN_INTO target_commalist
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);}
+ ;
+
+insert_statement:
+ SQL_TOKEN_INSERT SQL_TOKEN_INTO table_node opt_column_commalist query_exp
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ $$->append($5);}
+ ;
+values_or_query_spec:
+ SQL_TOKEN_VALUES '(' table_value_const_list ')'
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ ;
+
+table_value_const_list:
+ row_value_constructor
+ {$$ = SQL_NEW_COMMALISTRULE;
+ $$->append($1);}
+ | table_value_const_list ',' row_value_constructor
+ {$1->append($3);
+ $$ = $1;}
+ ;
+/*
+row_value_const_list:
+ row_value_constructor_elem
+ {$$ = SQL_NEW_COMMALISTRULE;
+ $$->append($1);}
+ | row_value_const_list ',' row_value_constructor_elem
+ {$1->append($3);
+ $$ = $1;}
+ ;
+*/
+row_value_constructor:
+ row_value_constructor_elem
+/* | '(' row_value_const_list ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($2);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ */
+ ;
+row_value_constructor_elem:
+ value_exp /*[^')']*/
+ | SQL_TOKEN_DEFAULT
+ ;
+
+
+rollback_statement:
+ SQL_TOKEN_ROLLBACK SQL_TOKEN_WORK
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);}
+ ;
+
+
+ /* INTO target_commalist herausgenommen */
+select_statement_into:
+ SQL_TOKEN_SELECT opt_all_distinct selection SQL_TOKEN_INTO target_commalist table_exp
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ $$->append($5);
+ $$->append($6); }
+ ;
+
+opt_all_distinct:
+ {$$ = SQL_NEW_RULE;}
+ | SQL_TOKEN_ALL
+ | SQL_TOKEN_DISTINCT
+
+ ;
+/*
+update_statement_positioned:
+ SQL_TOKEN_UPDATE table_node SQL_TOKEN_SET assignment_commalist
+ SQL_TOKEN_WHERE SQL_TOKEN_CURRENT SQL_TOKEN_OF cursor
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ $$->append($5);
+ $$->append($6);
+ $$->append($7);
+ $$->append($8);}
+ ;
+*/
+assignment_commalist:
+ assignment
+ {$$ = SQL_NEW_COMMALISTRULE;
+ $$->append($1);}
+ | assignment_commalist ',' assignment
+ {$1->append($3);
+ $$ = $1;}
+ ;
+
+assignment:
+ column SQL_EQUAL update_source
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);}
+ ;
+update_source:
+ value_exp
+ | SQL_TOKEN_DEFAULT
+ ;
+update_statement_searched:
+ SQL_TOKEN_UPDATE table_node SQL_TOKEN_SET assignment_commalist opt_where_clause
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ $$->append($5);}
+ ;
+
+target_commalist:
+ target
+ {$$ = SQL_NEW_COMMALISTRULE;
+ $$->append($1);}
+ | target_commalist ',' target
+ {$1->append($3);
+ $$ = $1;}
+ ;
+
+target:
+ parameter_ref
+ ;
+
+opt_where_clause:
+ /* empty */ {$$ = SQL_NEW_RULE;}
+ | where_clause
+ ;
+
+ /* query expressions */
+
+query_term:
+ non_join_query_term
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+ ;
+/* SELECT STATEMENT */
+select_statement:
+ SQL_TOKEN_SELECT opt_all_distinct selection table_exp
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ }
+ ;
+
+selection:
+ '*'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append(newNode("*", SQLNodeType::Punctuation));
+ }
+ | scalar_exp_commalist
+ ;
+opt_result_offset_clause:
+ /* empty */ {$$ = SQL_NEW_RULE;}
+ | result_offset_clause
+ ;
+result_offset_clause:
+ SQL_TOKEN_OFFSET offset_row_count row_or_rows
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ ;
+opt_fetch_first_row_count:
+ /* empty */ {$$ = SQL_NEW_RULE;}
+ | fetch_first_row_count
+ ;
+first_or_next:
+ SQL_TOKEN_FIRST
+ | SQL_TOKEN_NEXT
+ ;
+row_or_rows:
+ SQL_TOKEN_ROW
+ | SQL_TOKEN_ROWS
+ ;
+opt_fetch_first_clause:
+ /* empty */ {$$ = SQL_NEW_RULE;}
+ | fetch_first_clause
+ ;
+fetch_first_clause:
+ SQL_TOKEN_FETCH first_or_next opt_fetch_first_row_count row_or_rows SQL_TOKEN_ONLY
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ $$->append($5);
+ }
+ ;
+offset_row_count:
+ literal
+ ;
+fetch_first_row_count:
+ literal
+ ;
+
+opt_limit_offset_clause:
+ /* empty */ {$$ = SQL_NEW_RULE;}
+ | limit_offset_clause
+ ;
+opt_offset:
+ /* empty */ {$$ = SQL_NEW_RULE;}
+ | SQL_TOKEN_OFFSET SQL_TOKEN_INTNUM
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+limit_offset_clause:
+ SQL_TOKEN_LIMIT SQL_TOKEN_INTNUM opt_offset
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ ;
+table_exp:
+ from_clause opt_where_clause opt_group_by_clause opt_having_clause opt_window_clause opt_order_by_clause opt_limit_offset_clause opt_result_offset_clause opt_fetch_first_clause
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ $$->append($5);
+ $$->append($6);
+ $$->append($7);
+ $$->append($8);
+ $$->append($9);
+ }
+ ;
+
+from_clause:
+ SQL_TOKEN_FROM table_ref_commalist
+ { $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2); }
+ ;
+
+table_ref_commalist:
+
+ table_ref
+ { $$ = SQL_NEW_COMMALISTRULE;
+ $$->append($1); }
+ | table_ref_commalist ',' table_ref
+ { $1->append($3);
+ $$ = $1; }
+ ;
+
+opt_as:
+ /* empty */ {$$ = SQL_NEW_RULE;}
+ | SQL_TOKEN_AS
+ ;
+opt_row:
+ /* empty */ {$$ = SQL_NEW_RULE;}
+ | SQL_TOKEN_ROW
+ ;
+table_primary_as_range_column:
+ {$$ = SQL_NEW_RULE;}
+ | opt_as SQL_TOKEN_NAME op_column_commalist
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ ;
+table_ref:
+ table_node table_primary_as_range_column
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ | subquery range_variable op_column_commalist
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ | joined_table
+ | '{' SQL_TOKEN_OJ joined_table '}'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append(newNode("{", SQLNodeType::Punctuation));
+ $$->append($2);
+ $$->append($3);
+ $$->append(newNode("}", SQLNodeType::Punctuation));
+ }
+ | '(' joined_table ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($2);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ ;
+where_clause:
+ SQL_TOKEN_WHERE search_condition
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);}
+ ;
+
+opt_group_by_clause:
+ /* empty */ {$$ = SQL_NEW_RULE;}
+ | SQL_TOKEN_GROUP SQL_TOKEN_BY column_ref_commalist
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);}
+ ;
+
+column_ref_commalist:
+ column_ref
+ {$$ = SQL_NEW_COMMALISTRULE;
+ $$->append($1);}
+ | set_fct_spec
+ {$$ = SQL_NEW_COMMALISTRULE;
+ $$->append($1);}
+ | column_ref_commalist ',' column_ref
+ {$1->append($3);
+ $$ = $1;}
+ | column_ref_commalist ',' set_fct_spec
+ {$1->append($3);
+ $$ = $1;}
+ ;
+
+opt_having_clause:
+ /* empty */ {$$ = SQL_NEW_RULE;}
+ | SQL_TOKEN_HAVING search_condition
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);}
+ ;
+
+ /* search conditions */
+boolean_primary:
+ predicate
+ | '(' search_condition ')'
+ { // boolean_primary: rule 2
+ $$ = SQL_NEW_RULE;
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($2);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ | row_value_constructor_elem /*[^')' ',']*/
+ {
+ if(xxx_pGLOBAL_SQLPARSER->inPredicateCheck())// boolean_primary: rule 3
+ {
+ $$ = SQL_NEW_RULE;
+ sal_Int16 nErg = 0;
+ if ( SQL_ISTOKEN( $1, NULL))
+ {
+ OSQLParseNode* pColumnRef = newNode("", SQLNodeType::Rule,OSQLParser::RuleID(OSQLParseNode::column_ref));
+ pColumnRef->append(newNode(xxx_pGLOBAL_SQLPARSER->getFieldName(),SQLNodeType::Name));
+ OSQLParseNode* pTFN = new OSQLInternalNode("", SQLNodeType::Rule,OSQLParser::RuleID(OSQLParseNode::test_for_null));
+ pTFN->append(pColumnRef);
+
+ OSQLParseNode* pNPP2 = new OSQLInternalNode("", SQLNodeType::Rule, OSQLParser::RuleID(OSQLParseNode::null_predicate_part_2));
+ pNPP2->append(new OSQLInternalNode("", SQLNodeType::Keyword, SQL_TOKEN_IS));
+ pNPP2->append(new OSQLInternalNode("", SQLNodeType::Rule, OSQLParser::RuleID(OSQLParseNode::sql_not)));
+ pNPP2->append(new OSQLInternalNode("", SQLNodeType::Keyword, SQL_TOKEN_NULL));
+ pTFN->append(pNPP2);
+
+ $$->append(pTFN);
+
+ nErg = 1;
+ }
+ else
+ {
+ nErg = xxx_pGLOBAL_SQLPARSER->buildComparisonRule($$,$1);
+ }
+ if(nErg == 1)
+ {
+ OSQLParseNode* pTemp = $$;
+ $$ = pTemp->removeAt((sal_uInt32)0);
+ delete pTemp;
+ }
+ else
+ {
+ delete $$;
+ if(nErg)
+ YYERROR;
+ else
+ YYABORT;
+ }
+ }
+ else
+ YYERROR;
+ }
+ ;
+parenthesized_boolean_value_expression:
+ '(' search_condition ')'
+ { // boolean_primary: rule 2
+ $$ = SQL_NEW_RULE;
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($2);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ ;
+boolean_factor:
+ boolean_primary %dprec 2
+ | SQL_TOKEN_NOT boolean_primary %dprec 1
+ { // boolean_factor: rule 1
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+boolean_term:
+ boolean_factor
+ | boolean_term SQL_TOKEN_AND boolean_factor
+ {
+ $$ = SQL_NEW_RULE; // boolean_term: rule 1
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ ;
+search_condition:
+ boolean_term
+ | search_condition SQL_TOKEN_OR boolean_term
+ {
+ $$ = SQL_NEW_RULE; // search_condition
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ ;
+predicate:
+ comparison_predicate %dprec 1
+ | between_predicate
+ | all_or_any_predicate
+ | existence_test
+ | unique_test
+ | test_for_null %dprec 2
+ | in_predicate
+ | like_predicate
+ ;
+comparison_predicate_part_2:
+ comparison row_value_constructor
+ {
+ $$ = SQL_NEW_RULE; // comparison_predicate: rule 1
+ $$->append($1);
+ $$->append($2);
+ }
+comparison_predicate:
+ row_value_constructor comparison row_value_constructor
+ {
+ $$ = SQL_NEW_RULE; // comparison_predicate: rule 1
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ | comparison row_value_constructor
+ {
+ if(xxx_pGLOBAL_SQLPARSER->inPredicateCheck()) // comparison_predicate: rule 2
+ {
+ $$ = SQL_NEW_RULE;
+ sal_Int16 nErg = xxx_pGLOBAL_SQLPARSER->buildPredicateRule($$,$2,$1);
+ if(nErg == 1)
+ {
+ OSQLParseNode* pTemp = $$;
+ $$ = pTemp->removeAt((sal_uInt32)0);
+ delete pTemp;
+ }
+ else
+ {
+ delete $$;
+ YYABORT;
+ }
+ }
+ else
+ {
+ YYERROR;
+ }
+ }
+ ;
+comparison:
+ SQL_LESS
+ | SQL_NOTEQUAL
+ | SQL_EQUAL
+ | SQL_GREAT
+ | SQL_LESSEQ
+ | SQL_GREATEQ
+ | SQL_TOKEN_IS sql_not SQL_TOKEN_DISTINCT SQL_TOKEN_FROM
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ }
+ | SQL_TOKEN_IS sql_not
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+between_predicate_part_2:
+ sql_not SQL_TOKEN_BETWEEN row_value_constructor SQL_TOKEN_AND row_value_constructor
+ {
+ if (xxx_pGLOBAL_SQLPARSER->inPredicateCheck()) // between_predicate: rule 2
+ {
+ $$ = SQL_NEW_RULE;
+
+ sal_Int16 nErg = xxx_pGLOBAL_SQLPARSER->buildPredicateRule($$,$3,$2,$5);
+ if(nErg == 1)
+ {
+ OSQLParseNode* pTemp = $$;
+ $$ = pTemp->removeAt((sal_uInt32)0);
+ OSQLParseNode* pColumnRef = $$->removeAt((sal_uInt32)0);
+ $$->insert(0,$1);
+ OSQLParseNode* pBetween_predicate = new OSQLInternalNode("", SQLNodeType::Rule,OSQLParser::RuleID(OSQLParseNode::between_predicate));
+ pBetween_predicate->append(pColumnRef);
+ pBetween_predicate->append($$);
+ $$ = pBetween_predicate;
+
+ delete pTemp;
+ delete $4;
+ }
+ else
+ {
+ delete $$;
+ YYABORT;
+ }
+ }
+ else
+ {
+ $$ = SQL_NEW_RULE; // between_predicate: rule 1
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ $$->append($5);
+ }
+ }
+between_predicate:
+ row_value_constructor between_predicate_part_2
+ {
+ $$ = SQL_NEW_RULE; // between_predicate: rule 1
+ $$->append($1);
+ $$->append($2);
+ }
+ | between_predicate_part_2
+ ;
+character_like_predicate_part_2:
+ sql_not SQL_TOKEN_LIKE string_value_exp opt_escape
+ {
+ $$ = SQL_NEW_RULE; // like_predicate: rule 1
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ }
+ ;
+other_like_predicate_part_2:
+ sql_not SQL_TOKEN_LIKE value_exp_primary opt_escape
+ {
+ $$ = SQL_NEW_RULE; // like_predicate: rule 1
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ }
+ ;
+like_predicate:
+ row_value_constructor character_like_predicate_part_2
+ {
+ $$ = SQL_NEW_RULE; // like_predicate: rule 1
+ $$->append($1);
+ $$->append($2);
+ }
+ | row_value_constructor other_like_predicate_part_2
+ {
+ $$ = SQL_NEW_RULE; // like_predicate: rule 3
+ $$->append($1);
+ $$->append($2);
+ }
+ | character_like_predicate_part_2
+ {
+ if (xxx_pGLOBAL_SQLPARSER->inPredicateCheck()) // like_predicate: rule 5
+ {
+ OSQLParseNode* pColumnRef = newNode("", SQLNodeType::Rule,OSQLParser::RuleID(OSQLParseNode::column_ref));
+ pColumnRef->append(newNode(xxx_pGLOBAL_SQLPARSER->getFieldName(),SQLNodeType::Name));
+
+ $$ = SQL_NEW_RULE;
+ $$->append(pColumnRef);
+ $$->append($1);
+ OSQLParseNode* p2nd = $1->removeAt(2);
+ OSQLParseNode* p3rd = $1->removeAt(2);
+ if ( !xxx_pGLOBAL_SQLPARSER->buildLikeRule($1,p2nd,p3rd) )
+ {
+ delete $$;
+ YYABORT;
+ }
+ $1->append(p3rd);
+ }
+ else
+ YYERROR;
+ }
+ | other_like_predicate_part_2
+ {
+ if (xxx_pGLOBAL_SQLPARSER->inPredicateCheck()) // like_predicate: rule 6
+ {
+ OSQLParseNode* pColumnRef = newNode("", SQLNodeType::Rule,OSQLParser::RuleID(OSQLParseNode::column_ref));
+ pColumnRef->append(newNode(xxx_pGLOBAL_SQLPARSER->getFieldName(),SQLNodeType::Name));
+
+ $$ = SQL_NEW_RULE;
+ $$->append(pColumnRef);
+ $$->append($1);
+ OSQLParseNode* p2nd = $1->removeAt(2);
+ OSQLParseNode* p3rd = $1->removeAt(2);
+ if ( !xxx_pGLOBAL_SQLPARSER->buildLikeRule($1,p2nd,p3rd) )
+ {
+ delete $$;
+ YYABORT;
+ }
+ $1->append(p3rd);
+ }
+ else
+ YYERROR;
+ }
+ ;
+
+opt_escape:
+ /* empty */ {$$ = SQL_NEW_RULE;}
+ | SQL_TOKEN_ESCAPE string_value_exp
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);}
+ | '{' SQL_TOKEN_ESCAPE SQL_TOKEN_STRING '}'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append(newNode("{", SQLNodeType::Punctuation));
+ $$->append($2);
+ $$->append($3);
+ $$->append(newNode("}", SQLNodeType::Punctuation));
+ }
+ ;
+
+null_predicate_part_2:
+ SQL_TOKEN_IS sql_not SQL_TOKEN_NULL
+ {
+ $$ = SQL_NEW_RULE; // test_for_null: rule 1
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ | SQL_TOKEN_IS sql_not SQL_TOKEN_UNKNOWN
+ {
+ $$ = SQL_NEW_RULE; // test_for_null: rule 1
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ ;
+test_for_null:
+ row_value_constructor null_predicate_part_2
+ {
+ $$ = SQL_NEW_RULE; // test_for_null: rule 1
+ $$->append($1);
+ $$->append($2);
+ }
+ | null_predicate_part_2
+ {
+ if (xxx_pGLOBAL_SQLPARSER->inPredicateCheck())// test_for_null: rule 2
+ {
+ OSQLParseNode* pColumnRef = newNode("", SQLNodeType::Rule,OSQLParser::RuleID(OSQLParseNode::column_ref));
+ pColumnRef->append(newNode(xxx_pGLOBAL_SQLPARSER->getFieldName(),SQLNodeType::Name));
+
+ $$ = SQL_NEW_RULE;
+ $$->append(pColumnRef);
+ $$->append($1);
+ }
+ else
+ YYERROR;
+ }
+ ;
+in_predicate_value:
+ subquery
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+ | '(' value_exp_commalist ')'
+ {$$ = SQL_NEW_RULE;
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($2);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ ;
+in_predicate_part_2:
+ sql_not SQL_TOKEN_IN in_predicate_value
+ {
+ $$ = SQL_NEW_RULE;// in_predicate: rule 1
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ ;
+in_predicate:
+ row_value_constructor in_predicate_part_2
+ {
+ $$ = SQL_NEW_RULE;// in_predicate: rule 1
+ $$->append($1);
+ $$->append($2);
+ }
+ | in_predicate_part_2
+ {
+ if ( xxx_pGLOBAL_SQLPARSER->inPredicateCheck() )// in_predicate: rule 2
+ {
+ OSQLParseNode* pColumnRef = newNode("", SQLNodeType::Rule,OSQLParser::RuleID(OSQLParseNode::column_ref));
+ pColumnRef->append(newNode(xxx_pGLOBAL_SQLPARSER->getFieldName(),SQLNodeType::Name));
+
+ $$ = SQL_NEW_RULE;
+ $$->append(pColumnRef);
+ $$->append($1);
+ }
+ else
+ YYERROR;
+ }
+ ;
+quantified_comparison_predicate_part_2:
+ comparison any_all_some subquery
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ ;
+all_or_any_predicate:
+ row_value_constructor quantified_comparison_predicate_part_2
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ | quantified_comparison_predicate_part_2
+ {
+ if(xxx_pGLOBAL_SQLPARSER->inPredicateCheck())
+ {
+ OSQLParseNode* pColumnRef = newNode("", SQLNodeType::Rule,OSQLParser::RuleID(OSQLParseNode::column_ref));
+ pColumnRef->append(newNode(xxx_pGLOBAL_SQLPARSER->getFieldName(),SQLNodeType::Name));
+
+ $$ = SQL_NEW_RULE;
+ $$->append(pColumnRef);
+ $$->append($1);
+ }
+ else
+ YYERROR;
+ }
+ ;
+
+any_all_some:
+ SQL_TOKEN_ANY
+ | SQL_TOKEN_ALL
+ | SQL_TOKEN_SOME
+ ;
+
+existence_test:
+ SQL_TOKEN_EXISTS subquery
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);}
+ ;
+unique_test:
+ SQL_TOKEN_UNIQUE subquery
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);}
+ ;
+subquery:
+ '(' query_exp ')'
+ {$$ = SQL_NEW_RULE;
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($2);
+ $$->append(newNode(")", SQLNodeType::Punctuation));}
+ ;
+
+ /* scalar expressions */
+scalar_exp_commalist:
+ select_sublist
+ {
+ $$ = SQL_NEW_COMMALISTRULE;
+ $$->append($1);
+ }
+ | scalar_exp_commalist ',' select_sublist
+ {
+ $1->append($3);
+ $$ = $1;
+ }
+ ;
+select_sublist:
+/* table_node '.' '*'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode(".", SQLNodeType::Punctuation));
+ $$->append(newNode("*", SQLNodeType::Punctuation));
+ }
+*/
+ derived_column
+
+ ;
+
+parameter_ref:
+ parameter
+ ;
+
+/*
+op_like:
+ '*'
+ {
+ $$ = newNode("*", SQLNodeType::Punctuation);
+ }
+ | '?'
+ {
+ $$ = newNode("?", SQLNodeType::Punctuation);
+ }
+ | op_like '*'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("*", SQLNodeType::Punctuation));
+ xxx_pGLOBAL_SQLPARSER->reduceLiteral($$, sal_False);
+ }
+ | op_like '?'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("?", SQLNodeType::Punctuation));
+ xxx_pGLOBAL_SQLPARSER->reduceLiteral($$, sal_False);
+ }
+ ;
+*/
+
+literal:
+/* SQL_TOKEN_STRING
+ | */SQL_TOKEN_INT
+ | SQL_TOKEN_REAL_NUM
+ | SQL_TOKEN_INTNUM
+ | SQL_TOKEN_APPROXNUM
+ | SQL_TOKEN_ACCESS_DATE
+/* rules for predicate check */
+ | literal SQL_TOKEN_STRING
+ {
+ if (xxx_pGLOBAL_SQLPARSER->inPredicateCheck())
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ OSQLParser::reduceLiteral($$, true);
+ }
+ else
+ YYERROR;
+ }
+ | literal SQL_TOKEN_INT
+ {
+ if (xxx_pGLOBAL_SQLPARSER->inPredicateCheck())
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ OSQLParser::reduceLiteral($$, true);
+ }
+ else
+ YYERROR;
+ }
+ | literal SQL_TOKEN_REAL_NUM
+ {
+ if (xxx_pGLOBAL_SQLPARSER->inPredicateCheck())
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ OSQLParser::reduceLiteral($$, true);
+ }
+ else
+ YYERROR;
+ }
+ | literal SQL_TOKEN_APPROXNUM
+ {
+ if (xxx_pGLOBAL_SQLPARSER->inPredicateCheck())
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ OSQLParser::reduceLiteral($$, true);
+ }
+ else
+ YYERROR;
+ }
+ ;
+
+ /* miscellaneous */
+as_clause:
+ /* empty */ {$$ = SQL_NEW_RULE;}
+ | SQL_TOKEN_AS column
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ | column
+ ;
+position_exp:
+ SQL_TOKEN_POSITION '(' value_exp SQL_TOKEN_IN value_exp ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append($4);
+ $$->append($5);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ | SQL_TOKEN_POSITION '(' value_exp_commalist ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ ;
+num_value_fct:
+ position_exp
+ | extract_exp
+ | length_exp
+ ;
+char_length_exp:
+ SQL_TOKEN_CHAR_LENGTH '(' value_exp ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ | SQL_TOKEN_SQL_TOKEN_INTNUM '(' value_exp ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+
+ ;
+octet_length_exp:
+ SQL_TOKEN_OCTET_LENGTH '(' value_exp ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ ;
+bit_length_exp:
+ SQL_TOKEN_BIT_LENGTH '(' value_exp ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ ;
+length_exp:
+ char_length_exp
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+ | octet_length_exp
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+ | bit_length_exp
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+ ;
+datetime_field:
+ non_second_datetime_field
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+ | SQL_TOKEN_SECOND
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+ ;
+extract_field:
+ time_zone_field
+ | datetime_field
+ | value_exp
+ ;
+time_zone_field:
+ SQL_TOKEN_TIMEZONE_HOUR
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+ | SQL_TOKEN_TIMEZONE_MINUTE
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+ ;
+extract_exp:
+ SQL_TOKEN_EXTRACT '(' extract_field SQL_TOKEN_FROM value_exp ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append($4);
+ $$->append($5);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ ;
+unsigned_value_spec:
+ general_value_spec
+ | literal
+ ;
+general_value_spec:
+ parameter
+ | SQL_TOKEN_USER
+ | SQL_TOKEN_NULL
+ | SQL_TOKEN_FALSE
+ | SQL_TOKEN_TRUE
+ | SQL_TOKEN_VALUE
+ | SQL_TOKEN_CURRENT_CATALOG
+ | SQL_TOKEN_CURRENT_DEFAULT_TRANSFORM_GROUP
+ | SQL_TOKEN_CURRENT_PATH
+ | SQL_TOKEN_CURRENT_ROLE
+ | SQL_TOKEN_CURRENT_SCHEMA
+ | SQL_TOKEN_CURRENT_USER
+ | SQL_TOKEN_SESSION_USER
+ | SQL_TOKEN_SYSTEM_USER
+ ;
+set_fct_spec:
+ general_set_fct
+ | '{' odbc_fct_spec '}'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append(newNode("{", SQLNodeType::Punctuation));
+ $$->append($2);
+ $$->append(newNode("}", SQLNodeType::Punctuation));
+ }
+ | function_name '(' ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ | function_name0 '(' ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ | function_name1 '(' function_arg ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ | function_name2 '(' function_arg_commalist2 ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ | function_name3 '(' function_arg_commalist3 ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ | string_function_4Argument '(' function_arg_commalist4 ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ | function_name '(' function_args_commalist ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ | function_name12 '(' function_args_commalist ')'
+ {
+ if ( $3->count() == 1 || $3->count() == 2 )
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ else
+ YYERROR;
+ }
+ | function_name23 '(' function_args_commalist ')'
+ {
+ if ( $3->count() == 2 || $3->count() == 3)
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ else
+ YYERROR;
+ }
+ ;
+function_name0:
+ date_function_0Argument
+ | numeric_function_0Argument
+ ;
+function_name1:
+ string_function_1Argument
+ | date_function_1Argument
+ | numeric_function_1Argument
+ ;
+function_name2:
+ string_function_2Argument
+ | numeric_function_2Argument
+ ;
+function_name12:
+ SQL_TOKEN_ROUND
+ | SQL_TOKEN_WEEK
+ | SQL_TOKEN_LOGF
+ | SQL_TOKEN_LOG
+ ;
+function_name23:
+ SQL_TOKEN_LOCATE
+ | SQL_TOKEN_DATEDIFF
+ ;
+function_name3:
+ string_function_3Argument
+ ;
+function_name:
+ string_function
+ | date_function
+ | numeric_function
+ | SQL_TOKEN_NAME
+ ;
+string_function_1Argument:
+ SQL_TOKEN_LENGTH
+ | SQL_TOKEN_ASCII
+ | SQL_TOKEN_LCASE
+ | SQL_TOKEN_LTRIM
+ | SQL_TOKEN_RTRIM
+ | SQL_TOKEN_SPACE
+ | SQL_TOKEN_UCASE
+ ;
+
+string_function_2Argument:
+ SQL_TOKEN_REPEAT
+ | SQL_TOKEN_LEFT
+ | SQL_TOKEN_RIGHT
+ ;
+string_function_3Argument:
+ SQL_TOKEN_REPLACE
+ ;
+string_function_4Argument:
+ SQL_TOKEN_INSERT
+ ;
+
+string_function:
+ SQL_TOKEN_CHAR
+ | SQL_TOKEN_CONCAT
+ | SQL_TOKEN_DIFFERENCE
+ | SQL_TOKEN_LOCATE_2
+ | SQL_TOKEN_SOUNDEX
+ ;
+date_function_0Argument:
+ SQL_TOKEN_CURDATE
+ | SQL_TOKEN_CURTIME
+ | SQL_TOKEN_NOW
+ ;
+date_function_1Argument:
+ SQL_TOKEN_DAYOFWEEK
+ | SQL_TOKEN_DAYOFMONTH
+ | SQL_TOKEN_DAYOFYEAR
+ | SQL_TOKEN_MONTH
+ | SQL_TOKEN_DAYNAME
+ | SQL_TOKEN_MONTHNAME
+ | SQL_TOKEN_QUARTER
+ | SQL_TOKEN_HOUR
+ | SQL_TOKEN_MINUTE
+ | SQL_TOKEN_SECOND
+ | SQL_TOKEN_YEAR
+ | SQL_TOKEN_DAY
+ | SQL_TOKEN_TIMEVALUE
+ | SQL_TOKEN_DATEVALUE
+ ;
+
+date_function:
+ SQL_TOKEN_TIMESTAMPADD
+ | SQL_TOKEN_TIMESTAMPDIFF
+ | SQL_TOKEN_DATEADD
+ ;
+numeric_function_0Argument:
+ SQL_TOKEN_PI
+ ;
+numeric_function_1Argument:
+ SQL_TOKEN_ABS
+ | SQL_TOKEN_ACOS
+ | SQL_TOKEN_ASIN
+ | SQL_TOKEN_ATAN
+ | SQL_TOKEN_CEILING
+ | SQL_TOKEN_COS
+ | SQL_TOKEN_COT
+ | SQL_TOKEN_DEGREES
+ | SQL_TOKEN_FLOOR
+ | SQL_TOKEN_SIGN
+ | SQL_TOKEN_SIN
+ | SQL_TOKEN_SQRT
+ | SQL_TOKEN_TAN
+ | SQL_TOKEN_EXP
+ | SQL_TOKEN_LOG10
+ | SQL_TOKEN_LN
+ | SQL_TOKEN_RADIANS
+ | SQL_TOKEN_ROUNDMAGIC
+ ;
+numeric_function_2Argument:
+ SQL_TOKEN_ATAN2
+ | SQL_TOKEN_MOD
+ | SQL_TOKEN_POWER
+ ;
+numeric_function:
+ SQL_TOKEN_RAND
+ | SQL_TOKEN_TRUNCATE
+ ;
+
+window_function:
+ window_function_type SQL_TOKEN_OVER window_name_or_specification
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ ;
+window_function_type :
+ rank_function_type '(' ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ | SQL_TOKEN_ROW_NUMBER '(' ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ | general_set_fct
+ | ntile_function
+ | lead_or_lag_function
+ | first_or_last_value_function
+ | nth_value_function
+;
+ntile_function :
+ SQL_TOKEN_NTILE '(' number_of_tiles ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ ;
+dynamic_parameter_specification:
+ parameter
+ ;
+simple_value_specification:
+ literal
+ ;
+number_of_tiles :
+ simple_value_specification
+ | dynamic_parameter_specification
+ ;
+opt_lead_or_lag_function:
+ /* empty */ {$$ = SQL_NEW_RULE;}
+ | ',' offset
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append(newNode(",", SQLNodeType::Punctuation));
+ $$->append($2);
+ }
+ | ',' offset ',' default_expression
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append(newNode(",", SQLNodeType::Punctuation));
+ $$->append($2);
+ $$->append(newNode(",", SQLNodeType::Punctuation));
+ $$->append($4);
+ }
+ ;
+opt_null_treatment:
+ /* empty */ {$$ = SQL_NEW_RULE;}
+ | null_treatment
+ ;
+
+lead_or_lag_function:
+ lead_or_lag '(' lead_or_lag_extent opt_lead_or_lag_function ')' opt_null_treatment
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append($4);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ $$->append($6);
+ }
+ ;
+lead_or_lag:
+ SQL_TOKEN_LEAD
+ | SQL_TOKEN_LAG
+ ;
+lead_or_lag_extent:
+ value_exp
+ ;
+offset:
+ SQL_TOKEN_INTNUM
+ ;
+default_expression:
+ value_exp
+ ;
+null_treatment:
+ SQL_TOKEN_RESPECT SQL_TOKEN_NULLS
+ | SQL_TOKEN_IGNORE SQL_TOKEN_NULLS
+ ;
+first_or_last_value_function:
+ first_or_last_value '(' value_exp ')' opt_null_treatment
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ $$->append($5);
+ }
+ ;
+first_or_last_value :
+ SQL_TOKEN_FIRST_VALUE
+ | SQL_TOKEN_LAST_VALUE
+ ;
+opt_from_first_or_last:
+ /* empty */ {$$ = SQL_NEW_RULE;}
+ | from_first_or_last
+ ;
+nth_value_function:
+ SQL_TOKEN_NTH_VALUE '(' value_exp ',' nth_row ')' opt_from_first_or_last opt_null_treatment
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(",", SQLNodeType::Punctuation));
+ $$->append($5);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ $$->append($7);
+ $$->append($8);
+ }
+ ;
+nth_row:
+ simple_value_specification
+ | dynamic_parameter_specification
+ ;
+from_first_or_last:
+ SQL_TOKEN_FROM SQL_TOKEN_FIRST
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ | SQL_TOKEN_FROM SQL_TOKEN_LAST
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+window_name:
+ SQL_TOKEN_NAME
+ ;
+window_name_or_specification:
+ window_name
+ | in_line_window_specification
+ ;
+in_line_window_specification:
+ window_specification
+ ;
+opt_window_clause:
+ /* empty */ {$$ = SQL_NEW_RULE;}
+ | window_clause
+ ;
+window_clause:
+ SQL_TOKEN_WINDOW window_definition_list
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+window_definition_list:
+ window_definition_list ',' window_definition
+ {$1->append($3);
+ $$ = $1;}
+ | window_definition
+ {$$ = SQL_NEW_COMMALISTRULE;
+ $$->append($1);}
+ ;
+window_definition:
+ new_window_name SQL_TOKEN_AS window_specification
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ ;
+new_window_name:
+ window_name
+ ;
+window_specification:
+ '('
+ opt_existing_window_name
+ opt_window_partition_clause
+ opt_order_by_clause
+ opt_window_frame_clause
+ ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ $$->append($5);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ ;
+opt_existing_window_name:
+ /* empty */ {$$ = SQL_NEW_RULE;}
+ | existing_window_name
+ ;
+opt_window_partition_clause:
+ /* empty */ {$$ = SQL_NEW_RULE;}
+ | window_partition_clause
+ ;
+opt_window_frame_clause:
+ /* empty */ {$$ = SQL_NEW_RULE;}
+ | window_frame_clause
+ ;
+existing_window_name:
+ window_name
+ ;
+window_partition_clause:
+ SQL_TOKEN_PARTITION SQL_TOKEN_BY window_partition_column_reference_list
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ ;
+window_partition_column_reference_list:
+ window_partition_column_reference_list ',' window_partition_column_reference
+ {$1->append($3);
+ $$ = $1;}
+ | window_partition_column_reference
+ {$$ = SQL_NEW_COMMALISTRULE;
+ $$->append($1);}
+ ;
+window_partition_column_reference:
+ column_ref opt_collate_clause
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+opt_window_frame_exclusion:
+ /* empty */ {$$ = SQL_NEW_RULE;}
+ | window_frame_exclusion
+ ;
+window_frame_clause:
+ window_frame_units window_frame_extent opt_window_frame_exclusion
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ ;
+window_frame_units:
+ SQL_TOKEN_ROWS
+ | SQL_TOKEN_RANGE
+ ;
+window_frame_extent:
+ window_frame_start
+ | window_frame_between
+ ;
+window_frame_start:
+ SQL_TOKEN_UNBOUNDED SQL_TOKEN_PRECEDING
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ | window_frame_preceding
+ | SQL_TOKEN_CURRENT SQL_TOKEN_ROW
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+window_frame_preceding:
+ unsigned_value_spec SQL_TOKEN_PRECEDING
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+window_frame_between:
+ SQL_TOKEN_BETWEEN window_frame_bound_1 SQL_TOKEN_AND window_frame_bound_2
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ }
+ ;
+window_frame_bound_1:
+ window_frame_bound
+ ;
+window_frame_bound_2:
+ window_frame_bound
+ ;
+window_frame_bound:
+ window_frame_start
+ | SQL_TOKEN_UNBOUNDED SQL_TOKEN_FOLLOWING
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ | window_frame_following
+ ;
+window_frame_following:
+ unsigned_value_spec SQL_TOKEN_FOLLOWING
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+window_frame_exclusion:
+ SQL_TOKEN_EXCLUDE SQL_TOKEN_CURRENT SQL_TOKEN_ROW
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ | SQL_TOKEN_EXCLUDE SQL_TOKEN_GROUP
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ | SQL_TOKEN_EXCLUDE SQL_TOKEN_TIES
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ | SQL_TOKEN_EXCLUDE SQL_TOKEN_NO SQL_TOKEN_OTHERS
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ ;
+op_parameter:
+ {$$ = SQL_NEW_RULE;}
+ | '?' SQL_EQUAL
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append(newNode("?", SQLNodeType::Punctuation));
+ $$->append($2);
+ }
+ ;
+odbc_call_spec:
+ op_parameter SQL_TOKEN_CALL table_node op_odbc_call_parameter
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ }
+ ;
+
+op_odbc_call_parameter:
+ {$$ = SQL_NEW_RULE;}
+ | '(' odbc_parameter_commalist ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($2);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ ;
+
+odbc_parameter_commalist:
+ odbc_parameter
+ {$$ = SQL_NEW_COMMALISTRULE;
+ $$->append($1);}
+ | odbc_parameter_commalist ',' odbc_parameter
+ {
+ $1->append($3);
+ $$ = $1;
+ }
+ ;
+odbc_parameter:
+ /* empty */ {$$ = SQL_NEW_RULE;}
+ | literal
+ | parameter
+ ;
+
+odbc_fct_spec:
+ odbc_fct_type SQL_TOKEN_STRING
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ | SQL_TOKEN_FN set_fct_spec
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+
+odbc_fct_type:
+ SQL_TOKEN_D
+ | SQL_TOKEN_T
+ | SQL_TOKEN_TS
+ ;
+
+general_set_fct:
+ set_fct_type '(' opt_all_distinct function_arg ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append($4);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ | SQL_TOKEN_COUNT '(' '*' ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append(newNode("*", SQLNodeType::Punctuation));
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ | SQL_TOKEN_COUNT '(' opt_all_distinct function_arg ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append($4);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ | ordered_set_function
+ | array_aggregate_function
+ ;
+set_fct_type:
+ SQL_TOKEN_AVG
+ | SQL_TOKEN_MAX
+ | SQL_TOKEN_MIN
+ | SQL_TOKEN_SUM
+ | SQL_TOKEN_EVERY
+ | SQL_TOKEN_ANY
+ | SQL_TOKEN_SOME
+ | SQL_TOKEN_STDDEV_POP
+ | SQL_TOKEN_STDDEV_SAMP
+ | SQL_TOKEN_VAR_SAMP
+ | SQL_TOKEN_VAR_POP
+ | SQL_TOKEN_COLLECT
+ | SQL_TOKEN_FUSION
+ | SQL_TOKEN_INTERSECTION
+ ;
+
+ordered_set_function:
+ hypothetical_set_function
+ | inverse_distribution_function
+ ;
+hypothetical_set_function:
+ rank_function_type '(' hypothetical_set_function_value_expression_list ')' within_group_specification
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ $$->append($5);
+ }
+ | rank_function_type '(' hypothetical_set_function_value_expression_list SQL_TOKEN_BY value_exp_commalist ')' within_group_specification
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append($4);
+ $$->append($5);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ $$->append($7);
+ }
+ ;
+
+within_group_specification:
+ {
+ $$ = SQL_NEW_RULE;
+ }
+ | SQL_TOKEN_WITHIN SQL_TOKEN_GROUP '(' opt_order_by_clause ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($4);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ ;
+hypothetical_set_function_value_expression_list:
+ value_exp_commalist
+ ;
+
+inverse_distribution_function:
+ inverse_distribution_function_type '('inverse_distribution_function_argument ')' within_group_specification
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ ;
+inverse_distribution_function_argument:
+ num_value_exp
+ ;
+inverse_distribution_function_type:
+ SQL_TOKEN_PERCENTILE_CONT
+ | SQL_TOKEN_PERCENTILE_DISC
+ ;
+
+array_aggregate_function:
+ SQL_TOKEN_ARRAY_AGG '(' value_exp opt_order_by_clause ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append($4);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ ;
+
+rank_function_type:
+ SQL_TOKEN_RANK
+ | SQL_TOKEN_DENSE_RANK
+ | SQL_TOKEN_PERCENT_RANK
+ | SQL_TOKEN_CUME_DIST
+ ;
+outer_join_type:
+ SQL_TOKEN_LEFT %prec SQL_TOKEN_LEFT
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+ | SQL_TOKEN_RIGHT %prec SQL_TOKEN_RIGHT
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+ | SQL_TOKEN_FULL %prec SQL_TOKEN_FULL
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+ ;
+join_condition:
+ SQL_TOKEN_ON search_condition
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+join_spec:
+ join_condition
+ | named_columns_join
+ ;
+join_type:
+ /* empty */ {$$ = SQL_NEW_RULE;}
+ | SQL_TOKEN_INNER
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+ | outer_join_type
+ | outer_join_type SQL_TOKEN_OUTER
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+cross_union:
+ table_ref SQL_TOKEN_CROSS SQL_TOKEN_JOIN table_ref
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ }
+ ;
+
+qualified_join:
+ /* when SQL_TOKEN_NATURAL, then no join_spec */
+ table_ref SQL_TOKEN_NATURAL join_type SQL_TOKEN_JOIN table_ref
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ $$->append($5);
+ }
+ | table_ref join_type SQL_TOKEN_JOIN table_ref join_spec
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ $$->append($5);
+ }
+ | cross_union
+ ;
+joined_table:
+ qualified_join
+ ;
+named_columns_join:
+ SQL_TOKEN_USING '(' column_commalist ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ ;
+simple_table:
+ select_statement
+ | values_or_query_spec
+ ;
+
+non_join_query_primary:
+ simple_table
+ | '(' non_join_query_exp ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($2);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ ;
+non_join_query_term:
+ non_join_query_primary
+ | query_term SQL_TOKEN_INTERSECT all query_primary
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ }
+ ;
+query_primary:
+ non_join_query_primary
+ ;
+non_join_query_exp:
+ non_join_query_term
+ | query_exp SQL_TOKEN_UNION all query_term
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ }
+ | query_exp SQL_TOKEN_EXCEPT all query_term
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ }
+ ;
+all:
+ /* empty*/ {$$ = SQL_NEW_RULE;}
+ | SQL_TOKEN_ALL
+ ;
+query_exp:
+ non_join_query_exp /*[^')']*/
+ ;
+scalar_subquery:
+ subquery
+ ;
+cast_operand:
+ value_exp
+ ;
+cast_target:
+ table_node
+ | data_type
+ ;
+cast_spec:
+ SQL_TOKEN_CAST '(' cast_operand SQL_TOKEN_AS cast_target ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append($4);
+ $$->append($5);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ ;
+value_exp_primary:
+ unsigned_value_spec
+ | column_ref
+ | set_fct_spec
+ | scalar_subquery
+ | case_expression
+ | window_function
+ | '(' value_exp ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($2);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ | cast_spec
+ ;
+
+num_primary:
+ value_exp_primary
+ | num_value_fct
+ ;
+factor:
+ num_primary
+ | '-' num_primary %prec SQL_TOKEN_UMINUS
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append(newNode("-", SQLNodeType::Punctuation));
+ $$->append($2);
+ }
+ | '+' num_primary %prec SQL_TOKEN_UMINUS
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append(newNode("+", SQLNodeType::Punctuation));
+ $$->append($2);
+ }
+ ;
+
+term:
+ factor
+ | term '*' factor
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("*", SQLNodeType::Punctuation));
+ $$->append($3);
+ }
+ | term '/' factor
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("/", SQLNodeType::Punctuation));
+ $$->append($3);
+ }
+ ;
+
+num_value_exp:
+ term
+ | num_value_exp '+' term
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("+", SQLNodeType::Punctuation));
+ $$->append($3);
+ }
+ | num_value_exp '-' term
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("-", SQLNodeType::Punctuation));
+ $$->append($3);
+ }
+ ;
+datetime_primary:
+/* value_exp_primary
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+ |*/ datetime_value_fct
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+ ;
+datetime_value_fct:
+ SQL_TOKEN_CURRENT_DATE
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+ | SQL_TOKEN_CURRENT_TIME
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+ | SQL_TOKEN_CURRENT_TIMESTAMP
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+ ;
+time_zone:
+ SQL_TOKEN_AT time_zone_specifier
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+time_zone_specifier:
+ SQL_TOKEN_LOCAL
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+/* | SQL_TOKEN_TIME SQL_TOKEN_ZONE interval_value_exp
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }*/
+ ;
+datetime_factor:
+ datetime_primary
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+ | datetime_primary time_zone
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+datetime_term:
+ datetime_factor
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+ ;
+/*
+interval_term:
+ literal
+ | interval_term '*' factor
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("*", SQLNodeType::Punctuation));
+ $$->append($3);
+ }
+ | interval_term '/' factor
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("/", SQLNodeType::Punctuation));
+ $$->append($3);
+ }
+ ;
+*/
+datetime_value_exp:
+ datetime_term
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+/* | interval_value_exp '+' datetime_term
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("+", SQLNodeType::Punctuation));
+ $$->append($3);
+ }
+ | datetime_value_exp '+' interval_term
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("+", SQLNodeType::Punctuation));
+ $$->append($3);
+ }
+ | datetime_value_exp '-' interval_term
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("-", SQLNodeType::Punctuation));
+ $$->append($3);
+ }
+*/ ;
+/*
+interval_value_exp:
+ interval_term
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+ | interval_value_exp '+' interval_term
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("+", SQLNodeType::Punctuation));
+ $$->append($3);
+ }
+ | interval_value_exp '-' interval_term
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("-", SQLNodeType::Punctuation));
+ $$->append($3);
+ }
+ | '(' datetime_value_exp '-' datetime_term ')' interval_qualifier
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($2);
+ $$->append(newNode("-", SQLNodeType::Punctuation));
+ $$->append($4);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ $$->append($6);
+ }
+ ;
+*/
+non_second_datetime_field:
+ SQL_TOKEN_YEAR
+ | SQL_TOKEN_YEARDAY
+ | SQL_TOKEN_MONTH
+ | SQL_TOKEN_WEEK
+ | SQL_TOKEN_WEEKDAY
+ | SQL_TOKEN_DAY
+ | SQL_TOKEN_HOUR
+ | SQL_TOKEN_MINUTE
+ | SQL_TOKEN_MILLISECOND
+ ;
+
+datetime_unit:
+ SQL_TOKEN_YEAR
+ | SQL_TOKEN_MONTH
+ | SQL_TOKEN_WEEK
+ | SQL_TOKEN_DAY
+ | SQL_TOKEN_HOUR
+ | SQL_TOKEN_MINUTE
+ | SQL_TOKEN_SECOND
+ | SQL_TOKEN_MILLISECOND
+ ;
+
+start_field:
+ non_second_datetime_field opt_paren_precision
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+end_field:
+ non_second_datetime_field
+ | SQL_TOKEN_SECOND opt_paren_precision
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+
+single_datetime_field:
+ non_second_datetime_field opt_paren_precision
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ | SQL_TOKEN_SECOND opt_paren_precision_scale
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+
+interval_qualifier:
+ start_field SQL_TOKEN_TO end_field
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ | single_datetime_field
+ ;
+
+function_arg_commalist2:
+ function_arg ',' function_arg
+ {$$ = SQL_NEW_COMMALISTRULE;
+ $$->append($1);
+ $$->append($3);}
+ ;
+function_arg_commalist3:
+ function_arg ',' function_arg ',' function_arg
+ {
+ $$ = SQL_NEW_COMMALISTRULE;
+ $$->append($1);
+ $$->append($3);
+ $$->append($5);
+ }
+ ;
+function_arg_commalist4:
+ function_arg ',' function_arg ',' function_arg ',' function_arg
+ {
+ $$ = SQL_NEW_COMMALISTRULE;
+ $$->append($1);
+ $$->append($3);
+ $$->append($5);
+ $$->append($7);
+ }
+ ;
+value_exp_commalist:
+ value_exp
+ {$$ = SQL_NEW_COMMALISTRULE;
+ $$->append($1);}
+ | value_exp_commalist ',' value_exp
+ {$1->append($3);
+ $$ = $1;}
+ /* this rule is only valid if we check predicates */
+ | value_exp_commalist ';' value_exp
+ {
+ if (xxx_pGLOBAL_SQLPARSER->inPredicateCheck())
+ {
+ $1->append($3);
+ $$ = $1;
+ }
+ else
+ YYERROR;
+ }
+ ;
+function_arg:
+ result
+ | value_exp comparison value_exp
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ | value_exp SQL_TOKEN_USING value_exp comparison value_exp
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ }
+ | value_exp SQL_TOKEN_BY value_exp_commalist
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ ;
+function_args_commalist:
+ function_arg
+ {$$ = SQL_NEW_COMMALISTRULE;
+ $$->append($1);}
+ | function_args_commalist ',' function_arg
+ {$1->append($3);
+ $$ = $1;}
+ /* this rule is only valid if we check predicates */
+ | function_args_commalist ';' function_arg
+ {
+ if (xxx_pGLOBAL_SQLPARSER->inPredicateCheck())
+ {
+ $1->append($3);
+ $$ = $1;
+ }
+ else
+ YYERROR;
+ }
+ | datetime_unit ',' function_arg ',' function_arg
+ {
+ $$ = SQL_NEW_COMMALISTRULE;
+ $$->append($1);
+ $$->append($3);
+ $$->append($5);
+ }
+ ;
+
+value_exp:
+ num_value_exp /*[^')']*/
+ | string_value_exp
+ | datetime_value_exp
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+ ;
+string_value_exp:
+ char_value_exp
+/* | bit_value_exp
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+*/ ;
+char_value_exp:
+ char_factor
+ | concatenation
+ ;
+concatenation:
+ char_value_exp '+' char_factor
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("+", SQLNodeType::Punctuation));
+ $$->append($3);
+ }
+ | value_exp SQL_CONCAT value_exp
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ ;
+
+char_primary:
+ SQL_TOKEN_STRING
+ | string_value_fct
+ ;
+collate_clause:
+ SQL_TOKEN_COLLATE table_node
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+char_factor:
+ char_primary
+ | char_primary collate_clause
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+string_value_fct:
+ char_value_fct
+ | bit_value_fct
+ ;
+bit_value_fct:
+ bit_substring_fct
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+ ;
+bit_substring_fct:
+ SQL_TOKEN_SUBSTRING '(' bit_value_exp SQL_TOKEN_FROM string_value_exp for_length ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append($4);
+ $$->append($5);
+ $$->append($6);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ ;
+bit_value_exp:
+ bit_factor
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+ ;
+/*
+ bit_concatenation
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+ |
+bit_concatenation:
+ bit_value_exp '+' bit_factor
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("+", SQLNodeType::Punctuation));
+ $$->append($3);
+ }
+ ;
+*/
+bit_factor:
+ bit_primary
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+ ;
+bit_primary:
+ {$$ = SQL_NEW_RULE;}
+/* value_exp_primary
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+ | string_value_fct
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }*/
+ ;
+char_value_fct:
+ char_substring_fct
+ | fold
+ | form_conversion
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+ | char_translation
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+ | trim_fct
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+ ;
+for_length:
+ {$$ = SQL_NEW_RULE;}
+ | SQL_TOKEN_FOR value_exp
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+char_substring_fct:
+ SQL_TOKEN_SUBSTRING '(' value_exp SQL_TOKEN_FROM value_exp for_length ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append($4);
+ $$->append($5);
+ $$->append($6);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ | SQL_TOKEN_SUBSTRING '(' value_exp_commalist ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ ;
+upper_lower:
+ SQL_TOKEN_UPPER
+ | SQL_TOKEN_LOWER
+ ;
+fold:
+ upper_lower '(' value_exp ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ ;
+form_conversion:
+ SQL_TOKEN_CONVERT '(' string_value_exp SQL_TOKEN_USING table_node ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append($4);
+ $$->append($5);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ | SQL_TOKEN_CONVERT '(' cast_operand ',' cast_target ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(",", SQLNodeType::Punctuation));
+ $$->append($5);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ ;
+char_translation:
+ SQL_TOKEN_TRANSLATE '(' string_value_exp SQL_TOKEN_USING table_node ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append($4);
+ $$->append($5);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ ;
+trim_fct:
+ SQL_TOKEN_TRIM '(' trim_operands ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ ;
+trim_operands:
+ trim_spec value_exp SQL_TOKEN_FROM value_exp
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ }
+ | trim_spec SQL_TOKEN_FROM value_exp
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ | value_exp SQL_TOKEN_FROM value_exp
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ | SQL_TOKEN_FROM value_exp
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ | value_exp
+ ;
+
+trim_spec:
+ SQL_TOKEN_BOTH
+ | SQL_TOKEN_LEADING
+ | SQL_TOKEN_TRAILING
+ ;
+
+derived_column:
+ value_exp as_clause
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+/* Tabellenname */
+table_node:
+ table_name
+ | schema_name
+ | catalog_name
+;
+catalog_name:
+ SQL_TOKEN_NAME '.' schema_name
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode(".", SQLNodeType::Punctuation));
+ $$->append($3);
+ }
+ | SQL_TOKEN_NAME ':' schema_name
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode(":", SQLNodeType::Punctuation));
+ $$->append($3);
+ }
+;
+schema_name:
+ SQL_TOKEN_NAME '.' table_name
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode(".", SQLNodeType::Punctuation));
+ $$->append($3);
+ }
+;
+
+table_name:
+ SQL_TOKEN_NAME
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);}
+;
+/* Columns */
+column_ref:
+ column
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);}
+/* | table_node '.' column_val %prec '.'
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode(".", SQLNodeType::Punctuation));
+ $$->append($3);}
+*/
+ | SQL_TOKEN_NAME '.' column_val %prec '.'
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode(".", SQLNodeType::Punctuation));
+ $$->append($3);
+ }
+ | SQL_TOKEN_NAME '.' SQL_TOKEN_NAME '.' column_val %prec '.'
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode(".", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(".", SQLNodeType::Punctuation));
+ $$->append($5);}
+ | SQL_TOKEN_NAME '.' SQL_TOKEN_NAME '.' SQL_TOKEN_NAME '.' column_val %prec '.'
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode(".", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(".", SQLNodeType::Punctuation));
+ $$->append($5);
+ $$->append(newNode(".", SQLNodeType::Punctuation));
+ $$->append($7);
+ }
+ | SQL_TOKEN_NAME ':' SQL_TOKEN_NAME '.' SQL_TOKEN_NAME '.' column_val %prec '.'
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode(":", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(".", SQLNodeType::Punctuation));
+ $$->append($5);
+ $$->append(newNode(".", SQLNodeType::Punctuation));
+ $$->append($7);
+ }
+/* | SQL_TOKEN_NAME ';' SQL_TOKEN_NAME '.' SQL_TOKEN_NAME '.' column_val
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode(";", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(".", SQLNodeType::Punctuation));
+ $$->append($5);
+ $$->append(newNode(".", SQLNodeType::Punctuation));
+ $$->append($7);
+ }
+*/ ;
+
+ /* data types */
+column_val:
+ column
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);}
+ | '*'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append(newNode("*", SQLNodeType::Punctuation));
+ }
+ ;
+data_type:
+ predefined_type
+ ;
+opt_char_set_spec:
+ {$$ = SQL_NEW_RULE;}
+ | SQL_TOKEN_CHARACTER SQL_TOKEN_SET SQL_TOKEN_NAME
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ ;
+opt_collate_clause:
+ {$$ = SQL_NEW_RULE;}
+ | collate_clause
+ ;
+predefined_type:
+ character_string_type opt_char_set_spec opt_collate_clause
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ | national_character_string_type opt_collate_clause
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ | binary_string_type
+ | numeric_type
+ | boolean_type
+ | datetime_type
+ | interval_type
+ ;
+character_string_type:
+ SQL_TOKEN_CHARACTER opt_paren_precision
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ | SQL_TOKEN_CHAR opt_paren_precision
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ | SQL_TOKEN_CHARACTER SQL_TOKEN_VARYING paren_char_length
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ | SQL_TOKEN_CHAR SQL_TOKEN_VARYING paren_char_length
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ | SQL_TOKEN_VARCHAR paren_char_length
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ | character_large_object_type
+ ;
+opt_paren_precision:
+ {$$ = SQL_NEW_RULE;}
+ | paren_char_length
+ ;
+paren_char_length:
+ '(' SQL_TOKEN_INTNUM ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($2);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ ;
+opt_paren_char_large_length:
+ {$$ = SQL_NEW_RULE;}
+ | paren_character_large_object_length
+ ;
+paren_character_large_object_length:
+ '(' large_object_length ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($2);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ ;
+
+large_object_length:
+ SQL_TOKEN_INTNUM opt_multiplier
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+opt_multiplier:
+ {$$ = SQL_NEW_RULE;}
+ | 'K'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append(newNode("K", SQLNodeType::Punctuation));
+ }
+ | 'M'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append(newNode("M", SQLNodeType::Punctuation));
+ }
+ | 'G'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append(newNode("G", SQLNodeType::Punctuation));
+ }
+ | 'T'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append(newNode("T", SQLNodeType::Punctuation));
+ }
+ | 'P'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append(newNode("P", SQLNodeType::Punctuation));
+ }
+ ;
+character_large_object_type:
+ SQL_TOKEN_CHARACTER SQL_TOKEN_LARGE SQL_TOKEN_OBJECT opt_paren_char_large_length
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ }
+ | SQL_TOKEN_CHAR SQL_TOKEN_LARGE SQL_TOKEN_OBJECT opt_paren_char_large_length
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ }
+ | SQL_TOKEN_CLOB opt_paren_char_large_length
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+national_character_string_type:
+ SQL_TOKEN_NATIONAL SQL_TOKEN_CHARACTER opt_paren_precision
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ | SQL_TOKEN_NATIONAL SQL_TOKEN_CHAR opt_paren_precision
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ | SQL_TOKEN_NCHAR opt_paren_precision
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ | SQL_TOKEN_NATIONAL SQL_TOKEN_CHARACTER SQL_TOKEN_VARYING paren_char_length
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ }
+ | SQL_TOKEN_NATIONAL SQL_TOKEN_CHAR SQL_TOKEN_VARYING paren_char_length
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ }
+ | SQL_TOKEN_NCHAR SQL_TOKEN_VARYING paren_char_length
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ | national_character_large_object_type
+ ;
+national_character_large_object_type:
+ SQL_TOKEN_NATIONAL SQL_TOKEN_CHARACTER SQL_TOKEN_LARGE SQL_TOKEN_OBJECT opt_paren_char_large_length
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ $$->append($5);
+ }
+ | SQL_TOKEN_NCHAR SQL_TOKEN_LARGE SQL_TOKEN_OBJECT opt_paren_char_large_length
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ }
+ | SQL_TOKEN_NCLOB opt_paren_char_large_length
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+binary_string_type:
+ SQL_TOKEN_BINARY opt_paren_precision
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ | SQL_TOKEN_BINARY SQL_TOKEN_VARYING paren_char_length
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ | SQL_TOKEN_VARBINARY paren_char_length
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ | binary_large_object_string_type
+ ;
+binary_large_object_string_type:
+ SQL_TOKEN_BINARY SQL_TOKEN_LARGE SQL_TOKEN_OBJECT opt_paren_char_large_length
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ }
+ | SQL_TOKEN_BLOB opt_paren_char_large_length
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+numeric_type:
+ exact_numeric_type
+ | approximate_numeric_type
+ ;
+opt_paren_precision_scale:
+ {$$ = SQL_NEW_RULE;}
+ | '(' SQL_TOKEN_INTNUM ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($2);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ | '(' SQL_TOKEN_INTNUM ',' SQL_TOKEN_INTNUM ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($2);
+ $$->append(newNode(",", SQLNodeType::Punctuation));
+ $$->append($4);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ ;
+exact_numeric_type:
+ SQL_TOKEN_NUMERIC opt_paren_precision_scale
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ | SQL_TOKEN_DECIMAL opt_paren_precision_scale
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ | SQL_TOKEN_DEC opt_paren_precision_scale
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ | SQL_TOKEN_SMALLINT
+ | SQL_TOKEN_INTEGER
+ | SQL_TOKEN_INT
+ | SQL_TOKEN_BIGINT
+ ;
+approximate_numeric_type:
+ SQL_TOKEN_FLOAT '(' SQL_TOKEN_INTNUM ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ | SQL_TOKEN_FLOAT
+ | SQL_TOKEN_REAL
+ | SQL_TOKEN_DOUBLE
+ | SQL_TOKEN_DOUBLE SQL_TOKEN_PRECISION
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+boolean_type:
+ SQL_TOKEN_BOOLEAN
+;
+datetime_type:
+ SQL_TOKEN_DATE
+ | SQL_TOKEN_TIME opt_paren_precision opt_with_or_without_time_zone
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ | SQL_TOKEN_TIMESTAMP opt_paren_precision opt_with_or_without_time_zone
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ ;
+opt_with_or_without_time_zone:
+ {$$ = SQL_NEW_RULE;}
+ | SQL_TOKEN_WITH SQL_TOKEN_TIME SQL_TOKEN_ZONE
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ | SQL_TOKEN_WITHOUT SQL_TOKEN_TIME SQL_TOKEN_ZONE
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ ;
+interval_type:
+ SQL_TOKEN_INTERVAL interval_qualifier
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+ /* the various things you can name */
+
+column:
+ SQL_TOKEN_NAME
+ | SQL_TOKEN_POSITION
+ {
+ sal_uInt32 nNod = $$->getRuleID();
+ delete $$;
+ $$ = newNode(OSQLParser::TokenIDToStr(nNod), SQLNodeType::Name);
+ }
+ | SQL_TOKEN_CHAR_LENGTH
+ {
+ sal_uInt32 nNod = $$->getRuleID();
+ delete $$;
+ $$ = newNode(OSQLParser::TokenIDToStr(nNod), SQLNodeType::Name);
+ }
+ | SQL_TOKEN_EXTRACT
+ {
+ sal_uInt32 nNod = $$->getRuleID();
+ delete $$;
+ $$ = newNode(OSQLParser::TokenIDToStr(nNod), SQLNodeType::Name);
+ }
+ ;
+case_expression:
+ case_abbreviation
+ | case_specification
+ ;
+case_abbreviation:
+ SQL_TOKEN_NULLIF '(' value_exp_commalist ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ | SQL_TOKEN_COALESCE '(' value_exp ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ | SQL_TOKEN_COALESCE '(' value_exp_commalist ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ ;
+case_specification:
+ simple_case
+ | searched_case
+ ;
+simple_case:
+ SQL_TOKEN_CASE case_operand simple_when_clause_list else_clause SQL_TOKEN_END
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ $$->append($5);
+ }
+ ;
+searched_case:
+ SQL_TOKEN_CASE searched_when_clause_list else_clause SQL_TOKEN_END
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ }
+ ;
+simple_when_clause_list:
+ simple_when_clause
+ {
+ $$ = SQL_NEW_LISTRULE;
+ $$->append($1);
+ }
+ | searched_when_clause_list simple_when_clause
+ {
+ $1->append($2);
+ $$ = $1;
+ }
+ ;
+simple_when_clause:
+ SQL_TOKEN_WHEN when_operand_list SQL_TOKEN_THEN result
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ }
+ ;
+when_operand_list:
+ when_operand
+ {$$ = SQL_NEW_COMMALISTRULE;
+ $$->append($1);}
+ | when_operand_list ',' when_operand
+ {$1->append($3);
+ $$ = $1;}
+ ;
+when_operand:
+ row_value_constructor_elem
+ | comparison_predicate_part_2 %dprec 1
+ | between_predicate_part_2
+ | in_predicate_part_2
+ | character_like_predicate_part_2
+ | null_predicate_part_2 %dprec 2
+;
+searched_when_clause_list:
+ searched_when_clause
+ {
+ $$ = SQL_NEW_LISTRULE;
+ $$->append($1);
+ }
+ | searched_when_clause_list searched_when_clause
+ {
+ $1->append($2);
+ $$ = $1;
+ }
+ ;
+searched_when_clause:
+ SQL_TOKEN_WHEN search_condition SQL_TOKEN_THEN result
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ }
+ ;
+else_clause:
+ {$$ = SQL_NEW_RULE;}
+ | SQL_TOKEN_ELSE result
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+result:
+ result_expression
+ ;
+result_expression:
+ value_exp
+ ;
+case_operand:
+ row_value_constructor_elem
+ ;
+
+cursor: SQL_TOKEN_NAME
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);}
+ ;
+
+/***
+module: SQL_TOKEN_NAME
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);}
+ ;
+***/
+
+parameter:
+ ':' SQL_TOKEN_NAME
+ {$$ = SQL_NEW_RULE;
+ $$->append(newNode(":", SQLNodeType::Punctuation));
+ $$->append($2);}
+ | '?'
+ {$$ = SQL_NEW_RULE; // test
+ $$->append(newNode("?", SQLNodeType::Punctuation));}
+ | '[' SQL_TOKEN_NAME ']'
+ {$$ = SQL_NEW_RULE;
+ $$->append(newNode("[", SQLNodeType::Punctuation));
+ $$->append($2);
+ $$->append(newNode("]", SQLNodeType::Punctuation));}
+ ;
+
+/***
+procedure: SQL_TOKEN_NAME
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);}
+ ;
+***/
+
+range_variable:
+ {$$ = SQL_NEW_RULE;}
+ | opt_as SQL_TOKEN_NAME
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+
+user: SQL_TOKEN_NAME
+ ;
+
+/* PREDICATECHECK RULES */
+sql:
+ search_condition /* checking predicats */
+ {
+ if (xxx_pGLOBAL_SQLPARSER->inPredicateCheck()) // sql: rule 1
+ {
+ $$ = $1;
+ if ( SQL_ISRULE($$,search_condition) )
+ {
+ $$->insert(0,newNode("(", SQLNodeType::Punctuation));
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ }
+ else
+ YYERROR;
+ }
+ | '(' sql ')' /* checking predicats */
+ ;
+trigger_definition:
+ SQL_TOKEN_CREATE SQL_TOKEN_TRIGGER trigger_name trigger_action_time trigger_event SQL_TOKEN_ON table_name op_referencing triggered_action
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ $$->append($5);
+ $$->append($6);
+ $$->append($7);
+ $$->append($8);
+ $$->append($9);
+ }
+ ;
+op_referencing:
+ {
+ $$ = SQL_NEW_RULE;
+ }
+ | SQL_TOKEN_REFERENCING transition_table_or_variable_list
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+trigger_action_time:
+ SQL_TOKEN_BEFORE
+ | SQL_TOKEN_AFTER
+ | SQL_TOKEN_INSTEAD SQL_TOKEN_OF
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+;
+trigger_event:
+ SQL_TOKEN_INSERT
+ | SQL_TOKEN_DELETE
+ | SQL_TOKEN_UPDATE op_trigger_columnlist
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+op_trigger_columnlist:
+ {
+ $$ = SQL_NEW_RULE;
+ }
+ | SQL_TOKEN_OF trigger_column_list
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+trigger_column_list:
+ column_commalist
+ ;
+triggered_action:
+ op_triggered_action_for triggered_when_clause triggered_SQL_statement
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ ;
+op_triggered_action_for:
+ {
+ $$ = SQL_NEW_RULE;
+ }
+ | SQL_TOKEN_FOR SQL_TOKEN_EACH trigger_for
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ ;
+trigger_for:
+ SQL_TOKEN_ROW
+ | SQL_TOKEN_STATEMENT
+ ;
+triggered_when_clause:
+ {
+ $$ = SQL_NEW_RULE;
+ }
+ | SQL_TOKEN_WHEN parenthesized_boolean_value_expression
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+triggered_SQL_statement:
+ SQL_procedure_statement
+ | SQL_TOKEN_BEGIN SQL_TOKEN_ATOMIC SQL_procedure_statement_list ';' SQL_TOKEN_END
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append(newNode(";", SQLNodeType::Punctuation));
+ $$->append($5);
+ }
+ ;
+SQL_procedure_statement_list:
+ SQL_procedure_statement
+ {
+ $$ = SQL_NEW_LISTRULE;
+ $$->append($1);
+ }
+ | SQL_procedure_statement_list ';' SQL_procedure_statement
+ {
+ $1->append($3);
+ $$ = $1;
+ }
+ ;
+SQL_procedure_statement:
+ sql
+ ;
+
+transition_table_or_variable_list:
+ transition_table_or_variable
+ {
+ $$ = SQL_NEW_LISTRULE;
+ $$->append($1);
+ }
+ | transition_table_or_variable_list transition_table_or_variable
+ {
+ $1->append($2);
+ $$ = $1;
+ }
+ ;
+
+transition_table_or_variable:
+ SQL_TOKEN_OLD opt_row opt_as old_transition_variable_name
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ }
+ | SQL_TOKEN_NEW opt_row opt_as new_transition_variable_name
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ }
+ | SQL_TOKEN_OLD SQL_TOKEN_TABLE opt_as old_transition_table_name
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ }
+ | SQL_TOKEN_NEW SQL_TOKEN_TABLE opt_as new_transition_table_name
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ }
+;
+old_transition_table_name:
+ transition_table_name
+;
+new_transition_table_name:
+ transition_table_name
+;
+transition_table_name:
+ SQL_TOKEN_NAME
+;
+old_transition_variable_name:
+ SQL_TOKEN_NAME
+;
+new_transition_variable_name:
+ SQL_TOKEN_NAME
+;
+trigger_name:
+ SQL_TOKEN_NAME
+;
+%%
+
+#if defined _MSC_VER
+#pragma warning(pop)
+#endif
+
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::i18n;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::util;
+using namespace ::osl;
+using namespace ::dbtools;
+
+connectivity::OSQLParser* xxx_pGLOBAL_SQLPARSER;
+
+connectivity::OSQLInternalNode* newNode(const char* pNewValue,
+ const connectivity::SQLNodeType eNodeType,
+ const sal_uInt32 nNodeID)
+{
+ return new connectivity::OSQLInternalNode(pNewValue, eNodeType, nNodeID);
+}
+
+connectivity::OSQLInternalNode* newNode(const OString& _newValue,
+ const connectivity::SQLNodeType eNodeType,
+ const sal_uInt32 nNodeID)
+{
+ return new connectivity::OSQLInternalNode(_newValue, eNodeType, nNodeID);
+}
+
+connectivity::OSQLInternalNode* newNode(const OUString& _newValue,
+ const connectivity::SQLNodeType eNodeType,
+ const sal_uInt32 nNodeID)
+{
+ return new connectivity::OSQLInternalNode(_newValue, eNodeType, nNodeID);
+}
+
+OParseContext::OParseContext()
+{
+}
+
+
+OParseContext::~OParseContext()
+{
+}
+
+
+OUString OParseContext::getErrorMessage(ErrorCode _eCode) const
+{
+ OUString aMsg;
+ switch (_eCode)
+ {
+ case ErrorCode::General: aMsg = "Syntax error in SQL expression"; break;
+ case ErrorCode::ValueNoLike: aMsg = "The value #1 can not be used with LIKE."; break;
+ case ErrorCode::FieldNoLike: aMsg = "LIKE can not be used with this field."; break;
+ case ErrorCode::InvalidCompare: aMsg = "The entered criterion can not be compared with this field."; break;
+ case ErrorCode::InvalidIntCompare: aMsg = "The field can not be compared with a number."; break;
+ case ErrorCode::InvalidDateCompare: aMsg = "The field can not be compared with a date."; break;
+ case ErrorCode::InvalidRealCompare: aMsg = "The field can not be compared with a floating point number."; break;
+ case ErrorCode::InvalidTableNosuch: aMsg = "The database does not contain a table named \"#\"."; break;
+ case ErrorCode::InvalidTableOrQuery: aMsg = "The database does contain neither a table nor a query named \"#\"."; break;
+ case ErrorCode::InvalidColumn: aMsg = "The column \"#1\" is unknown in the table \"#2\"."; break;
+ case ErrorCode::InvalidTableExist: aMsg = "The database already contains a table or view with name \"#\"."; break;
+ case ErrorCode::InvalidQueryExist: aMsg = "The database already contains a query with name \"#\"."; break;
+ default:
+ OSL_FAIL( "OParseContext::getErrorMessage: unknown error code!" );
+ break;
+ }
+ return aMsg;
+}
+
+
+OString OParseContext::getIntlKeywordAscii(InternationalKeyCode _eKey) const
+{
+ OString aKeyword;
+ switch (_eKey)
+ {
+ case InternationalKeyCode::Like: aKeyword = "LIKE"; break;
+ case InternationalKeyCode::Not: aKeyword = "NOT"; break;
+ case InternationalKeyCode::Null: aKeyword = "NULL"; break;
+ case InternationalKeyCode::True: aKeyword = "True"; break;
+ case InternationalKeyCode::False: aKeyword = "False"; break;
+ case InternationalKeyCode::Is: aKeyword = "IS"; break;
+ case InternationalKeyCode::Between: aKeyword = "BETWEEN"; break;
+ case InternationalKeyCode::Or: aKeyword = "OR"; break;
+ case InternationalKeyCode::And: aKeyword = "AND"; break;
+ case InternationalKeyCode::Avg: aKeyword = "AVG"; break;
+ case InternationalKeyCode::Count: aKeyword = "COUNT"; break;
+ case InternationalKeyCode::Max: aKeyword = "MAX"; break;
+ case InternationalKeyCode::Min: aKeyword = "MIN"; break;
+ case InternationalKeyCode::Sum: aKeyword = "SUM"; break;
+ case InternationalKeyCode::Every: aKeyword = "EVERY"; break;
+ case InternationalKeyCode::Any: aKeyword = "ANY"; break;
+ case InternationalKeyCode::Some: aKeyword = "SOME"; break;
+ case InternationalKeyCode::StdDevPop: aKeyword = "STDDEV_POP"; break;
+ case InternationalKeyCode::StdDevSamp: aKeyword = "STDDEV_SAMP"; break;
+ case InternationalKeyCode::VarSamp: aKeyword = "VAR_SAMP"; break;
+ case InternationalKeyCode::VarPop: aKeyword = "VAR_POP"; break;
+ case InternationalKeyCode::Collect: aKeyword = "COLLECT"; break;
+ case InternationalKeyCode::Fusion: aKeyword = "FUSION"; break;
+ case InternationalKeyCode::Intersection:aKeyword = "INTERSECTION"; break;
+ case InternationalKeyCode::None: break;
+ default:
+ OSL_FAIL( "OParseContext::getIntlKeywordAscii: unknown key!" );
+ break;
+ }
+ return aKeyword;
+}
+
+
+IParseContext::InternationalKeyCode OParseContext::getIntlKeyCode(const OString& rToken) const
+{
+ static IParseContext::InternationalKeyCode const Intl_TokenID[] =
+ {
+ InternationalKeyCode::Like, InternationalKeyCode::Not, InternationalKeyCode::Null, InternationalKeyCode::True,
+ InternationalKeyCode::False, InternationalKeyCode::Is, InternationalKeyCode::Between, InternationalKeyCode::Or,
+ InternationalKeyCode::And, InternationalKeyCode::Avg, InternationalKeyCode::Count, InternationalKeyCode::Max,
+ InternationalKeyCode::Min, InternationalKeyCode::Sum, InternationalKeyCode::Every,InternationalKeyCode::Any,InternationalKeyCode::Some,
+ InternationalKeyCode::StdDevPop,InternationalKeyCode::StdDevSamp,InternationalKeyCode::VarSamp,
+ InternationalKeyCode::VarPop,InternationalKeyCode::Collect,InternationalKeyCode::Fusion,InternationalKeyCode::Intersection
+ };
+
+ auto const token = std::find_if(std::cbegin(Intl_TokenID), std::cend(Intl_TokenID)
+ , [&rToken, this](IParseContext::InternationalKeyCode const & tokenID)
+ { return rToken.equalsIgnoreAsciiCase(getIntlKeywordAscii(tokenID)); });
+
+ if (std::cend(Intl_TokenID) != token)
+ return *token;
+
+ return InternationalKeyCode::None;
+}
+
+
+static Locale& impl_getLocaleInstance( )
+{
+ static Locale s_aLocale( "en", "US", "" );
+ return s_aLocale;
+}
+
+
+Locale OParseContext::getPreferredLocale( ) const
+{
+ return getDefaultLocale();
+}
+
+
+const Locale& OParseContext::getDefaultLocale()
+{
+ return impl_getLocaleInstance();
+}
+
+// The (unfortunately global) yylval for the handing over of
+// values from the Scanner to the Parser. The global variable
+// is only used for a short term, the Parser reads the variable
+// immediately after the call of the Scanner into a same named own
+// member variable.
+
+
+OUString ConvertLikeToken(const OSQLParseNode* pTokenNode, const OSQLParseNode* pEscapeNode, bool bInternational)
+{
+ OUStringBuffer aMatchStr(0);
+ if (pTokenNode->isToken())
+ {
+ sal_Unicode cEscape = 0;
+ if (pEscapeNode->count())
+ cEscape = pEscapeNode->getChild(1)->getTokenValue().toChar();
+
+ // Change place holder
+ aMatchStr = pTokenNode->getTokenValue();
+ const sal_Int32 nLen = aMatchStr.getLength();
+ OUStringBuffer sSearch,sReplace;
+ if ( bInternational )
+ {
+ sSearch.append("%_");
+ sReplace.append("*?");
+ }
+ else
+ {
+ sSearch.append("*?");
+ sReplace.append("%_");
+ }
+
+ bool wasEscape = false;
+ for (sal_Int32 i = 0; i < nLen; i++)
+ {
+ const sal_Unicode c = aMatchStr[i];
+ // SQL standard requires the escape to be followed
+ // by a meta-character ('%', '_' or itself), else error
+ // We are more lenient here and let it escape anything.
+ // Especially since some databases (e.g. Microsoft SQL Server)
+ // have more meta-characters than the standard, such as e.g. '[' and ']'
+ if (wasEscape)
+ {
+ wasEscape=false;
+ continue;
+ }
+ if (c == cEscape)
+ {
+ wasEscape=true;
+ continue;
+ }
+ int match = -1;
+ if (c == sSearch[0])
+ match=0;
+ else if (c == sSearch[1])
+ match=1;
+
+ if (match != -1)
+ {
+ aMatchStr[i] = sReplace[match];
+ }
+ }
+ }
+ return aMatchStr.makeStringAndClear();
+}
+
+sal_uInt32 OSQLParser::s_nRuleIDs[OSQLParseNode::rule_count + 1];
+OSQLParser::RuleIDMap OSQLParser::s_aReverseRuleIDLookup;
+OParseContext OSQLParser::s_aDefaultContext;
+
+sal_Int32 OSQLParser::s_nRefCount = 0;
+// ::osl::Mutex OSQLParser::s_aMutex;
+OSQLScanner* OSQLParser::s_pScanner = nullptr;
+OSQLParseNodesGarbageCollector* OSQLParser::s_pGarbageCollector = nullptr;
+vcl::DeleteOnDeinit<css::uno::Reference< css::i18n::XLocaleData4>> OSQLParser::s_xLocaleData(vcl::DeleteOnDeinitFlag::Empty);
+
+void setParser(OSQLParser* _pParser)
+{
+ xxx_pGLOBAL_SQLPARSER = _pParser;
+}
+
+void OSQLParser::setParseTree(OSQLParseNode* pNewParseTree)
+{
+ m_pParseTree.reset(pNewParseTree);
+}
+
+
+/** Delete all comments in a query.
+
+ See also getComment()/concatComment() implementation for
+ OQueryController::translateStatement().
+ */
+static OUString delComment( const OUString& rQuery )
+{
+ // First a quick search if there is any "--" or "//" or "/*", if not then the whole
+ // copying loop is pointless.
+ if (rQuery.indexOf("--") < 0 && rQuery.indexOf("//") < 0 &&
+ rQuery.indexOf("/*") < 0)
+ return rQuery;
+
+ const sal_Unicode* pCopy = rQuery.getStr();
+ sal_Int32 nQueryLen = rQuery.getLength();
+ bool bIsText1 = false; // "text"
+ bool bIsText2 = false; // 'text'
+ bool bComment2 = false; // /* comment */
+ bool bComment = false; // -- or // comment
+ OUStringBuffer aBuf(nQueryLen);
+ for (sal_Int32 i=0; i < nQueryLen; ++i)
+ {
+ if (bComment2)
+ {
+ if ((i+1) < nQueryLen)
+ {
+ if (pCopy[i]=='*' && pCopy[i+1]=='/')
+ {
+ bComment2 = false;
+ ++i;
+ }
+ }
+ else
+ {
+ // comment can't close anymore, actually an error, but...
+ }
+ continue;
+ }
+ if (pCopy[i] == '\n')
+ bComment = false;
+ else if (!bComment)
+ {
+ if (pCopy[i] == '\"' && !bIsText2)
+ bIsText1 = !bIsText1;
+ else if (pCopy[i] == '\'' && !bIsText1)
+ bIsText2 = !bIsText2;
+ if (!bIsText1 && !bIsText2 && (i+1) < nQueryLen)
+ {
+ if ((pCopy[i]=='-' && pCopy[i+1]=='-') || (pCopy[i]=='/' && pCopy[i+1]=='/'))
+ bComment = true;
+ else if ((pCopy[i]=='/' && pCopy[i+1]=='*'))
+ bComment2 = true;
+ }
+ }
+ if (!bComment && !bComment2)
+ aBuf.append( &pCopy[i], 1);
+ }
+ return aBuf.makeStringAndClear();
+}
+
+std::unique_ptr<OSQLParseNode> OSQLParser::parseTree(OUString& rErrorMessage,
+ const OUString& rStatement,
+ bool bInternational)
+{
+
+
+ // Guard the parsing
+ std::unique_lock aGuard(getMutex());
+ // must be reset
+ setParser(this);
+
+ // delete comments before parsing
+ OUString sTemp = delComment(rStatement);
+
+ // defines how to scan
+ s_pScanner->SetRule(OSQLScanner::GetSQLRule()); // initial
+ s_pScanner->prepareScan(sTemp, m_pContext, bInternational);
+
+ SQLyylval.pParseNode = nullptr;
+ // SQLyypvt = NULL;
+ m_pParseTree = nullptr;
+ m_sErrorMessage = "";
+
+ // start parsing
+ if (SQLyyparse() != 0)
+ {
+ // only set the error message, if it's not already set
+ if (m_sErrorMessage.isEmpty())
+ m_sErrorMessage = s_pScanner->getErrorMessage();
+ if (m_sErrorMessage.isEmpty())
+ m_sErrorMessage = m_pContext->getErrorMessage(IParseContext::ErrorCode::General);
+
+ rErrorMessage = m_sErrorMessage;
+
+ // clear the garbage collector
+ (*s_pGarbageCollector)->clearAndDelete();
+ // coverity[leaked_storage : FALSE] - because the garbage collector deleted it
+ m_pParseTree.release();
+ return nullptr;
+ }
+ else
+ {
+ (*s_pGarbageCollector)->clear();
+
+ // return result:
+ // to work around a bug in MKS YACC return the member m_pParseTree
+ // instead of Sdbyyval.pParseNode
+
+ SAL_WARN_IF(!m_pParseTree, "connectivity.parse",
+ "OSQLParser: Parser did not create ParseTree");
+ return std::move(m_pParseTree);
+ }
+}
+
+OString OSQLParser::TokenIDToStr(sal_uInt32 nTokenID, const IParseContext* pContext)
+{
+ OString aStr;
+ if (pContext)
+ {
+ IParseContext::InternationalKeyCode eKeyCode = IParseContext::InternationalKeyCode::None;
+ switch( nTokenID )
+ {
+ case SQL_TOKEN_LIKE: eKeyCode = IParseContext::InternationalKeyCode::Like; break;
+ case SQL_TOKEN_NOT: eKeyCode = IParseContext::InternationalKeyCode::Not; break;
+ case SQL_TOKEN_NULL: eKeyCode = IParseContext::InternationalKeyCode::Null; break;
+ case SQL_TOKEN_TRUE: eKeyCode = IParseContext::InternationalKeyCode::True; break;
+ case SQL_TOKEN_FALSE: eKeyCode = IParseContext::InternationalKeyCode::False; break;
+ case SQL_TOKEN_IS: eKeyCode = IParseContext::InternationalKeyCode::Is; break;
+ case SQL_TOKEN_BETWEEN: eKeyCode = IParseContext::InternationalKeyCode::Between; break;
+ case SQL_TOKEN_OR: eKeyCode = IParseContext::InternationalKeyCode::Or; break;
+ case SQL_TOKEN_AND: eKeyCode = IParseContext::InternationalKeyCode::And; break;
+ case SQL_TOKEN_AVG: eKeyCode = IParseContext::InternationalKeyCode::Avg; break;
+ case SQL_TOKEN_COUNT: eKeyCode = IParseContext::InternationalKeyCode::Count; break;
+ case SQL_TOKEN_MAX: eKeyCode = IParseContext::InternationalKeyCode::Max; break;
+ case SQL_TOKEN_MIN: eKeyCode = IParseContext::InternationalKeyCode::Min; break;
+ case SQL_TOKEN_SUM: eKeyCode = IParseContext::InternationalKeyCode::Sum; break;
+ }
+ if ( eKeyCode != IParseContext::InternationalKeyCode::None )
+ aStr = pContext->getIntlKeywordAscii(eKeyCode);
+ }
+
+ if (aStr.isEmpty())
+ {
+ // coverity[unsigned_compare : SUPPRESS] - YYTRANSLATE is out of our control
+ aStr = yytname[YYTRANSLATE(nTokenID)];
+ if(aStr.startsWith("SQL_TOKEN_"))
+ aStr = aStr.copy(10);
+ switch( nTokenID )
+ {
+ case SQL_TOKEN_OJ:
+ case SQL_TOKEN_TS:
+ case SQL_TOKEN_T:
+ case SQL_TOKEN_D:
+ aStr = aStr.toAsciiLowerCase();
+ }
+ }
+ return aStr;
+}
+
+#if OSL_DEBUG_LEVEL > 0
+OUString OSQLParser::RuleIDToStr(sal_uInt32 nRuleID)
+{
+ OSL_ENSURE(nRuleID < std::size(yytname), "OSQLParser::RuleIDToStr: Invalid nRuleId!");
+ return OUString::createFromAscii(yytname[nRuleID]);
+}
+#endif
+
+
+sal_uInt32 OSQLParser::StrToRuleID(const OString & rValue)
+{
+ // Search for the given name in yytname and return the index
+ // (or UNKNOWN_RULE, if not found)
+ static sal_uInt32 const nLen = std::size(yytname)-1;
+ for (sal_uInt32 i = YYTRANSLATE(SQL_TOKEN_INVALIDSYMBOL); i < nLen; ++i)
+ {
+ if (rValue == yytname[i])
+ return i;
+ }
+
+ // Not found
+ return OSQLParseNode::UNKNOWN_RULE;
+}
+
+
+OSQLParseNode::Rule OSQLParser::RuleIDToRule( sal_uInt32 _nRule )
+{
+ OSQLParser::RuleIDMap::const_iterator i (s_aReverseRuleIDLookup.find(_nRule));
+ if (i == s_aReverseRuleIDLookup.end())
+ {
+ SAL_INFO("connectivity.parse",
+ "connectivity::OSQLParser::RuleIDToRule cannot reverse-lookup rule. "
+ "Reverse mapping incomplete? "
+ "_nRule='" << _nRule << "' "
+ "yytname[_nRule]='" << yytname[_nRule] << "'");
+ return OSQLParseNode::UNKNOWN_RULE;
+ }
+ else
+ return i->second;
+}
+
+
+sal_uInt32 OSQLParser::RuleID(OSQLParseNode::Rule eRule)
+{
+ return s_nRuleIDs[(sal_uInt16)eRule];
+}
+
+sal_Int16 OSQLParser::buildNode(OSQLParseNode*& pAppend,OSQLParseNode* pCompare,OSQLParseNode* pLiteral,OSQLParseNode* pLiteral2)
+{
+ OSQLParseNode* pColumnRef = new OSQLInternalNode("", SQLNodeType::Rule,OSQLParser::RuleID(OSQLParseNode::column_ref));
+ pColumnRef->append(new OSQLInternalNode(m_sFieldName,SQLNodeType::Name));
+ OSQLParseNode* pComp = nullptr;
+ if ( SQL_ISTOKEN( pCompare, BETWEEN) && pLiteral2 )
+ pComp = new OSQLInternalNode("", SQLNodeType::Rule,OSQLParser::RuleID(OSQLParseNode::between_predicate_part_2));
+ else
+ pComp = new OSQLInternalNode("", SQLNodeType::Rule,OSQLParser::RuleID(OSQLParseNode::comparison_predicate));
+
+ pComp->append(pColumnRef);
+ pComp->append(pCompare);
+ pComp->append(pLiteral);
+ if ( pLiteral2 )
+ {
+ pComp->append(new OSQLInternalNode("", SQLNodeType::Keyword,SQL_TOKEN_AND));
+ pComp->append(pLiteral2);
+ }
+ pAppend->append(pComp);
+ return 1;
+}
+
+sal_Int16 OSQLParser::buildStringNodes(OSQLParseNode*& pLiteral)
+{
+ if(!pLiteral)
+ return 1;
+
+ if(SQL_ISRULE(pLiteral,set_fct_spec) || SQL_ISRULE(pLiteral,general_set_fct) || SQL_ISRULE(pLiteral,column_ref)
+ || SQL_ISRULE(pLiteral,subquery))
+ return 1; // here I have a function that I can't transform into a string
+
+ if(pLiteral->getNodeType() == SQLNodeType::IntNum || pLiteral->getNodeType() == SQLNodeType::ApproxNum || pLiteral->getNodeType() == SQLNodeType::AccessDate)
+ {
+ OSQLParseNode* pParent = pLiteral->getParent();
+
+ OSQLParseNode* pNewNode = new OSQLInternalNode(pLiteral->getTokenValue(), SQLNodeType::String);
+ pParent->replaceAndDelete(pLiteral, pNewNode);
+ pLiteral = nullptr;
+ return 1;
+ }
+
+ for(size_t i=0;i<pLiteral->count();++i)
+ {
+ OSQLParseNode* pChild = pLiteral->getChild(i);
+ buildStringNodes(pChild);
+ }
+ if(SQL_ISRULE(pLiteral,term) || SQL_ISRULE(pLiteral,value_exp_primary))
+ {
+ m_sErrorMessage = m_pContext->getErrorMessage(IParseContext::ErrorCode::InvalidCompare);
+ return 0;
+ }
+ return 1;
+}
+
+sal_Int16 OSQLParser::buildComparisonRule(OSQLParseNode*& pAppend,OSQLParseNode* pLiteral)
+{
+ OSQLParseNode* pComp = new OSQLInternalNode("=", SQLNodeType::Equal);
+ return buildPredicateRule(pAppend,pLiteral,pComp);
+}
+
+
+
+void OSQLParser::reduceLiteral(OSQLParseNode*& pLiteral, bool bAppendBlank)
+{
+ OSL_ENSURE(pLiteral->isRule(), "This is no Rule");
+ OSL_ENSURE(pLiteral->count() == 2, "OSQLParser::ReduceLiteral() Invalid count");
+ OSQLParseNode* pTemp = pLiteral;
+ OUStringBuffer aValue(pLiteral->getChild(0)->getTokenValue());
+ if (bAppendBlank)
+ {
+ aValue.append(" ");
+ }
+
+ aValue.append(pLiteral->getChild(1)->getTokenValue());
+
+ pLiteral = new OSQLInternalNode(aValue.makeStringAndClear(),SQLNodeType::String);
+ delete pTemp;
+}
+
+
+void OSQLParser::error(const char *fmt)
+{
+ if(m_sErrorMessage.isEmpty())
+ {
+ OUString sStr(fmt,strlen(fmt),RTL_TEXTENCODING_UTF8);
+ OUString sSQL_TOKEN("SQL_TOKEN_");
+
+ sal_Int32 nPos1 = sStr.indexOf(sSQL_TOKEN);
+ if(nPos1 != -1)
+ {
+ OUString sFirst = sStr.copy(0,nPos1);
+ sal_Int32 nPos2 = sStr.indexOf(sSQL_TOKEN,nPos1+1);
+ if(nPos2 != -1)
+ {
+ sFirst += sStr.subView(nPos1+sSQL_TOKEN.getLength(),nPos2-nPos1-sSQL_TOKEN.getLength());
+ sFirst += sStr.subView(nPos2+sSQL_TOKEN.getLength());
+ }
+ else
+ sFirst += sStr.subView(nPos1+sSQL_TOKEN.getLength());
+
+ m_sErrorMessage = sFirst;
+ }
+ else
+ m_sErrorMessage = sStr;
+
+ OUString aError = s_pScanner->getErrorMessage();
+ if(!aError.isEmpty())
+ {
+ m_sErrorMessage += ", ";
+ m_sErrorMessage += aError;
+ }
+ }
+}
+
+int OSQLParser::SQLlex()
+{
+ return OSQLScanner::SQLlex();
+}
diff --git a/connectivity/source/parse/sqlflex.l b/connectivity/source/parse/sqlflex.l
new file mode 100644
index 0000000000..44daeb236b
--- /dev/null
+++ b/connectivity/source/parse/sqlflex.l
@@ -0,0 +1,809 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+%{
+
+#include "sal/config.h"
+
+#define YY_EXIT 1 // YY_FATAL will not halt the application
+
+#ifndef _CSTDARG_
+#include <cstdarg>
+#endif
+
+#include <string.h>
+
+#if defined _MSC_VER
+#pragma warning ( push )
+// Silence warnings about redefinition of INT8_MIN etc in stdint.h
+// The flex-generated workdir/LexTarget/idlc/source/scanner.cxx defines them prior to these includes
+#pragma warning ( disable : 4005 )
+#endif
+#include <connectivity/internalnode.hxx>
+#if defined _MSC_VER
+#pragma warning(pop)
+#endif
+
+#ifndef INCLUDED_CONNECTIVITY_SOURCE_PARSE_SQLFLEX_L
+#define INCLUDED_CONNECTIVITY_SOURCE_PARSE_SQLFLEX_L
+
+#ifndef SQLYYDEBUG
+#define SQLYYDEBUG 1
+#endif
+
+#include "sqlbison.hxx"
+#undef SQLyylex
+#undef SQLyyerror
+#endif
+#include <osl/diagnose.h>
+#include <rtl/strbuf.hxx>
+#include <connectivity/sqlparse.hxx>
+#include <connectivity/sqlscan.hxx>
+
+#if defined _MSC_VER
+/**/
+#ifdef yywrap
+#undef yywrap
+#define yywrap() 1
+#endif
+/**/
+#endif
+#define YY_NO_UNISTD_H
+
+using namespace connectivity;
+
+// Creation of the pages for the tokens
+// Pages generally are created from the Lexer
+
+static sal_Int32 gatherString(int delim, sal_Int32 nTyp);
+static sal_Int32 gatherName(const char*);
+static sal_Int32 gatherNamePre(const char* );
+// has to be set before the parser starts
+OSQLScanner* xxx_pGLOBAL_SQLSCAN = nullptr;
+
+#define SQL_NEW_NODE(text, token) \
+ SQLyylval.pParseNode = new OSQLInternalNode(text, token);
+
+#define SQL_NEW_KEYWORD(token) \
+ SQLyylval.pParseNode = new OSQLInternalNode("", SQLNodeType::Keyword, (token)); return token;
+
+#define SQL_NEW_INTNUM SQL_NEW_NODE(OUString(SQLyytext,strlen(SQLyytext),RTL_TEXTENCODING_UTF8), SQLNodeType::IntNum); return SQL_TOKEN_INTNUM;
+#define SQL_NEW_APPROXNUM SQL_NEW_NODE(OUString(SQLyytext,strlen(SQLyytext),RTL_TEXTENCODING_UTF8), SQLNodeType::ApproxNum); return SQL_TOKEN_APPROXNUM;
+#define SQL_NEW_DATE SQL_NEW_NODE(OUString(SQLyytext,strlen(SQLyytext),RTL_TEXTENCODING_UTF8), SQLNodeType::AccessDate); return SQL_TOKEN_ACCESS_DATE;
+
+#define YY_INPUT(buf,result,max_size) \
+{ \
+ int c = xxx_pGLOBAL_SQLSCAN->SQLyygetc(); \
+ result = (c == EOF) ? YY_NULL : (buf[0] = c, 1);\
+}
+
+// coverity[+kill]
+static void do_fatal_error(const char* msg)
+{
+ xxx_pGLOBAL_SQLSCAN->SQLyyerror(msg);
+ /*hack to silence -Wunused-function*/
+ if ((0)) yy_fatal_error(msg);
+}
+
+#define YY_FATAL_ERROR(msg) \
+{ \
+ do_fatal_error(msg); \
+}
+
+%}
+
+%s SQL
+%s PREDICATE_ENG
+%s PREDICATE_GER
+%s DATE
+%s STRING
+
+%option noyywrap
+%option never-interactive
+%%
+
+ABS {SQL_NEW_KEYWORD(SQL_TOKEN_ABS); }
+ACOS {SQL_NEW_KEYWORD(SQL_TOKEN_ACOS); }
+AFTER {SQL_NEW_KEYWORD(SQL_TOKEN_AFTER); }
+ALL {SQL_NEW_KEYWORD(SQL_TOKEN_ALL); }
+ALTER {SQL_NEW_KEYWORD(SQL_TOKEN_ALTER); }
+AND {SQL_NEW_KEYWORD(SQL_TOKEN_AND); }
+ANY {SQL_NEW_KEYWORD(SQL_TOKEN_ANY); }
+ARRAY_AGG {SQL_NEW_KEYWORD(SQL_TOKEN_ARRAY_AGG); }
+AS {SQL_NEW_KEYWORD(SQL_TOKEN_AS); }
+ASC {SQL_NEW_KEYWORD(SQL_TOKEN_ASC); }
+ASCII {SQL_NEW_KEYWORD(SQL_TOKEN_ASCII); }
+ASIN {SQL_NEW_KEYWORD(SQL_TOKEN_ASIN); }
+AT {SQL_NEW_KEYWORD(SQL_TOKEN_AT); }
+ATAN {SQL_NEW_KEYWORD(SQL_TOKEN_ATAN); }
+ATAN2 {SQL_NEW_KEYWORD(SQL_TOKEN_ATAN2); }
+ATOMIC {SQL_NEW_KEYWORD(SQL_TOKEN_ATOMIC); }
+AUTHORIZATION {SQL_NEW_KEYWORD(SQL_TOKEN_AUTHORIZATION); }
+AVG {SQL_NEW_KEYWORD(SQL_TOKEN_AVG); }
+
+BEFORE {SQL_NEW_KEYWORD(SQL_TOKEN_BEFORE); }
+BEGIN {SQL_NEW_KEYWORD(SQL_TOKEN_BEGIN); }
+BETWEEN {SQL_NEW_KEYWORD(SQL_TOKEN_BETWEEN); }
+BIGINT {SQL_NEW_KEYWORD(SQL_TOKEN_BIGINT); }
+BINARY {SQL_NEW_KEYWORD(SQL_TOKEN_BINARY); }
+BIT {SQL_NEW_KEYWORD(SQL_TOKEN_BIT); }
+BIT_LENGTH {SQL_NEW_KEYWORD(SQL_TOKEN_BIT_LENGTH); }
+BLOB {SQL_NEW_KEYWORD(SQL_TOKEN_BLOB); }
+BOTH {SQL_NEW_KEYWORD(SQL_TOKEN_BOTH); }
+BY {SQL_NEW_KEYWORD(SQL_TOKEN_BY); }
+
+CALL {SQL_NEW_KEYWORD(SQL_TOKEN_CALL); }
+CASE {SQL_NEW_KEYWORD(SQL_TOKEN_CASE); }
+CAST {SQL_NEW_KEYWORD(SQL_TOKEN_CAST); }
+CEILING {SQL_NEW_KEYWORD(SQL_TOKEN_CEILING); }
+CHAR {SQL_NEW_KEYWORD(SQL_TOKEN_CHAR); }
+CHARACTER {SQL_NEW_KEYWORD(SQL_TOKEN_CHARACTER); }
+CHAR(ACTER)?_LENGTH {SQL_NEW_KEYWORD(SQL_TOKEN_CHAR_LENGTH); }
+CHECK {SQL_NEW_KEYWORD(SQL_TOKEN_CHECK); }
+CLOB {SQL_NEW_KEYWORD(SQL_TOKEN_CLOB); }
+COALESCE {SQL_NEW_KEYWORD(SQL_TOKEN_COALESCE); }
+COLLATE {SQL_NEW_KEYWORD(SQL_TOKEN_COLLATE); }
+COLLECT {SQL_NEW_KEYWORD(SQL_TOKEN_COLLECT); }
+COMMIT {SQL_NEW_KEYWORD(SQL_TOKEN_COMMIT); }
+CONCAT {SQL_NEW_KEYWORD(SQL_TOKEN_CONCAT); }
+CONTINUE {SQL_NEW_KEYWORD(SQL_TOKEN_CONTINUE); }
+CONVERT {SQL_NEW_KEYWORD(SQL_TOKEN_CONVERT); }
+COS {SQL_NEW_KEYWORD(SQL_TOKEN_COS); }
+COT {SQL_NEW_KEYWORD(SQL_TOKEN_COT); }
+COUNT {SQL_NEW_KEYWORD(SQL_TOKEN_COUNT); }
+CREATE {SQL_NEW_KEYWORD(SQL_TOKEN_CREATE); }
+CROSS {SQL_NEW_KEYWORD(SQL_TOKEN_CROSS); }
+CUME_RANK {SQL_NEW_KEYWORD(SQL_TOKEN_CUME_DIST); }
+CURRENT {SQL_NEW_KEYWORD(SQL_TOKEN_CURRENT); }
+CURRENT_DATE {SQL_NEW_KEYWORD(SQL_TOKEN_CURRENT_DATE); }
+CURRENT_CATALOG {SQL_NEW_KEYWORD(SQL_TOKEN_CURRENT_CATALOG); }
+CURRENT_DEFAULT_TRANSFORM_GROUP {SQL_NEW_KEYWORD(SQL_TOKEN_CURRENT_DEFAULT_TRANSFORM_GROUP); }
+CURRENT_PATH {SQL_NEW_KEYWORD(SQL_TOKEN_CURRENT_PATH); }
+CURRENT_ROLE {SQL_NEW_KEYWORD(SQL_TOKEN_CURRENT_ROLE); }
+CURRENT_SCHEMA {SQL_NEW_KEYWORD(SQL_TOKEN_CURRENT_SCHEMA); }
+CURRENT_USER {SQL_NEW_KEYWORD(SQL_TOKEN_CURRENT_USER); }
+CURDATE {SQL_NEW_KEYWORD(SQL_TOKEN_CURDATE); }
+CURRENT_TIME {SQL_NEW_KEYWORD(SQL_TOKEN_CURRENT_TIME); }
+CURTIME {SQL_NEW_KEYWORD(SQL_TOKEN_CURTIME); }
+CURRENT_TIMESTAMP {SQL_NEW_KEYWORD(SQL_TOKEN_CURRENT_TIMESTAMP); }
+CURSOR {SQL_NEW_KEYWORD(SQL_TOKEN_CURSOR); }
+
+D {SQL_NEW_KEYWORD(SQL_TOKEN_D); }
+DATE {SQL_NEW_KEYWORD(SQL_TOKEN_DATE); }
+DATEADD {SQL_NEW_KEYWORD(SQL_TOKEN_DATEADD); }
+DATEDIFF {SQL_NEW_KEYWORD(SQL_TOKEN_DATEDIFF); }
+DATEVALUE {SQL_NEW_KEYWORD(SQL_TOKEN_DATEVALUE); }
+DAY {SQL_NEW_KEYWORD(SQL_TOKEN_DAY); }
+DAYNAME {SQL_NEW_KEYWORD(SQL_TOKEN_DAYNAME); }
+DAYOFMONTH {SQL_NEW_KEYWORD(SQL_TOKEN_DAYOFMONTH); }
+DAYOFWEEK {SQL_NEW_KEYWORD(SQL_TOKEN_DAYOFWEEK); }
+DAYOFYEAR {SQL_NEW_KEYWORD(SQL_TOKEN_DAYOFYEAR); }
+DEC {SQL_NEW_KEYWORD(SQL_TOKEN_DEC); }
+DECIMAL {SQL_NEW_KEYWORD(SQL_TOKEN_DECIMAL); }
+DECLARE {SQL_NEW_KEYWORD(SQL_TOKEN_DECLARE); }
+DEFAULT {SQL_NEW_KEYWORD(SQL_TOKEN_DEFAULT); }
+DEGREES {SQL_NEW_KEYWORD(SQL_TOKEN_DEGREES); }
+DELETE {SQL_NEW_KEYWORD(SQL_TOKEN_DELETE); }
+DENSE_RANK {SQL_NEW_KEYWORD(SQL_TOKEN_DENSE_RANK); }
+DESC {SQL_NEW_KEYWORD(SQL_TOKEN_DESC); }
+DIFFERENCE {SQL_NEW_KEYWORD(SQL_TOKEN_DIFFERENCE); }
+DISTINCT {SQL_NEW_KEYWORD(SQL_TOKEN_DISTINCT); }
+DOUBLE {SQL_NEW_KEYWORD(SQL_TOKEN_DOUBLE); }
+DROP {SQL_NEW_KEYWORD(SQL_TOKEN_DROP); }
+
+EACH {SQL_NEW_KEYWORD(SQL_TOKEN_EACH); }
+ELSE {SQL_NEW_KEYWORD(SQL_TOKEN_ELSE); }
+END {SQL_NEW_KEYWORD(SQL_TOKEN_END); }
+EVERY {SQL_NEW_KEYWORD(SQL_TOKEN_EVERY); }
+ESCAPE {SQL_NEW_KEYWORD(SQL_TOKEN_ESCAPE); }
+EXCEPT {SQL_NEW_KEYWORD(SQL_TOKEN_EXCEPT); }
+EXCLUDE {SQL_NEW_KEYWORD(SQL_TOKEN_EXCLUDE); }
+EXISTS {SQL_NEW_KEYWORD(SQL_TOKEN_EXISTS); }
+EXP {SQL_NEW_KEYWORD(SQL_TOKEN_EXP); }
+EXTRACT {SQL_NEW_KEYWORD(SQL_TOKEN_EXTRACT); }
+
+FALSE {SQL_NEW_KEYWORD(SQL_TOKEN_FALSE); }
+FETCH {SQL_NEW_KEYWORD(SQL_TOKEN_FETCH); }
+FIRST {SQL_NEW_KEYWORD(SQL_TOKEN_FIRST); }
+FIRST_VALUE {SQL_NEW_KEYWORD(SQL_TOKEN_FIRST_VALUE); }
+FLOAT {SQL_NEW_KEYWORD(SQL_TOKEN_FLOAT); }
+FLOOR {SQL_NEW_KEYWORD(SQL_TOKEN_FLOOR); }
+FN {SQL_NEW_KEYWORD(SQL_TOKEN_FN); }
+FOLLOWING {SQL_NEW_KEYWORD(SQL_TOKEN_FOLLOWING); }
+FOR {SQL_NEW_KEYWORD(SQL_TOKEN_FOR); }
+FOREIGN {SQL_NEW_KEYWORD(SQL_TOKEN_FOREIGN); }
+FOUND {SQL_NEW_KEYWORD(SQL_TOKEN_FOUND); }
+FROM {SQL_NEW_KEYWORD(SQL_TOKEN_FROM); }
+FULL {SQL_NEW_KEYWORD(SQL_TOKEN_FULL); }
+FUSION {SQL_NEW_KEYWORD(SQL_TOKEN_FUSION); }
+
+GRANT {SQL_NEW_KEYWORD(SQL_TOKEN_GRANT); }
+GROUP {SQL_NEW_KEYWORD(SQL_TOKEN_GROUP); }
+
+HAVING {SQL_NEW_KEYWORD(SQL_TOKEN_HAVING); }
+HOUR {SQL_NEW_KEYWORD(SQL_TOKEN_HOUR); }
+
+IGNORE {SQL_NEW_KEYWORD(SQL_TOKEN_IGNORE); }
+IN {SQL_NEW_KEYWORD(SQL_TOKEN_IN); }
+INNER {SQL_NEW_KEYWORD(SQL_TOKEN_INNER); }
+INSERT {SQL_NEW_KEYWORD(SQL_TOKEN_INSERT); }
+INSTEAD {SQL_NEW_KEYWORD(SQL_TOKEN_INSTEAD); }
+INT(EGER)? {SQL_NEW_KEYWORD(SQL_TOKEN_INTEGER); }
+INTERSECT {SQL_NEW_KEYWORD(SQL_TOKEN_INTERSECT); }
+INTERVAL {SQL_NEW_KEYWORD(SQL_TOKEN_INTERVAL); }
+INTERSECTION {SQL_NEW_KEYWORD(SQL_TOKEN_INTERSECTION); }
+INTO {SQL_NEW_KEYWORD(SQL_TOKEN_INTO); }
+IS {SQL_NEW_KEYWORD(SQL_TOKEN_IS); }
+
+JOIN {SQL_NEW_KEYWORD(SQL_TOKEN_JOIN); }
+
+KEY {SQL_NEW_KEYWORD(SQL_TOKEN_KEY); }
+
+LAG {SQL_NEW_KEYWORD(SQL_TOKEN_LAG); }
+LARGE {SQL_NEW_KEYWORD(SQL_TOKEN_LARGE); }
+LAST {SQL_NEW_KEYWORD(SQL_TOKEN_LAST); }
+LAST_VALUE {SQL_NEW_KEYWORD(SQL_TOKEN_LAST_VALUE); }
+LCASE {SQL_NEW_KEYWORD(SQL_TOKEN_LCASE); }
+LEAD {SQL_NEW_KEYWORD(SQL_TOKEN_LEAD); }
+LEADING {SQL_NEW_KEYWORD(SQL_TOKEN_LEADING); }
+LEFT {SQL_NEW_KEYWORD(SQL_TOKEN_LEFT); }
+LENGTH {SQL_NEW_KEYWORD(SQL_TOKEN_LENGTH); }
+LIKE {SQL_NEW_KEYWORD(SQL_TOKEN_LIKE); }
+LIMIT {SQL_NEW_KEYWORD(SQL_TOKEN_LIMIT); }
+LN {SQL_NEW_KEYWORD(SQL_TOKEN_LN); }
+LOCAL {SQL_NEW_KEYWORD(SQL_TOKEN_LOCAL); }
+LOCATE {SQL_NEW_KEYWORD(SQL_TOKEN_LOCATE); }
+LOG {SQL_NEW_KEYWORD(SQL_TOKEN_LOG); }
+LOGF {SQL_NEW_KEYWORD(SQL_TOKEN_LOGF); }
+LOG10 {SQL_NEW_KEYWORD(SQL_TOKEN_LOG10); }
+LOWER {SQL_NEW_KEYWORD(SQL_TOKEN_LOWER); }
+LTRIM {SQL_NEW_KEYWORD(SQL_TOKEN_LTRIM); }
+
+MAX {SQL_NEW_KEYWORD(SQL_TOKEN_MAX); }
+MILLISECOND {SQL_NEW_KEYWORD(SQL_TOKEN_MILLISECOND); }
+MIN {SQL_NEW_KEYWORD(SQL_TOKEN_MIN); }
+MINUTE {SQL_NEW_KEYWORD(SQL_TOKEN_MINUTE); }
+MOD {SQL_NEW_KEYWORD(SQL_TOKEN_MOD); }
+MONTH {SQL_NEW_KEYWORD(SQL_TOKEN_MONTH); }
+MONTHNAME {SQL_NEW_KEYWORD(SQL_TOKEN_MONTHNAME); }
+
+NATIONAL {SQL_NEW_KEYWORD(SQL_TOKEN_NATIONAL); }
+NATURAL {SQL_NEW_KEYWORD(SQL_TOKEN_NATURAL); }
+NCHAR {SQL_NEW_KEYWORD(SQL_TOKEN_NCHAR); }
+NCLOB {SQL_NEW_KEYWORD(SQL_TOKEN_NCLOB); }
+NEW {SQL_NEW_KEYWORD(SQL_TOKEN_NEW); }
+NEXT {SQL_NEW_KEYWORD(SQL_TOKEN_NEXT); }
+NO {SQL_NEW_KEYWORD(SQL_TOKEN_NO); }
+NOT {SQL_NEW_KEYWORD(SQL_TOKEN_NOT); }
+NOW {SQL_NEW_KEYWORD(SQL_TOKEN_NOW); }
+NTH_VALUE {SQL_NEW_KEYWORD(SQL_TOKEN_NTH_VALUE); }
+NTILE {SQL_NEW_KEYWORD(SQL_TOKEN_NTILE); }
+NULL {SQL_NEW_KEYWORD(SQL_TOKEN_NULL); }
+NULLIF {SQL_NEW_KEYWORD(SQL_TOKEN_NULLIF); }
+NULLS {SQL_NEW_KEYWORD(SQL_TOKEN_NULLS); }
+NUMERIC {SQL_NEW_KEYWORD(SQL_TOKEN_NUMERIC); }
+
+OBJECT {SQL_NEW_KEYWORD(SQL_TOKEN_OBJECT); }
+OCTET_LENGTH {SQL_NEW_KEYWORD(SQL_TOKEN_OCTET_LENGTH); }
+OF {SQL_NEW_KEYWORD(SQL_TOKEN_OF); }
+OFFSET {SQL_NEW_KEYWORD(SQL_TOKEN_OFFSET); }
+OJ {SQL_NEW_KEYWORD(SQL_TOKEN_OJ); }
+OLD {SQL_NEW_KEYWORD(SQL_TOKEN_OLD); }
+ON {SQL_NEW_KEYWORD(SQL_TOKEN_ON); }
+ONLY {SQL_NEW_KEYWORD(SQL_TOKEN_ONLY); }
+OPTION {SQL_NEW_KEYWORD(SQL_TOKEN_OPTION); }
+OR {SQL_NEW_KEYWORD(SQL_TOKEN_OR); }
+ORDER {SQL_NEW_KEYWORD(SQL_TOKEN_ORDER); }
+OTHERS {SQL_NEW_KEYWORD(SQL_TOKEN_OTHERS); }
+OUTER {SQL_NEW_KEYWORD(SQL_TOKEN_OUTER); }
+OVER {SQL_NEW_KEYWORD(SQL_TOKEN_OVER); }
+
+PARTITION {SQL_NEW_KEYWORD(SQL_TOKEN_PARTITION); }
+PERCENT_RANK {SQL_NEW_KEYWORD(SQL_TOKEN_PERCENT_RANK); }
+PERCENTILE_CONT {SQL_NEW_KEYWORD(SQL_TOKEN_PERCENTILE_CONT); }
+PERCENTILE_DISC {SQL_NEW_KEYWORD(SQL_TOKEN_PERCENTILE_DISC); }
+PI {SQL_NEW_KEYWORD(SQL_TOKEN_PI); }
+POSITION {SQL_NEW_KEYWORD(SQL_TOKEN_POSITION); }
+POWER {SQL_NEW_KEYWORD(SQL_TOKEN_POWER); }
+PRECEDING {SQL_NEW_KEYWORD(SQL_TOKEN_PRECEDING); }
+PRECISION {SQL_NEW_KEYWORD(SQL_TOKEN_PRECISION); }
+PRIMARY {SQL_NEW_KEYWORD(SQL_TOKEN_PRIMARY); }
+PRIVILEGES {SQL_NEW_KEYWORD(SQL_TOKEN_PRIVILEGES); }
+PROCEDURE {SQL_NEW_KEYWORD(SQL_TOKEN_PROCEDURE); }
+PUBLIC {SQL_NEW_KEYWORD(SQL_TOKEN_PUBLIC); }
+
+QUARTER {SQL_NEW_KEYWORD(SQL_TOKEN_QUARTER); }
+
+RADIANS {SQL_NEW_KEYWORD(SQL_TOKEN_RADIANS); }
+RAND {SQL_NEW_KEYWORD(SQL_TOKEN_RAND); }
+RANGE {SQL_NEW_KEYWORD(SQL_TOKEN_RANGE); }
+RANK {SQL_NEW_KEYWORD(SQL_TOKEN_RANK); }
+REAL {SQL_NEW_KEYWORD(SQL_TOKEN_REAL); }
+REFERENCES {SQL_NEW_KEYWORD(SQL_TOKEN_REFERENCES); }
+REFERENCING {SQL_NEW_KEYWORD(SQL_TOKEN_REFERENCING); }
+REPEAT {SQL_NEW_KEYWORD(SQL_TOKEN_REPEAT); }
+REPLACE {SQL_NEW_KEYWORD(SQL_TOKEN_REPLACE); }
+RESPECT {SQL_NEW_KEYWORD(SQL_TOKEN_RESPECT); }
+ROLLBACK {SQL_NEW_KEYWORD(SQL_TOKEN_ROLLBACK); }
+ROUND {SQL_NEW_KEYWORD(SQL_TOKEN_ROUND); }
+ROUNDMAGIC {SQL_NEW_KEYWORD(SQL_TOKEN_ROUNDMAGIC); }
+ROW {SQL_NEW_KEYWORD(SQL_TOKEN_ROW); }
+ROWS {SQL_NEW_KEYWORD(SQL_TOKEN_ROWS); }
+ROW_NUMBER {SQL_NEW_KEYWORD(SQL_TOKEN_ROW_NUMBER); }
+RIGHT {SQL_NEW_KEYWORD(SQL_TOKEN_RIGHT); }
+RTRIM {SQL_NEW_KEYWORD(SQL_TOKEN_RTRIM); }
+
+SCHEMA {SQL_NEW_KEYWORD(SQL_TOKEN_SCHEMA); }
+SECOND {SQL_NEW_KEYWORD(SQL_TOKEN_SECOND); }
+SELECT {SQL_NEW_KEYWORD(SQL_TOKEN_SELECT); }
+SET {SQL_NEW_KEYWORD(SQL_TOKEN_SET); }
+SIZE {SQL_NEW_KEYWORD(SQL_TOKEN_SIZE); }
+SIGN {SQL_NEW_KEYWORD(SQL_TOKEN_SIGN); }
+SIN {SQL_NEW_KEYWORD(SQL_TOKEN_SIN); }
+SMALLINT {SQL_NEW_KEYWORD(SQL_TOKEN_SMALLINT); }
+SOME {SQL_NEW_KEYWORD(SQL_TOKEN_SOME); }
+SOUNDEX {SQL_NEW_KEYWORD(SQL_TOKEN_SOUNDEX); }
+SPACE {SQL_NEW_KEYWORD(SQL_TOKEN_SPACE); }
+SQRT {SQL_NEW_KEYWORD(SQL_TOKEN_SQRT); }
+STDDEV_POP {SQL_NEW_KEYWORD(SQL_TOKEN_STDDEV_POP); }
+STDDEV_SAMP {SQL_NEW_KEYWORD(SQL_TOKEN_STDDEV_SAMP); }
+STATEMENT {SQL_NEW_KEYWORD(SQL_TOKEN_STATEMENT); }
+SUBSTRING {SQL_NEW_KEYWORD(SQL_TOKEN_SUBSTRING); }
+SUM {SQL_NEW_KEYWORD(SQL_TOKEN_SUM); }
+SESSION_USER {SQL_NEW_KEYWORD(SQL_TOKEN_SESSION_USER); }
+SYSTEM_USER {SQL_NEW_KEYWORD(SQL_TOKEN_SYSTEM_USER); }
+
+TABLE {SQL_NEW_KEYWORD(SQL_TOKEN_TABLE); }
+TAN {SQL_NEW_KEYWORD(SQL_TOKEN_TAN); }
+THEN {SQL_NEW_KEYWORD(SQL_TOKEN_THEN); }
+TIES {SQL_NEW_KEYWORD(SQL_TOKEN_TIES); }
+TIME {SQL_NEW_KEYWORD(SQL_TOKEN_TIME); }
+TIMESTAMP {SQL_NEW_KEYWORD(SQL_TOKEN_TIMESTAMP); }
+TIMESTAMPADD {SQL_NEW_KEYWORD(SQL_TOKEN_TIMESTAMPADD); }
+TIMESTAMPDIFF {SQL_NEW_KEYWORD(SQL_TOKEN_TIMESTAMPDIFF); }
+TIMEVALUE {SQL_NEW_KEYWORD(SQL_TOKEN_TIMEVALUE); }
+TIMEZONE_HOUR {SQL_NEW_KEYWORD(SQL_TOKEN_TIMEZONE_HOUR); }
+TIMEZONE_MINUTE {SQL_NEW_KEYWORD(SQL_TOKEN_TIMEZONE_MINUTE); }
+TO {SQL_NEW_KEYWORD(SQL_TOKEN_TO); }
+TRAILING {SQL_NEW_KEYWORD(SQL_TOKEN_TRAILING); }
+TRANSLATE {SQL_NEW_KEYWORD(SQL_TOKEN_TRANSLATE); }
+TRIGGER {SQL_NEW_KEYWORD(SQL_TOKEN_TRIGGER); }
+TRIM {SQL_NEW_KEYWORD(SQL_TOKEN_TRIM); }
+TRUE {SQL_NEW_KEYWORD(SQL_TOKEN_TRUE); }
+TRUNCATE {SQL_NEW_KEYWORD(SQL_TOKEN_TRUNCATE); }
+TS {SQL_NEW_KEYWORD(SQL_TOKEN_TS); }
+T {SQL_NEW_KEYWORD(SQL_TOKEN_T); }
+
+UCASE {SQL_NEW_KEYWORD(SQL_TOKEN_UCASE); }
+UNBOUNDED {SQL_NEW_KEYWORD(SQL_TOKEN_UNBOUNDED); }
+UNION {SQL_NEW_KEYWORD(SQL_TOKEN_UNION); }
+UNIQUE {SQL_NEW_KEYWORD(SQL_TOKEN_UNIQUE); }
+UNKNOWN {SQL_NEW_KEYWORD(SQL_TOKEN_UNKNOWN); }
+UPDATE {SQL_NEW_KEYWORD(SQL_TOKEN_UPDATE); }
+UPPER {SQL_NEW_KEYWORD(SQL_TOKEN_UPPER); }
+USAGE {SQL_NEW_KEYWORD(SQL_TOKEN_USAGE); }
+USER {SQL_NEW_KEYWORD(SQL_TOKEN_USER); }
+USING {SQL_NEW_KEYWORD(SQL_TOKEN_USING); }
+
+VARBINARY {SQL_NEW_KEYWORD(SQL_TOKEN_VARBINARY); }
+VARCHAR {SQL_NEW_KEYWORD(SQL_TOKEN_VARCHAR); }
+VARYING {SQL_NEW_KEYWORD(SQL_TOKEN_VARYING); }
+VAR_POP {SQL_NEW_KEYWORD(SQL_TOKEN_VAR_POP); }
+VAR_SAMP {SQL_NEW_KEYWORD(SQL_TOKEN_VAR_SAMP); }
+VALUE {SQL_NEW_KEYWORD(SQL_TOKEN_VALUE); }
+VALUES {SQL_NEW_KEYWORD(SQL_TOKEN_VALUES); }
+VIEW {SQL_NEW_KEYWORD(SQL_TOKEN_VIEW); }
+
+WEEK {SQL_NEW_KEYWORD(SQL_TOKEN_WEEK); }
+WEEKDAY {SQL_NEW_KEYWORD(SQL_TOKEN_WEEKDAY); }
+WHEN {SQL_NEW_KEYWORD(SQL_TOKEN_WHEN); }
+WHERE {SQL_NEW_KEYWORD(SQL_TOKEN_WHERE); }
+WITH {SQL_NEW_KEYWORD(SQL_TOKEN_WITH); }
+WITHIN {SQL_NEW_KEYWORD(SQL_TOKEN_WITHIN); }
+WITHOUT {SQL_NEW_KEYWORD(SQL_TOKEN_WITHOUT); }
+WORK {SQL_NEW_KEYWORD(SQL_TOKEN_WORK); }
+
+YEAR {SQL_NEW_KEYWORD(SQL_TOKEN_YEAR); }
+YEARDAY {SQL_NEW_KEYWORD(SQL_TOKEN_YEARDAY); }
+
+ZONE {SQL_NEW_KEYWORD(SQL_TOKEN_ZONE); }
+
+"<" { SQL_NEW_NODE(OUString(SQLyytext,strlen(SQLyytext),RTL_TEXTENCODING_UTF8), SQLNodeType::Less);return SQL_LESS;}
+">" { SQL_NEW_NODE(OUString(SQLyytext,strlen(SQLyytext),RTL_TEXTENCODING_UTF8), SQLNodeType::Great);return SQL_GREAT;}
+"=" { SQL_NEW_NODE(OUString(SQLyytext,strlen(SQLyytext),RTL_TEXTENCODING_UTF8), SQLNodeType::Equal);return SQL_EQUAL;}
+"<=" { SQL_NEW_NODE(OUString(SQLyytext,strlen(SQLyytext),RTL_TEXTENCODING_UTF8), SQLNodeType::LessEq);return SQL_LESSEQ;}
+">=" { SQL_NEW_NODE(OUString(SQLyytext,strlen(SQLyytext),RTL_TEXTENCODING_UTF8), SQLNodeType::GreatEq);return SQL_GREATEQ;}
+"<>" { SQL_NEW_NODE(OUString(SQLyytext,strlen(SQLyytext),RTL_TEXTENCODING_UTF8), SQLNodeType::NotEqual);return SQL_NOTEQUAL;}
+"!=" { SQL_NEW_NODE(OUString(SQLyytext,strlen(SQLyytext),RTL_TEXTENCODING_UTF8), SQLNodeType::NotEqual);return SQL_NOTEQUAL;}
+"||" { SQL_NEW_NODE(OUString(SQLyytext,strlen(SQLyytext),RTL_TEXTENCODING_UTF8), SQLNodeType::Concat);return SQL_CONCAT;}
+
+
+[-+*/:(),.;?{}] { return SQLyytext[0]; }
+
+
+<SQL>[A-Za-z\200-\277\300-\337\340-\357\360-\367\370-\373\374-\375][A-Za-z\200-\277\300-\337\340-\357\360-\367\370-\373\374-\375_0-9]* {return gatherName( SQLyytext);}
+
+<SQL>([0-9]+) {SQL_NEW_INTNUM; }
+
+<SQL>("."[0-9]*) |
+<SQL>([0-9]+"."[0-9]*) |
+<SQL>[0-9]+[eE][+-]?[0-9]+ |
+<SQL>[0-9]+"."[0-9]*[eE][+-]?[0-9]+ |
+<SQL>"."[0-9]*[eE][+-]?[0-9]+ {SQL_NEW_APPROXNUM; }
+
+<PREDICATE_GER,PREDICATE_ENG,DATE>[A-Za-z\200-\277\300-\337\340-\357\360-\367\370-\373\374-\375][A-Za-z0-9_%.,*?\200-\277\300-\337\340-\357\360-\367\370-\373\374-\375]* {return gatherNamePre(SQLyytext);}
+
+<PREDICATE_GER,PREDICATE_ENG>([0-9]+) {SQL_NEW_INTNUM; }
+<PREDICATE_ENG>([0-9]{1,3}(","[0-9]{3})+) {SQL_NEW_INTNUM; }
+<PREDICATE_GER>([0-9]{1,3}("."[0-9]{3})+) {SQL_NEW_INTNUM; }
+
+<PREDICATE_ENG>([0-9]+"."[0-9]+) |
+<PREDICATE_ENG>([0-9]{1,3}(","[0-9]{3})+"."[0-9]+) |
+<PREDICATE_ENG>("."[0-9]+) {SQL_NEW_APPROXNUM; }
+<PREDICATE_ENG>[0-9]+[eE][+-]?[0-9]+ |
+<PREDICATE_ENG>[0-9]+"."[0-9]*[eE][+-]?[0-9]+ |
+<PREDICATE_ENG>"."[0-9]*[eE][+-]?[0-9]+ {SQL_NEW_APPROXNUM; }
+
+<PREDICATE_GER>([0-9]+","[0-9]+) |
+<PREDICATE_GER>([0-9]{1,3}("."[0-9]{3})+","[0-9]+) |
+<PREDICATE_GER>(","[0-9]+) {SQL_NEW_APPROXNUM; }
+<PREDICATE_GER>[0-9]+[eE][+-]?[0-9]+ |
+<PREDICATE_GER>[0-9]+","[0-9]*[eE][+-]?[0-9]+ |
+<PREDICATE_GER>","[0-9]*[eE][+-]?[0-9]+ {SQL_NEW_APPROXNUM; }
+
+<PREDICATE_GER,PREDICATE_ENG>[0-9.,][A-Za-z0-9_.,%]* {return gatherNamePre(SQLyytext);}
+
+<SQL>\" { return gatherString('\"',0); }
+<SQL>` { return gatherString('`' ,0); }
+
+<PREDICATE_GER,PREDICATE_ENG,DATE,SQL>"[" { return gatherString(']' ,0);}
+
+\' { return gatherString('\'',1); }
+
+<PREDICATE_GER,PREDICATE_ENG,DATE># { return gatherString('#' ,2); }
+
+<DATE>[0-9]{1,4}[^ ]*[0-9] |
+<DATE>[0-9]{1,4}[^ ]*[0-9][ ][0-9]{1,4}[^ ]*[0-9] { SQL_NEW_DATE; }
+
+<STRING>["-""+""*""/"":""("")"",""."";""?""{""}"] { return SQLyytext[0]; } /* */
+<STRING>"[" { return gatherString(']' ,0); }
+<STRING>[^ ':["?"]* { return gatherNamePre(SQLyytext); }
+
+\n {}
+
+[ \t\r]+ {}
+
+"--".*$ {}
+
+. {YY_FATAL_ERROR("Invalid symbol"); return SQL_TOKEN_INVALIDSYMBOL;}
+
+%%
+
+// Kludge around a bug (well, Posix incompatibility) in flex 2.5.x
+// http://bugs.debian.org/cgi-bin/bugreport.cgi?archive=no&bug=189332
+#if YY_FLEX_MAJOR_VERSION >= 2 && YY_FLEX_MINOR_VERSION >= 5
+
+ #ifndef YY_FLUSH_BUFFER
+ #define YY_FLUSH_BUFFER SQLyy_flush_buffer(YY_CURRENT_BUFFER )
+ #endif
+
+ #ifndef yytext_ptr
+ #define yytext_ptr SQLyytext
+ #endif
+
+#endif
+
+// Versions of flex apparently differ in whether input() resp. yyinput() returns
+// zero or EOF upon end of file:
+inline bool checkeof(int c) { return c == 0 || c == EOF; }
+
+/*
+ * Read SQL string literal
+ * Valid strings:
+ * '' 'a string' 'quote '' within string'
+ * "" "a string" "quote "" within string"
+ * nTyp == 0 -> SQLNodeType::Name
+ * nTyp == 1 -> SQLNodeType::String
+ * nTyp == 2 -> SQLNodeType::AccessDate
+ */
+sal_Int32 gatherString(int delim, sal_Int32 nTyp)
+{
+ int ch;
+ OStringBuffer sBuffer(256);
+
+ assert(nTyp == 0 || nTyp == 1 || nTyp == 2);
+
+ while (!checkeof(ch = yyinput()))
+ {
+ if (ch == delim)
+ {
+ if ((ch = yyinput()) != delim)
+ {
+ if (!checkeof(ch))
+ unput(ch);
+
+ switch(nTyp)
+ {
+ case 0:
+ SQL_NEW_NODE(OStringToOUString(sBuffer.makeStringAndClear(),RTL_TEXTENCODING_UTF8), SQLNodeType::Name);
+ return SQL_TOKEN_NAME;
+ case 1:
+ SQL_NEW_NODE(OStringToOUString(sBuffer.makeStringAndClear(),RTL_TEXTENCODING_UTF8), SQLNodeType::String);
+ return SQL_TOKEN_STRING;
+ case 2:
+ SQL_NEW_NODE(OStringToOUString(sBuffer.makeStringAndClear(),RTL_TEXTENCODING_UTF8), SQLNodeType::AccessDate);
+ return SQL_TOKEN_ACCESS_DATE;
+ }
+ }
+ else
+ {
+ sBuffer.append(static_cast<char>(ch));
+ }
+
+ }
+ else if (nTyp == 2 && (ch == '\r' || ch == '\n') )
+ break;
+ else
+ {
+ sBuffer.append(static_cast<char>(ch));
+ }
+ }
+ YY_FATAL_ERROR("Unterminated name string");
+ return SQL_TOKEN_INVALIDSYMBOL;
+}
+
+sal_Int32 mapEnumToToken(IParseContext::InternationalKeyCode _eKeyCode )
+{
+ sal_Int32 nTokenID = 0;
+ switch( _eKeyCode )
+ {
+ case IParseContext::InternationalKeyCode::Like: nTokenID = SQL_TOKEN_LIKE; break;
+ case IParseContext::InternationalKeyCode::Not: nTokenID = SQL_TOKEN_NOT; break;
+ case IParseContext::InternationalKeyCode::Null: nTokenID = SQL_TOKEN_NULL; break;
+ case IParseContext::InternationalKeyCode::True: nTokenID = SQL_TOKEN_TRUE; break;
+ case IParseContext::InternationalKeyCode::False: nTokenID = SQL_TOKEN_FALSE; break;
+ case IParseContext::InternationalKeyCode::Is: nTokenID = SQL_TOKEN_IS; break;
+ case IParseContext::InternationalKeyCode::Between: nTokenID = SQL_TOKEN_BETWEEN; break;
+ case IParseContext::InternationalKeyCode::Or: nTokenID = SQL_TOKEN_OR; break;
+ case IParseContext::InternationalKeyCode::And: nTokenID = SQL_TOKEN_AND; break;
+ case IParseContext::InternationalKeyCode::Avg: nTokenID = SQL_TOKEN_AVG; break;
+ case IParseContext::InternationalKeyCode::Count: nTokenID = SQL_TOKEN_COUNT; break;
+ case IParseContext::InternationalKeyCode::Max: nTokenID = SQL_TOKEN_MAX; break;
+ case IParseContext::InternationalKeyCode::Min: nTokenID = SQL_TOKEN_MIN; break;
+ case IParseContext::InternationalKeyCode::Sum: nTokenID = SQL_TOKEN_SUM; break;
+ case IParseContext::InternationalKeyCode::Every: nTokenID = SQL_TOKEN_EVERY; break;
+ case IParseContext::InternationalKeyCode::Any: nTokenID = SQL_TOKEN_ANY; break;
+ case IParseContext::InternationalKeyCode::Some: nTokenID = SQL_TOKEN_SOME; break;
+ case IParseContext::InternationalKeyCode::StdDevPop: nTokenID = SQL_TOKEN_STDDEV_POP; break;
+ case IParseContext::InternationalKeyCode::StdDevSamp: nTokenID = SQL_TOKEN_STDDEV_SAMP; break;
+ case IParseContext::InternationalKeyCode::VarSamp: nTokenID = SQL_TOKEN_VAR_SAMP; break;
+ case IParseContext::InternationalKeyCode::VarPop: nTokenID = SQL_TOKEN_VAR_POP; break;
+ case IParseContext::InternationalKeyCode::Collect: nTokenID = SQL_TOKEN_COLLECT; break;
+ case IParseContext::InternationalKeyCode::Fusion: nTokenID = SQL_TOKEN_FUSION; break;
+ case IParseContext::InternationalKeyCode::Intersection: nTokenID = SQL_TOKEN_INTERSECTION; break;
+ default:
+ OSL_FAIL( "mapEnumToToken: unsupported key!" );
+ }
+ return nTokenID;
+}
+/*
+ * Read SQL Name literal
+ * Valid Names or international keywords:
+ * As we have international keywords, we test first on them
+ */
+sal_Int32 gatherName(const char* text)
+{
+ sal_Int32 nToken;
+ OSL_ENSURE(xxx_pGLOBAL_SQLSCAN,"You forgot to set the scanner!");
+ IParseContext::InternationalKeyCode eKeyCode = xxx_pGLOBAL_SQLSCAN->getInternationalTokenID(text);
+ switch (eKeyCode)
+ {
+ case IParseContext::InternationalKeyCode::Like:
+ case IParseContext::InternationalKeyCode::Not:
+ case IParseContext::InternationalKeyCode::Null:
+ case IParseContext::InternationalKeyCode::True:
+ case IParseContext::InternationalKeyCode::False:
+ case IParseContext::InternationalKeyCode::Is:
+ case IParseContext::InternationalKeyCode::Between:
+ case IParseContext::InternationalKeyCode::Or:
+ case IParseContext::InternationalKeyCode::And:
+ case IParseContext::InternationalKeyCode::Count:
+ case IParseContext::InternationalKeyCode::Avg:
+ case IParseContext::InternationalKeyCode::Max:
+ case IParseContext::InternationalKeyCode::Min:
+ case IParseContext::InternationalKeyCode::Sum:
+ case IParseContext::InternationalKeyCode::Every:
+ case IParseContext::InternationalKeyCode::Any:
+ case IParseContext::InternationalKeyCode::Some:
+ case IParseContext::InternationalKeyCode::StdDevPop:
+ case IParseContext::InternationalKeyCode::StdDevSamp:
+ case IParseContext::InternationalKeyCode::VarSamp:
+ case IParseContext::InternationalKeyCode::VarPop:
+ case IParseContext::InternationalKeyCode::Collect:
+ case IParseContext::InternationalKeyCode::Fusion:
+ case IParseContext::InternationalKeyCode::Intersection:
+ nToken = mapEnumToToken(eKeyCode);
+ SQL_NEW_KEYWORD(nToken);
+ break;
+ default:
+ SQL_NEW_NODE(OUString(text,strlen(text),RTL_TEXTENCODING_UTF8), SQLNodeType::Name);
+ return SQL_TOKEN_NAME;
+ }
+}
+/**
+ Read SQL Name literal for predicate check
+ Valid Names or international keywords:
+ As we have international keywords, we test first on them
+*/
+sal_Int32 gatherNamePre(const char* text)
+{
+ sal_Int32 nToken;
+ OSL_ENSURE(xxx_pGLOBAL_SQLSCAN,"You forgot to set the scanner!");
+ IParseContext::InternationalKeyCode eKeyCode = xxx_pGLOBAL_SQLSCAN->getInternationalTokenID(text);
+ switch (eKeyCode)
+ {
+ case IParseContext::InternationalKeyCode::Like:
+ case IParseContext::InternationalKeyCode::Not:
+ case IParseContext::InternationalKeyCode::Null:
+ case IParseContext::InternationalKeyCode::True:
+ case IParseContext::InternationalKeyCode::False:
+ case IParseContext::InternationalKeyCode::Is:
+ case IParseContext::InternationalKeyCode::Between:
+ case IParseContext::InternationalKeyCode::Or:
+ case IParseContext::InternationalKeyCode::And:
+ case IParseContext::InternationalKeyCode::Count:
+ case IParseContext::InternationalKeyCode::Avg:
+ case IParseContext::InternationalKeyCode::Max:
+ case IParseContext::InternationalKeyCode::Min:
+ case IParseContext::InternationalKeyCode::Sum:
+ case IParseContext::InternationalKeyCode::Every:
+ case IParseContext::InternationalKeyCode::Any:
+ case IParseContext::InternationalKeyCode::Some:
+ case IParseContext::InternationalKeyCode::StdDevPop:
+ case IParseContext::InternationalKeyCode::StdDevSamp:
+ case IParseContext::InternationalKeyCode::VarSamp:
+ case IParseContext::InternationalKeyCode::VarPop:
+ case IParseContext::InternationalKeyCode::Collect:
+ case IParseContext::InternationalKeyCode::Fusion:
+ case IParseContext::InternationalKeyCode::Intersection:
+ nToken = mapEnumToToken(eKeyCode);
+ SQL_NEW_KEYWORD(nToken);
+ break;
+ default:
+ // we need a special handling for parameter
+ {
+ OString sStmt = xxx_pGLOBAL_SQLSCAN->getStatement();
+ sal_Int32 nLength = strlen(text);
+ sal_Int32 nPos = xxx_pGLOBAL_SQLSCAN->GetCurrentPos() - nLength - 2;
+ if (sStmt.getStr()[nPos] == ':')
+ {
+ SQL_NEW_NODE(OUString(text,nLength,RTL_TEXTENCODING_UTF8), SQLNodeType::Name);
+ nToken = SQL_TOKEN_NAME;
+ }
+ else
+ {
+ SQL_NEW_NODE(OUString(text,nLength,RTL_TEXTENCODING_UTF8), SQLNodeType::String);
+ nToken = SQL_TOKEN_STRING;
+ }
+ }
+ }
+ return nToken;
+}
+
+using namespace connectivity;
+
+static bool IN_SQLyyerror;
+//------------------------------------------------------------------------------
+OSQLScanner::OSQLScanner()
+ : m_pContext(nullptr)
+ , m_nCurrentPos(0)
+ , m_bInternational(false)
+ , m_nRule(0) // 0 is INITIAL
+{
+ IN_SQLyyerror = false;
+}
+
+//------------------------------------------------------------------------------
+OSQLScanner::~OSQLScanner()
+{
+}
+//------------------------------------------------------------------------------
+void OSQLScanner::SQLyyerror(char const *fmt)
+{
+
+ if(IN_SQLyyerror)
+ return;
+ IN_SQLyyerror = true;
+
+ OSL_ENSURE(m_pContext, "OSQLScanner::SQLyyerror: No Context set");
+ m_sErrorMessage = OUString(fmt,strlen(fmt),RTL_TEXTENCODING_UTF8);
+ if (m_nCurrentPos < m_sStatement.getLength())
+ {
+ m_sErrorMessage += ": ";
+
+ OUString aError;
+ OUStringBuffer Buffer(256);
+
+ int ch = SQLyytext ? (SQLyytext[0] == 0 ? ' ' : SQLyytext[0]): ' ';
+ Buffer.append((sal_Unicode)ch);
+ while (!checkeof(ch = yyinput()))
+ {
+ if (ch == ' ')
+ {
+ if ((ch = yyinput()) != ' ')
+ {
+ if (!checkeof(ch))
+ unput(ch);
+ }
+ aError = Buffer.makeStringAndClear();
+ break;
+ }
+ else
+ {
+ Buffer.append((sal_Unicode)ch);
+ }
+ }
+ m_sErrorMessage += aError;
+ }
+ IN_SQLyyerror = false;
+ YY_FLUSH_BUFFER;
+}
+
+//------------------------------------------------------------------------------
+void OSQLScanner::prepareScan(const OUString & rNewStatement, const IParseContext* pContext, bool bInternational)
+{
+ YY_FLUSH_BUFFER;
+ BEGIN(m_nRule);
+
+ m_sErrorMessage = OUString();
+ m_sStatement = OUStringToOString(rNewStatement, RTL_TEXTENCODING_UTF8);
+ m_nCurrentPos = 0;
+ m_bInternational = bInternational;
+ m_pContext = pContext;
+}
+
+//------------------------------------------------------------------------------
+sal_Int32 OSQLScanner::SQLyygetc(void)
+{
+ sal_Int32 nPos = (m_nCurrentPos >= m_sStatement.getLength()) ? EOF : m_sStatement.getStr()[m_nCurrentPos];
+ m_nCurrentPos++;
+ return nPos;
+}
+
+//------------------------------------------------------------------------------
+IParseContext::InternationalKeyCode OSQLScanner::getInternationalTokenID(const char* sToken) const
+{
+ OSL_ENSURE(m_pContext, "OSQLScanner::getInternationalTokenID: No Context set");
+ return (m_bInternational) ? m_pContext->getIntlKeyCode(OString(sToken) ) : IParseContext::InternationalKeyCode::None;
+}
+sal_Int32 OSQLScanner::GetGERRule() { return PREDICATE_GER; }
+sal_Int32 OSQLScanner::GetENGRule() { return PREDICATE_ENG; }
+sal_Int32 OSQLScanner::GetSQLRule() { return SQL; }
+sal_Int32 OSQLScanner::GetDATERule() { return DATE; }
+sal_Int32 OSQLScanner::GetSTRINGRule() { return STRING; }
+void OSQLScanner::setScanner(bool _bNull)
+{
+ xxx_pGLOBAL_SQLSCAN = _bNull ? nullptr : this;
+}
+sal_Int32 OSQLScanner::SQLlex()
+{
+ return SQLyylex();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/connectivity/source/parse/sqliterator.cxx b/connectivity/source/parse/sqliterator.cxx
new file mode 100644
index 0000000000..a89d631e25
--- /dev/null
+++ b/connectivity/source/parse/sqliterator.cxx
@@ -0,0 +1,2122 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <connectivity/sqliterator.hxx>
+#include <connectivity/sdbcx/VTable.hxx>
+#include <connectivity/sqlparse.hxx>
+#include <sqlbison.hxx>
+#include <connectivity/dbtools.hxx>
+#include <connectivity/sqlerror.hxx>
+#include <com/sun/star/sdbc/ColumnValue.hpp>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdb/XQueriesSupplier.hpp>
+#include <com/sun/star/sdb/ErrorCondition.hpp>
+#ifdef SQL_TEST_PARSETREEITERATOR
+#include <iostream>
+#endif
+#include <connectivity/PColumn.hxx>
+#include <comphelper/diagnose_ex.hxx>
+#include <TConnection.hxx>
+#include <comphelper/types.hxx>
+#include <connectivity/dbmetadata.hxx>
+#include <com/sun/star/sdb/SQLFilterOperator.hpp>
+#include <o3tl/safeint.hxx>
+#include <sal/log.hxx>
+
+#include <iterator>
+#include <memory>
+#include <utility>
+
+using namespace ::comphelper;
+using namespace ::connectivity;
+using namespace ::connectivity::sdbcx;
+using namespace ::dbtools;
+using namespace ::connectivity::parse;
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdb;
+
+namespace connectivity
+{
+ struct OSQLParseTreeIteratorImpl
+ {
+ std::vector< TNodePair > m_aJoinConditions;
+ Reference< XConnection > m_xConnection;
+ Reference< XDatabaseMetaData > m_xDatabaseMetaData;
+ Reference< XNameAccess > m_xTableContainer;
+ Reference< XNameAccess > m_xQueryContainer;
+
+ std::shared_ptr< OSQLTables > m_pTables; // all tables which participate in the SQL statement
+ std::shared_ptr< OSQLTables > m_pSubTables; // all tables from sub queries not the tables from the select tables
+ std::shared_ptr< QueryNameSet > m_pForbiddenQueryNames;
+
+ TraversalParts m_nIncludeMask;
+
+ bool m_bIsCaseSensitive;
+
+ OSQLParseTreeIteratorImpl( const Reference< XConnection >& _rxConnection, const Reference< XNameAccess >& _rxTables )
+ :m_xConnection( _rxConnection )
+ ,m_nIncludeMask( TraversalParts::All )
+ ,m_bIsCaseSensitive( true )
+ {
+ OSL_PRECOND( m_xConnection.is(), "OSQLParseTreeIteratorImpl::OSQLParseTreeIteratorImpl: invalid connection!" );
+ m_xDatabaseMetaData = m_xConnection->getMetaData();
+
+ m_bIsCaseSensitive = m_xDatabaseMetaData.is() && m_xDatabaseMetaData->supportsMixedCaseQuotedIdentifiers();
+ m_pTables = std::make_shared<OSQLTables>( m_bIsCaseSensitive );
+ m_pSubTables = std::make_shared<OSQLTables>( m_bIsCaseSensitive );
+
+ m_xTableContainer = _rxTables;
+
+ DatabaseMetaData aMetaData( m_xConnection );
+ if ( aMetaData.supportsSubqueriesInFrom() )
+ {
+ // connections might support the XQueriesSupplier interface, if they implement the css.sdb.Connection
+ // service
+ Reference< XQueriesSupplier > xSuppQueries( m_xConnection, UNO_QUERY );
+ if ( xSuppQueries.is() )
+ m_xQueryContainer = xSuppQueries->getQueries();
+ }
+ }
+
+ public:
+ bool isQueryAllowed( const OUString& _rQueryName )
+ {
+ if ( !m_pForbiddenQueryNames )
+ return true;
+ if ( m_pForbiddenQueryNames->find( _rQueryName ) == m_pForbiddenQueryNames->end() )
+ return true;
+ return false;
+ }
+ };
+
+ namespace {
+
+ /** helper class for temporarily adding a query name to a list of forbidden query names
+ */
+ class ForbidQueryName
+ {
+ std::shared_ptr< QueryNameSet >& m_rpAllForbiddenNames;
+ OUString m_sForbiddenQueryName;
+
+ public:
+ ForbidQueryName( OSQLParseTreeIteratorImpl& _rIteratorImpl, OUString _aForbiddenQueryName )
+ :m_rpAllForbiddenNames( _rIteratorImpl.m_pForbiddenQueryNames )
+ ,m_sForbiddenQueryName(std::move( _aForbiddenQueryName ))
+ {
+ if ( !m_rpAllForbiddenNames )
+ m_rpAllForbiddenNames = std::make_shared<QueryNameSet>();
+ m_rpAllForbiddenNames->insert( m_sForbiddenQueryName );
+ }
+
+ ~ForbidQueryName()
+ {
+ m_rpAllForbiddenNames->erase( m_sForbiddenQueryName );
+ }
+ };
+
+ }
+}
+
+OSQLParseTreeIterator::OSQLParseTreeIterator(const Reference< XConnection >& _rxConnection,
+ const Reference< XNameAccess >& _rxTables,
+ const OSQLParser& _rParser )
+ :m_rParser( _rParser )
+ ,m_pImpl( new OSQLParseTreeIteratorImpl( _rxConnection, _rxTables ) )
+{
+ setParseTree(nullptr);
+}
+
+
+OSQLParseTreeIterator::OSQLParseTreeIterator( const OSQLParseTreeIterator& _rParentIterator, const OSQLParser& _rParser, const OSQLParseNode* pRoot )
+ :m_rParser( _rParser )
+ ,m_pImpl( new OSQLParseTreeIteratorImpl( _rParentIterator.m_pImpl->m_xConnection, _rParentIterator.m_pImpl->m_xTableContainer ) )
+{
+ m_pImpl->m_pForbiddenQueryNames = _rParentIterator.m_pImpl->m_pForbiddenQueryNames;
+ setParseTree( pRoot );
+}
+
+
+OSQLParseTreeIterator::~OSQLParseTreeIterator()
+{
+ dispose();
+}
+
+
+const OSQLTables& OSQLParseTreeIterator::getTables() const
+{
+ return *m_pImpl->m_pTables;
+}
+
+
+bool OSQLParseTreeIterator::isCaseSensitive() const
+{
+ return m_pImpl->m_bIsCaseSensitive;
+}
+
+
+void OSQLParseTreeIterator::dispose()
+{
+ m_aSelectColumns = nullptr;
+ m_aGroupColumns = nullptr;
+ m_aOrderColumns = nullptr;
+ m_aParameters = nullptr;
+ m_pImpl->m_xTableContainer = nullptr;
+ m_pImpl->m_xDatabaseMetaData = nullptr;
+ m_aCreateColumns = nullptr;
+ m_pImpl->m_pTables->clear();
+ m_pImpl->m_pSubTables->clear();
+}
+
+void OSQLParseTreeIterator::setParseTree(const OSQLParseNode * pNewParseTree)
+{
+ m_pImpl->m_pTables->clear();
+ m_pImpl->m_pSubTables->clear();
+
+ m_aSelectColumns = new OSQLColumns();
+ m_aGroupColumns = new OSQLColumns();
+ m_aOrderColumns = new OSQLColumns();
+ m_aParameters = new OSQLColumns();
+ m_aCreateColumns = new OSQLColumns();
+
+ m_pParseTree = pNewParseTree;
+ if (!m_pParseTree)
+ {
+ m_eStatementType = OSQLStatementType::Unknown;
+ return;
+ }
+
+ // If m_pParseTree, but no connection then return
+ if ( !m_pImpl->m_xTableContainer.is() )
+ return;
+
+ m_xErrors.reset();
+
+
+ // Determine statement type ...
+ if (SQL_ISRULE(m_pParseTree,select_statement) || SQL_ISRULE(m_pParseTree,union_statement) )
+ {
+ m_eStatementType = OSQLStatementType::Select;
+ }
+ else if (SQL_ISRULE(m_pParseTree,insert_statement))
+ {
+ m_eStatementType = OSQLStatementType::Insert;
+ }
+ else if (SQL_ISRULE(m_pParseTree,update_statement_searched))
+ {
+ m_eStatementType = OSQLStatementType::Update;
+ }
+ else if (SQL_ISRULE(m_pParseTree,delete_statement_searched))
+ {
+ m_eStatementType = OSQLStatementType::Delete;
+ }
+ else if (m_pParseTree->count() == 3 && SQL_ISRULE(m_pParseTree->getChild(1),odbc_call_spec))
+ {
+ m_eStatementType = OSQLStatementType::OdbcCall;
+ }
+ else if (SQL_ISRULE(m_pParseTree->getChild(0),base_table_def))
+ {
+ m_eStatementType = OSQLStatementType::CreateTable;
+ m_pParseTree = m_pParseTree->getChild(0);
+ }
+ else
+ {
+ m_eStatementType = OSQLStatementType::Unknown;
+ //aIteratorStatus.setInvalidStatement();
+ return;
+ }
+}
+
+
+namespace
+{
+
+ void impl_getRowString( const Reference< XRow >& _rxRow, const sal_Int32 _nColumnIndex, OUString& _out_rString )
+ {
+ _out_rString = _rxRow->getString( _nColumnIndex );
+ if ( _rxRow->wasNull() )
+ _out_rString.clear();
+ }
+
+
+ OUString lcl_findTableInMetaData(
+ const Reference< XDatabaseMetaData >& _rxDBMeta, const OUString& _rCatalog,
+ const OUString& _rSchema, const OUString& _rTableName )
+ {
+ OUString sComposedName;
+
+ static constexpr OUString s_sWildcard = u"%"_ustr ;
+
+ // we want all catalogues, all schemas, all tables
+ Sequence< OUString > sTableTypes { "VIEW", "TABLE", s_sWildcard }; // this last one just to be sure to include anything else...
+
+ if ( _rxDBMeta.is() )
+ {
+ sComposedName.clear();
+
+ Reference< XResultSet> xRes = _rxDBMeta->getTables(
+ !_rCatalog.isEmpty() ? Any( _rCatalog ) : Any(), !_rSchema.isEmpty() ? _rSchema : s_sWildcard, _rTableName, sTableTypes );
+
+ Reference< XRow > xCurrentRow( xRes, UNO_QUERY );
+ if ( xCurrentRow.is() && xRes->next() )
+ {
+ OUString sCatalog, sSchema, sName;
+
+ impl_getRowString( xCurrentRow, 1, sCatalog );
+ impl_getRowString( xCurrentRow, 2, sSchema );
+ impl_getRowString( xCurrentRow, 3, sName );
+
+ sComposedName = ::dbtools::composeTableName(
+ _rxDBMeta,
+ sCatalog,
+ sSchema,
+ sName,
+ false,
+ ::dbtools::EComposeRule::InDataManipulation
+ );
+ }
+ }
+ return sComposedName;
+ }
+}
+
+
+void OSQLParseTreeIterator::impl_getQueryParameterColumns( const OSQLTable& _rQuery )
+{
+ if ( !( m_pImpl->m_nIncludeMask & TraversalParts::Parameters ) )
+ // parameters not to be included in the traversal
+ return;
+
+ ::rtl::Reference pSubQueryParameterColumns( new OSQLColumns() );
+
+ // get the command and the EscapeProcessing properties from the sub query
+ OUString sSubQueryCommand;
+ bool bEscapeProcessing = false;
+ try
+ {
+ Reference< XPropertySet > xQueryProperties( _rQuery, UNO_QUERY_THROW );
+ OSL_VERIFY( xQueryProperties->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex( PROPERTY_ID_COMMAND ) ) >>= sSubQueryCommand );
+ OSL_VERIFY( xQueryProperties->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex( PROPERTY_ID_ESCAPEPROCESSING ) ) >>= bEscapeProcessing );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("connectivity.parse");
+ }
+
+ // parse the sub query
+ do {
+
+ if ( !bEscapeProcessing || ( sSubQueryCommand.isEmpty() ) )
+ break;
+
+ OUString sError;
+ std::unique_ptr< OSQLParseNode > pSubQueryNode( const_cast< OSQLParser& >( m_rParser ).parseTree( sError, sSubQueryCommand ) );
+ if (!pSubQueryNode)
+ break;
+
+ OSQLParseTreeIterator aSubQueryIterator( *this, m_rParser, pSubQueryNode.get() );
+ aSubQueryIterator.impl_traverse( TraversalParts::Parameters | TraversalParts::SelectColumns );
+ // SelectColumns might also contain parameters #i77635#
+ pSubQueryParameterColumns = aSubQueryIterator.getParameters();
+ aSubQueryIterator.dispose();
+
+ } while ( false );
+
+ // copy the parameters of the sub query to our own parameter array
+ m_aParameters->insert( m_aParameters->end(), pSubQueryParameterColumns->begin(), pSubQueryParameterColumns->end() );
+}
+
+
+OSQLTable OSQLParseTreeIterator::impl_locateRecordSource( const OUString& _rComposedName )
+{
+ if ( _rComposedName.isEmpty() )
+ {
+ SAL_WARN( "connectivity.parse", "OSQLParseTreeIterator::impl_locateRecordSource: no object name at all?" );
+ return OSQLTable();
+ }
+
+ OSQLTable aReturn;
+ OUString sComposedName( _rComposedName );
+
+ try
+ {
+ OUString sCatalog, sSchema, sName;
+ qualifiedNameComponents( m_pImpl->m_xDatabaseMetaData, sComposedName, sCatalog, sSchema, sName, ::dbtools::EComposeRule::InDataManipulation );
+
+ // check whether there is a query with the given name
+ bool bQueryDoesExist = m_pImpl->m_xQueryContainer.is() && m_pImpl->m_xQueryContainer->hasByName( sComposedName );
+
+ // check whether the table container contains an object with the given name
+ if ( !bQueryDoesExist && !m_pImpl->m_xTableContainer->hasByName( sComposedName ) )
+ sComposedName = lcl_findTableInMetaData( m_pImpl->m_xDatabaseMetaData, sCatalog, sSchema, sName );
+ bool bTableDoesExist = m_pImpl->m_xTableContainer->hasByName( sComposedName );
+
+ // now obtain the object
+
+ // if we're creating a table, and there already is a table or query with the same name,
+ // this is worth an error
+ if ( OSQLStatementType::CreateTable == m_eStatementType )
+ {
+ if ( bQueryDoesExist )
+ impl_appendError( IParseContext::ErrorCode::InvalidQueryExist, &sName );
+ else if ( bTableDoesExist )
+ impl_appendError( IParseContext::ErrorCode::InvalidTableExist, &sName );
+ else
+ aReturn = impl_createTableObject( sName, sCatalog, sSchema );
+ }
+ else
+ {
+ // queries win over tables, so if there's a query with this name, take this, no matter if
+ // there's a table, too
+ if ( bQueryDoesExist )
+ {
+ if ( !m_pImpl->isQueryAllowed( sComposedName ) )
+ {
+ impl_appendError( m_rParser.getErrorHelper().getSQLException( sdb::ErrorCondition::PARSER_CYCLIC_SUB_QUERIES, nullptr ) );
+ return nullptr;
+ }
+
+ m_pImpl->m_xQueryContainer->getByName( sComposedName ) >>= aReturn;
+
+ // collect the parameters from the sub query
+ ForbidQueryName aForbidName( *m_pImpl, sComposedName );
+ impl_getQueryParameterColumns( aReturn );
+ }
+ else if ( bTableDoesExist )
+ m_pImpl->m_xTableContainer->getByName( sComposedName ) >>= aReturn;
+ else
+ {
+ if ( m_pImpl->m_xQueryContainer.is() )
+ // the connection on which we're working supports sub queries in from (else
+ // m_xQueryContainer would not have been set), so emit a better error message
+ impl_appendError( IParseContext::ErrorCode::InvalidTableOrQuery, &sName );
+ else
+ impl_appendError( IParseContext::ErrorCode::InvalidTableNosuch, &sName );
+ }
+ }
+ }
+ catch(Exception&)
+ {
+ impl_appendError( IParseContext::ErrorCode::InvalidTableNosuch, &sComposedName );
+ }
+
+ return aReturn;
+}
+
+
+void OSQLParseTreeIterator::traverseOneTableName( OSQLTables& _rTables,const OSQLParseNode * pTableName, const OUString & rTableRange )
+{
+ if ( !( m_pImpl->m_nIncludeMask & TraversalParts::TableNames ) )
+ // tables should not be included in the traversal
+ return;
+
+ OSL_ENSURE(pTableName != nullptr,"OSQLParseTreeIterator::traverseOneTableName: pTableName == NULL");
+
+ Any aCatalog;
+ OUString aSchema,aTableName,aComposedName;
+ OUString aTableRange(rTableRange);
+
+ // Get table name
+ OSQLParseNode::getTableComponents(pTableName,aCatalog,aSchema,aTableName,m_pImpl->m_xDatabaseMetaData);
+
+ // create the composed name like DOMAIN.USER.TABLE1
+ aComposedName = ::dbtools::composeTableName(m_pImpl->m_xDatabaseMetaData,
+ aCatalog.hasValue() ? ::comphelper::getString(aCatalog) : OUString(),
+ aSchema,
+ aTableName,
+ false,
+ ::dbtools::EComposeRule::InDataManipulation);
+
+ // if there is no alias for the table name assign the original name to it
+ if ( aTableRange.isEmpty() )
+ aTableRange = aComposedName;
+
+ // get the object representing this table/query
+ OSQLTable aTable = impl_locateRecordSource( aComposedName );
+ if ( aTable.is() )
+ _rTables[ aTableRange ] = aTable;
+}
+
+void OSQLParseTreeIterator::impl_fillJoinConditions(const OSQLParseNode* i_pJoinCondition)
+{
+ if (i_pJoinCondition->count() == 3 && // Expression with brackets
+ SQL_ISPUNCTUATION(i_pJoinCondition->getChild(0),"(") &&
+ SQL_ISPUNCTUATION(i_pJoinCondition->getChild(2),")"))
+ {
+ impl_fillJoinConditions(i_pJoinCondition->getChild(1));
+ }
+ else if (SQL_ISRULEOR2(i_pJoinCondition,search_condition,boolean_term) && // AND/OR logic operation:
+ i_pJoinCondition->count() == 3)
+ {
+ // Only allow AND logic operation
+ if ( SQL_ISTOKEN(i_pJoinCondition->getChild(1),AND) )
+ {
+ impl_fillJoinConditions(i_pJoinCondition->getChild(0));
+ impl_fillJoinConditions(i_pJoinCondition->getChild(1));
+ }
+ }
+ else if (SQL_ISRULE(i_pJoinCondition,comparison_predicate))
+ {
+ // only the comparison of columns is allowed
+ OSL_ENSURE(i_pJoinCondition->count() == 3,"OQueryDesignView::InsertJoinConnection: error in the parse tree");
+ if (SQL_ISRULE(i_pJoinCondition->getChild(0),column_ref) &&
+ SQL_ISRULE(i_pJoinCondition->getChild(2),column_ref) &&
+ i_pJoinCondition->getChild(1)->getNodeType() == SQLNodeType::Equal)
+ {
+ m_pImpl->m_aJoinConditions.push_back( TNodePair(i_pJoinCondition->getChild(0),i_pJoinCondition->getChild(2)) );
+ }
+ }
+}
+
+std::vector< TNodePair >& OSQLParseTreeIterator::getJoinConditions() const
+{
+ return m_pImpl->m_aJoinConditions;
+}
+
+void OSQLParseTreeIterator::getQualified_join( OSQLTables& _rTables, const OSQLParseNode *pTableRef, OUString& aTableRange )
+{
+ OSL_PRECOND( SQL_ISRULE( pTableRef, cross_union ) || SQL_ISRULE( pTableRef, qualified_join ) ,
+ "OSQLParseTreeIterator::getQualified_join: illegal node!" );
+
+ aTableRange.clear();
+
+ const OSQLParseNode* pNode = getTableNode(_rTables,pTableRef->getChild(0),aTableRange);
+ if ( isTableNode( pNode ) )
+ traverseOneTableName( _rTables, pNode, aTableRange );
+
+ sal_uInt32 nPos = 4;
+ if( SQL_ISRULE(pTableRef,cross_union) || pTableRef->getChild(1)->getTokenID() != SQL_TOKEN_NATURAL)
+ {
+ nPos = 3;
+ // join_condition,named_columns_join
+ if ( SQL_ISRULE( pTableRef, qualified_join ) )
+ {
+ const OSQLParseNode* pJoin_spec = pTableRef->getChild(4);
+ if ( SQL_ISRULE( pJoin_spec, join_condition ) )
+ {
+ impl_fillJoinConditions(pJoin_spec->getChild(1));
+ }
+ else
+ {
+ const OSQLParseNode* pColumnCommalist = pJoin_spec->getChild(2);
+ // All columns in the column_commalist ...
+ for (size_t i = 0; i < pColumnCommalist->count(); i++)
+ {
+ const OSQLParseNode * pCol = pColumnCommalist->getChild(i);
+ // add twice because the column must exists in both tables
+ m_pImpl->m_aJoinConditions.push_back( TNodePair(pCol,pCol) );
+ }
+ }
+ }
+ }
+
+ pNode = getTableNode(_rTables,pTableRef->getChild(nPos),aTableRange);
+ if ( isTableNode( pNode ) )
+ traverseOneTableName( _rTables, pNode, aTableRange );
+}
+
+const OSQLParseNode* OSQLParseTreeIterator::getTableNode( OSQLTables& _rTables, const OSQLParseNode *pTableRef,OUString& rTableRange )
+{
+ OSL_PRECOND( SQL_ISRULE( pTableRef, table_ref ) || SQL_ISRULE( pTableRef, joined_table )
+ || SQL_ISRULE( pTableRef, qualified_join ) || SQL_ISRULE( pTableRef, cross_union ),
+ "OSQLParseTreeIterator::getTableNode: only to be called for table_ref nodes!" );
+
+ const OSQLParseNode* pTableNameNode = nullptr;
+
+ if ( SQL_ISRULE( pTableRef, joined_table ) )
+ {
+ getQualified_join( _rTables, pTableRef->getChild(1), rTableRange );
+ }
+ if ( SQL_ISRULE( pTableRef, qualified_join ) || SQL_ISRULE( pTableRef, cross_union ) )
+ {
+ getQualified_join( _rTables, pTableRef, rTableRange );
+ }
+ else
+ {
+ rTableRange = OSQLParseNode::getTableRange(pTableRef);
+ if ( ( pTableRef->count() == 4 ) // '{' SQL_TOKEN_OJ joined_table '}'
+ || ( pTableRef->count() == 5 ) // '(' joined_table ')' range_variable op_column_commalist
+ )
+ {
+ getQualified_join( _rTables, pTableRef->getChild(6 - pTableRef->count()), rTableRange );
+ }
+ else if ( pTableRef->count() == 3 ) // subquery range_variable op_column_commalist || '(' joined_table ')'
+ {
+ const OSQLParseNode* pSubQuery = pTableRef->getChild(0);
+ if ( pSubQuery->isToken() )
+ {
+ getQualified_join( _rTables, pTableRef->getChild(1), rTableRange );
+ }
+ else
+ {
+ OSL_ENSURE( pSubQuery->count() == 3, "sub queries should have 3 children!" );
+ const OSQLParseNode* pQueryExpression = pSubQuery->getChild(1);
+ if ( SQL_ISRULE( pQueryExpression, select_statement ) )
+ {
+ getSelect_statement( *m_pImpl->m_pSubTables, pQueryExpression );
+ // TODO: now, we need to setup an OSQLTable from pQueryExpression in some way
+ // and stick it in _rTables[rTableRange]. Probably fake it by
+ // setting up a full OSQLParseTreeIterator on pQueryExpression
+ // and using its m_aSelectColumns
+ // This is necessary in stuff like "SELECT * FROM tbl1 INNER JOIN (SELECT foo, bar FROM tbl2) AS tbl3"
+ // so that setSelectColumnName() can expand the "*" correctly.
+ // See e.g. R_UserAndLastSubscription query of https://bugs.libreoffice.org/attachment.cgi?id=71871
+ }
+ else
+ {
+ SAL_WARN( "connectivity.parse", "OSQLParseTreeIterator::getTableNode: subquery which is no select_statement: not yet implemented!" );
+ }
+ }
+ }
+ else if ( pTableRef->count() == 2 ) // table_node table_primary_as_range_column
+ {
+ pTableNameNode = pTableRef->getChild(0);
+ }
+ else
+ SAL_WARN( "connectivity.parse", "OSQLParseTreeIterator::getTableNode: unhandled case!" );
+ }
+
+ return pTableNameNode;
+}
+
+void OSQLParseTreeIterator::getSelect_statement(OSQLTables& _rTables,const OSQLParseNode* pSelect)
+{
+ if(SQL_ISRULE(pSelect,union_statement))
+ {
+ getSelect_statement(_rTables,pSelect->getChild(0));
+ //getSelect_statement(pSelect->getChild(3));
+ return;
+ }
+ OSQLParseNode * pTableRefCommalist = pSelect->getChild(3)->getChild(0)->getChild(1);
+
+ OSL_ENSURE(pTableRefCommalist != nullptr,"OSQLParseTreeIterator: error in parse tree!");
+ OSL_ENSURE(SQL_ISRULE(pTableRefCommalist,table_ref_commalist),"OSQLParseTreeIterator: error in parse tree!");
+
+ const OSQLParseNode* pTableName = nullptr;
+ OUString aTableRange;
+ for (size_t i = 0; i < pTableRefCommalist->count(); i++)
+ { // Process FROM clause
+ aTableRange.clear();
+
+ const OSQLParseNode* pTableListElement = pTableRefCommalist->getChild(i);
+ if ( isTableNode( pTableListElement ) )
+ {
+ traverseOneTableName( _rTables, pTableListElement, aTableRange );
+ }
+ else if ( SQL_ISRULE( pTableListElement, table_ref ) )
+ {
+ // Table references can be made up of table names, table names (+),'('joined_table')'(+)
+ pTableName = pTableListElement->getChild(0);
+ if( isTableNode( pTableName ) )
+ { // Found table names
+ aTableRange = OSQLParseNode::getTableRange(pTableListElement);
+ traverseOneTableName( _rTables, pTableName, aTableRange );
+ }
+ else if(SQL_ISPUNCTUATION(pTableName,"{"))
+ { // '{' SQL_TOKEN_OJ joined_table '}'
+ getQualified_join( _rTables, pTableListElement->getChild(2), aTableRange );
+ }
+ else
+ { // '(' joined_table ')' range_variable op_column_commalist
+ getTableNode( _rTables, pTableListElement, aTableRange );
+ }
+ }
+ else if (SQL_ISRULE( pTableListElement, qualified_join ) || SQL_ISRULE( pTableListElement, cross_union ) )
+ {
+ getQualified_join( _rTables, pTableListElement, aTableRange );
+ }
+ else if ( SQL_ISRULE( pTableListElement, joined_table ) )
+ {
+ getQualified_join( _rTables, pTableListElement->getChild(1), aTableRange );
+ }
+
+ // if (! aIteratorStatus.IsSuccessful()) break;
+ }
+}
+
+bool OSQLParseTreeIterator::traverseTableNames(OSQLTables& _rTables)
+{
+ if ( m_pParseTree == nullptr )
+ return false;
+
+ OSQLParseNode* pTableName = nullptr;
+
+ switch ( m_eStatementType )
+ {
+ case OSQLStatementType::Select:
+ getSelect_statement( _rTables, m_pParseTree );
+ break;
+
+ case OSQLStatementType::CreateTable:
+ case OSQLStatementType::Insert:
+ case OSQLStatementType::Delete:
+ pTableName = m_pParseTree->getChild(2);
+ break;
+
+ case OSQLStatementType::Update:
+ pTableName = m_pParseTree->getChild(1);
+ break;
+ default:
+ break;
+ }
+
+ if ( pTableName )
+ {
+ traverseOneTableName( _rTables, pTableName, OUString() );
+ }
+
+ return !hasErrors();
+}
+
+OUString OSQLParseTreeIterator::getColumnAlias(const OSQLParseNode* _pDerivedColumn)
+{
+ OSL_ENSURE(SQL_ISRULE(_pDerivedColumn,derived_column),"No derived column!");
+ OUString sColumnAlias;
+ if(_pDerivedColumn->getChild(1)->count() == 2)
+ sColumnAlias = _pDerivedColumn->getChild(1)->getChild(1)->getTokenValue();
+ else if(!_pDerivedColumn->getChild(1)->isRule())
+ sColumnAlias = _pDerivedColumn->getChild(1)->getTokenValue();
+ return sColumnAlias;
+}
+
+
+namespace
+{
+ void lcl_getColumnRange( const OSQLParseNode* _pColumnRef, const Reference< XConnection >& _rxConnection,
+ OUString& _out_rColumnName, OUString& _out_rTableRange,
+ const OSQLColumns* _pSelectColumns, OUString& _out_rColumnAliasIfPresent )
+ {
+ _out_rColumnName.clear();
+ _out_rTableRange.clear();
+ _out_rColumnAliasIfPresent.clear();
+ if ( SQL_ISRULE( _pColumnRef, column_ref ) )
+ {
+ if( _pColumnRef->count() > 1 )
+ {
+ for ( sal_Int32 i=0; i<static_cast<sal_Int32>(_pColumnRef->count())-2; ++i )
+ _pColumnRef->getChild(i)->parseNodeToStr( _out_rTableRange, _rxConnection, nullptr, false, false );
+ _out_rColumnName = _pColumnRef->getChild( _pColumnRef->count()-1 )->getChild(0)->getTokenValue();
+ }
+ else
+ _out_rColumnName = _pColumnRef->getChild(0)->getTokenValue();
+
+ // look up the column in the select column, to find a possible alias
+ if ( _pSelectColumns )
+ {
+ for (const Reference< XPropertySet >& xColumn : *_pSelectColumns)
+ {
+ try
+ {
+ OUString sName, sTableName;
+ xColumn->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex( PROPERTY_ID_REALNAME ) ) >>= sName;
+ xColumn->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex( PROPERTY_ID_TABLENAME ) ) >>= sTableName;
+ if ( sName == _out_rColumnName && ( _out_rTableRange.isEmpty() || sTableName == _out_rTableRange ) )
+ {
+ xColumn->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex( PROPERTY_ID_NAME ) ) >>= _out_rColumnAliasIfPresent;
+ break;
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("connectivity.parse");
+ }
+ }
+ }
+ }
+ else if(SQL_ISRULE(_pColumnRef,general_set_fct) || SQL_ISRULE(_pColumnRef,set_fct_spec))
+ { // Function
+ _pColumnRef->parseNodeToStr( _out_rColumnName, _rxConnection );
+ }
+ else if(_pColumnRef->getNodeType() == SQLNodeType::Name)
+ _out_rColumnName = _pColumnRef->getTokenValue();
+ }
+}
+
+
+void OSQLParseTreeIterator::getColumnRange( const OSQLParseNode* _pColumnRef,
+ OUString& _rColumnName,
+ OUString& _rTableRange) const
+{
+ OUString sDummy;
+ lcl_getColumnRange( _pColumnRef, m_pImpl->m_xConnection, _rColumnName, _rTableRange, nullptr, sDummy );
+}
+
+
+void OSQLParseTreeIterator::getColumnRange( const OSQLParseNode* _pColumnRef,
+ OUString& _rColumnName,
+ OUString& _rTableRange,
+ OUString& _out_rColumnAliasIfPresent ) const
+{
+ lcl_getColumnRange( _pColumnRef, m_pImpl->m_xConnection, _rColumnName, _rTableRange, &*m_aSelectColumns, _out_rColumnAliasIfPresent );
+}
+
+
+void OSQLParseTreeIterator::getColumnRange( const OSQLParseNode* _pColumnRef,
+ const Reference< XConnection >& _rxConnection, OUString& _out_rColumnName, OUString& _out_rTableRange )
+{
+ OUString sDummy;
+ lcl_getColumnRange( _pColumnRef, _rxConnection, _out_rColumnName, _out_rTableRange, nullptr, sDummy );
+}
+
+
+void OSQLParseTreeIterator::traverseCreateColumns(const OSQLParseNode* pSelectNode)
+{
+ // aIteratorStatus.Clear();
+
+ if (!pSelectNode || m_eStatementType != OSQLStatementType::CreateTable || m_pImpl->m_pTables->empty())
+ {
+ impl_appendError( IParseContext::ErrorCode::General );
+ return;
+ }
+ if (!SQL_ISRULE(pSelectNode,base_table_element_commalist))
+ return ;
+
+ for (size_t i = 0; i < pSelectNode->count(); i++)
+ {
+ OSQLParseNode *pColumnRef = pSelectNode->getChild(i);
+
+ if (SQL_ISRULE(pColumnRef,column_def))
+ {
+ OUString aColumnName;
+ OUString aTypeName;
+ sal_Int32 nType = DataType::VARCHAR;
+ aColumnName = pColumnRef->getChild(0)->getTokenValue();
+
+ OSQLParseNode *pDatatype = pColumnRef->getChild(1);
+ if (pDatatype && SQL_ISRULE(pDatatype,character_string_type))
+ {
+ const OSQLParseNode *pType = pDatatype->getChild(0);
+ aTypeName = pType->getTokenValue();
+ if (pDatatype->count() == 2 && (pType->getTokenID() == SQL_TOKEN_CHAR || pType->getTokenID() == SQL_TOKEN_CHARACTER ))
+ nType = DataType::CHAR;
+ }
+ else if(pDatatype && pDatatype->getNodeType() == SQLNodeType::Keyword)
+ {
+ aTypeName = "VARCHAR";
+ }
+
+ if (!aTypeName.isEmpty())
+ {
+ //TODO:Create a new class for create statement to handle field length
+ rtl::Reference<OParseColumn> pColumn = new OParseColumn(aColumnName,aTypeName,OUString(),OUString(),
+ ColumnValue::NULLABLE_UNKNOWN,0,0,nType,false,false,isCaseSensitive(),
+ OUString(),OUString(),OUString());
+ pColumn->setFunction(false);
+ pColumn->setRealName(aColumnName);
+
+ m_aCreateColumns->push_back(pColumn);
+ }
+ }
+
+ }
+}
+
+bool OSQLParseTreeIterator::traverseSelectColumnNames(const OSQLParseNode* pSelectNode)
+{
+ if ( !( m_pImpl->m_nIncludeMask & TraversalParts::SelectColumns ) )
+ return true;
+
+ if (!pSelectNode || m_eStatementType != OSQLStatementType::Select || m_pImpl->m_pTables->empty())
+ {
+ impl_appendError( IParseContext::ErrorCode::General );
+ return false;
+ }
+
+ if(SQL_ISRULE(pSelectNode,union_statement))
+ {
+ return traverseSelectColumnNames( pSelectNode->getChild( 0 ) )
+ /*&& traverseSelectColumnNames( pSelectNode->getChild( 3 ) )*/;
+ }
+
+ // nyi: more checks for correct structure!
+ if (pSelectNode->getChild(2)->isRule() && SQL_ISPUNCTUATION(pSelectNode->getChild(2)->getChild(0),"*"))
+ {
+ // SELECT * ...
+ setSelectColumnName("*", "", "");
+ }
+ else if (SQL_ISRULE(pSelectNode->getChild(2),scalar_exp_commalist))
+ {
+ // SELECT column[,column] or SELECT COUNT(*) ...
+ OSQLParseNode * pSelection = pSelectNode->getChild(2);
+
+ for (size_t i = 0; i < pSelection->count(); i++)
+ {
+ OSQLParseNode *pColumnRef = pSelection->getChild(i);
+
+ //if (SQL_ISRULE(pColumnRef,select_sublist))
+ if (SQL_ISRULE(pColumnRef,derived_column) &&
+ SQL_ISRULE(pColumnRef->getChild(0),column_ref) &&
+ pColumnRef->getChild(0)->count() == 3 &&
+ SQL_ISPUNCTUATION(pColumnRef->getChild(0)->getChild(2),"*"))
+ {
+ // All the table's columns
+ OUString aTableRange;
+ pColumnRef->getChild(0)->parseNodeToStr( aTableRange, m_pImpl->m_xConnection, nullptr, false, false );
+ setSelectColumnName("*", "", aTableRange);
+ continue;
+ }
+ else if (SQL_ISRULE(pColumnRef,derived_column))
+ {
+ OUString aColumnAlias(getColumnAlias(pColumnRef)); // can be empty
+ OUString sColumnName;
+ OUString aTableRange;
+ sal_Int32 nType = DataType::VARCHAR;
+ bool bFkt(false);
+ pColumnRef = pColumnRef->getChild(0);
+ while (
+ pColumnRef->getKnownRuleID() != OSQLParseNode::subquery &&
+ pColumnRef->count() == 3 &&
+ SQL_ISPUNCTUATION(pColumnRef->getChild(0),"(") &&
+ SQL_ISPUNCTUATION(pColumnRef->getChild(2),")")
+ )
+ pColumnRef = pColumnRef->getChild(1);
+
+ if (SQL_ISRULE(pColumnRef,column_ref))
+ {
+ getColumnRange(pColumnRef,sColumnName,aTableRange);
+ OSL_ENSURE(!sColumnName.isEmpty(),"Column name must not be empty!");
+ }
+ else /*if (SQL_ISRULE(pColumnRef,general_set_fct) || SQL_ISRULE(pColumnRef,set_fct_spec) ||
+ SQL_ISRULE(pColumnRef,position_exp) || SQL_ISRULE(pColumnRef,extract_exp) ||
+ SQL_ISRULE(pColumnRef,length_exp) || SQL_ISRULE(pColumnRef,char_value_fct)||
+ SQL_ISRULE(pColumnRef,num_value_exp) || SQL_ISRULE(pColumnRef,term))*/
+ {
+ // Function call present
+ pColumnRef->parseNodeToStr( sColumnName, m_pImpl->m_xConnection );
+ // check if the column is also a parameter
+ traverseSearchCondition(pColumnRef); // num_value_exp
+
+ if ( pColumnRef->isRule() )
+ {
+ // FIXME: the if condition is not quite right
+ // many expressions are rules, e.g. "5+3"
+ // or even: "colName + 1"
+ bFkt = true;
+ nType = getFunctionReturnType(pColumnRef);
+ }
+ }
+ /*
+ else
+ {
+ aIteratorStatus.setStatementTooComplex();
+ return;
+ }
+ */
+ if(aColumnAlias.isEmpty())
+ aColumnAlias = sColumnName;
+ setSelectColumnName(sColumnName,aColumnAlias,aTableRange,bFkt,nType,SQL_ISRULE(pColumnRef,general_set_fct) || SQL_ISRULE(pColumnRef,set_fct_spec));
+ }
+ }
+ }
+
+ return !hasErrors();
+}
+
+
+bool OSQLParseTreeIterator::traverseOrderByColumnNames(const OSQLParseNode* pSelectNode)
+{
+ traverseByColumnNames( pSelectNode, true );
+ return !hasErrors();
+}
+
+void OSQLParseTreeIterator::traverseByColumnNames(const OSQLParseNode* pSelectNode, bool _bOrder)
+{
+ // aIteratorStatus.Clear();
+
+ if (pSelectNode == nullptr)
+ {
+ //aIteratorStatus.setInvalidStatement();
+ return;
+ }
+
+ if (m_eStatementType != OSQLStatementType::Select)
+ {
+ //aIteratorStatus.setInvalidStatement();
+ return;
+ }
+
+ if(SQL_ISRULE(pSelectNode,union_statement))
+ {
+ traverseByColumnNames(pSelectNode->getChild(0),_bOrder);
+ return;
+ }
+
+ OSL_ENSURE(pSelectNode->count() >= 4,"OSQLParseTreeIterator: error in parse tree!");
+
+ OSQLParseNode * pTableExp = pSelectNode->getChild(3);
+ OSL_ENSURE(pTableExp != nullptr,"OSQLParseTreeIterator: error in parse tree!");
+ OSL_ENSURE(SQL_ISRULE(pTableExp,table_exp),"OSQLParseTreeIterator:table_exp error in parse tree!");
+ OSL_ENSURE(pTableExp->count() == TABLE_EXPRESSION_CHILD_COUNT,"OSQLParseTreeIterator: error in parse tree!");
+
+ sal_uInt32 nPos = ( _bOrder ? ORDER_BY_CHILD_POS : 2 );
+
+ OSQLParseNode * pOptByClause = pTableExp->getChild(nPos);
+ OSL_ENSURE(pOptByClause != nullptr,"OSQLParseTreeIterator: error in parse tree!");
+ if ( pOptByClause->count() == 0 )
+ return;
+
+ OSL_ENSURE(pOptByClause->count() == 3,"OSQLParseTreeIterator: error in parse tree!");
+
+ OSQLParseNode * pOrderingSpecCommalist = pOptByClause->getChild(2);
+ OSL_ENSURE(pOrderingSpecCommalist != nullptr,"OSQLParseTreeIterator: error in parse tree!");
+ OSL_ENSURE(!_bOrder || SQL_ISRULE(pOrderingSpecCommalist,ordering_spec_commalist),"OSQLParseTreeIterator:ordering_spec_commalist error in parse tree!");
+ OSL_ENSURE(pOrderingSpecCommalist->count() > 0,"OSQLParseTreeIterator: error in parse tree!");
+
+ OUString sColumnName;
+ OUString aTableRange;
+ sal_uInt32 nCount = pOrderingSpecCommalist->count();
+ for (sal_uInt32 i = 0; i < nCount; ++i)
+ {
+ OSQLParseNode* pColumnRef = pOrderingSpecCommalist->getChild(i);
+ OSL_ENSURE(pColumnRef != nullptr,"OSQLParseTreeIterator: error in parse tree!");
+ if ( _bOrder )
+ {
+ OSL_ENSURE(SQL_ISRULE(pColumnRef,ordering_spec),"OSQLParseTreeIterator:ordering_spec error in parse tree!");
+ OSL_ENSURE(pColumnRef->count() == 2,"OSQLParseTreeIterator: error in parse tree!");
+
+ pColumnRef = pColumnRef->getChild(0);
+ }
+ OSL_ENSURE(pColumnRef != nullptr,"OSQLParseTreeIterator: error in parse tree!");
+ aTableRange.clear();
+ sColumnName.clear();
+ if ( SQL_ISRULE(pColumnRef,column_ref) )
+ {
+ // Column name (and TableRange):
+ getColumnRange(pColumnRef,sColumnName,aTableRange);
+ }
+ else
+ { // here I found a predicate
+ pColumnRef->parseNodeToStr( sColumnName, m_pImpl->m_xConnection, nullptr, false, false );
+ }
+ OSL_ENSURE(!sColumnName.isEmpty(),"sColumnName must not be empty!");
+ if ( _bOrder )
+ {
+ // Ascending/Descending
+ OSQLParseNode * pOptAscDesc = pColumnRef->getParent()->getChild(1);
+ OSL_ENSURE(pOptAscDesc != nullptr,"OSQLParseTreeIterator: error in parse tree!");
+
+ bool bAscending = ! (pOptAscDesc && SQL_ISTOKEN(pOptAscDesc,DESC));
+ setOrderByColumnName(sColumnName, aTableRange,bAscending);
+ }
+ else
+ setGroupByColumnName(sColumnName, aTableRange);
+ }
+}
+
+bool OSQLParseTreeIterator::traverseGroupByColumnNames(const OSQLParseNode* pSelectNode)
+{
+ traverseByColumnNames( pSelectNode, false );
+ return !hasErrors();
+}
+
+
+namespace
+{
+ OUString lcl_generateParameterName( const OSQLParseNode& _rParentNode, const OSQLParseNode& _rParamNode )
+ {
+ OUString sColumnName( "param" );
+ const sal_Int32 nCount = static_cast<sal_Int32>(_rParentNode.count());
+ for ( sal_Int32 i = 0; i < nCount; ++i )
+ {
+ if ( _rParentNode.getChild(i) == &_rParamNode )
+ {
+ sColumnName += OUString::number( i+1 );
+ break;
+ }
+ }
+ return sColumnName;
+ }
+}
+
+
+void OSQLParseTreeIterator::traverseParameters(const OSQLParseNode* _pNode)
+{
+ if ( _pNode == nullptr )
+ return;
+
+ OUString sColumnName, sTableRange, aColumnAlias;
+ const OSQLParseNode* pParent = _pNode->getParent();
+ if ( pParent != nullptr )
+ {
+ if ( SQL_ISRULE(pParent,comparison_predicate) ) // x = X
+ {
+ sal_uInt32 nPos = 0;
+ if ( pParent->getChild(nPos) == _pNode )
+ nPos = 2;
+ const OSQLParseNode* pOther = pParent->getChild(nPos);
+ if ( SQL_ISRULE( pOther, column_ref ) )
+ getColumnRange( pOther, sColumnName, sTableRange, aColumnAlias);
+ else
+ pOther->parseNodeToStr( sColumnName, m_pImpl->m_xConnection, nullptr, false, false );
+ } // if ( SQL_ISRULE(pParent,comparison_predicate) ) // x = X
+ else if ( SQL_ISRULE(pParent,other_like_predicate_part_2) )
+ {
+ const OSQLParseNode* pOther = pParent->getParent()->getChild(0);
+ if ( SQL_ISRULE( pOther, column_ref ) )
+ getColumnRange( pOther, sColumnName, sTableRange, aColumnAlias);
+ else
+ pOther->parseNodeToStr( sColumnName, m_pImpl->m_xConnection, nullptr, false, false );
+ }
+ else if ( SQL_ISRULE(pParent,between_predicate_part_2) )
+ {
+ const OSQLParseNode* pOther = pParent->getParent()->getChild(0);
+ if ( SQL_ISRULE( pOther, column_ref ) )
+ getColumnRange( pOther, sColumnName, sTableRange, aColumnAlias);
+ else
+ {
+ pOther->parseNodeToStr( sColumnName, m_pImpl->m_xConnection, nullptr, false, false );
+ lcl_generateParameterName( *pParent, *_pNode );
+ }
+ }
+ else if ( pParent->getNodeType() == SQLNodeType::CommaListRule )
+ {
+ lcl_generateParameterName( *pParent, *_pNode );
+ }
+ }
+ traverseParameter( _pNode, pParent, sColumnName, sTableRange, aColumnAlias );
+ const sal_uInt32 nCount = _pNode->count();
+ for (sal_uInt32 i = 0; i < nCount; ++i)
+ {
+ const OSQLParseNode* pChild = _pNode->getChild(i);
+ traverseParameters( pChild );
+ }
+}
+
+bool OSQLParseTreeIterator::traverseSelectionCriteria(const OSQLParseNode* pSelectNode)
+{
+ if ( pSelectNode == nullptr )
+ return false;
+
+
+ // Analyse parse tree (depending on statement type)
+ // and set pointer to WHERE clause:
+ OSQLParseNode * pWhereClause = nullptr;
+
+ if (m_eStatementType == OSQLStatementType::Select)
+ {
+ if(SQL_ISRULE(pSelectNode,union_statement))
+ {
+ return traverseSelectionCriteria( pSelectNode->getChild( 0 ) )
+ && traverseSelectionCriteria( pSelectNode->getChild( 3 ) );
+ }
+ OSL_ENSURE(pSelectNode->count() >= 4,"OSQLParseTreeIterator: error in parse tree!");
+
+ OSQLParseNode * pTableExp = pSelectNode->getChild(3);
+ OSL_ENSURE(pTableExp != nullptr,"OSQLParseTreeIterator: error in parse tree!");
+ OSL_ENSURE(SQL_ISRULE(pTableExp,table_exp),"OSQLParseTreeIterator: error in parse tree!");
+ OSL_ENSURE(pTableExp->count() == TABLE_EXPRESSION_CHILD_COUNT,"OSQLParseTreeIterator: error in parse tree!");
+
+ pWhereClause = pTableExp->getChild(1);
+ } else if (SQL_ISRULE(pSelectNode,update_statement_searched)) {
+ OSL_ENSURE(pSelectNode->count() == 5,"OSQLParseTreeIterator: error in parse tree!");
+ pWhereClause = pSelectNode->getChild(4);
+ } else if (SQL_ISRULE(pSelectNode,delete_statement_searched)) {
+ OSL_ENSURE(pSelectNode->count() == 4,"OSQLParseTreeIterator: error in parse tree!");
+ pWhereClause = pSelectNode->getChild(3);
+ } else if (SQL_ISRULE(pSelectNode,delete_statement_positioned)) {
+ // nyi
+ SAL_WARN( "connectivity.parse","OSQLParseTreeIterator::getSelectionCriteria: positioned nyi");
+ } else {
+ // Other statement, no selection criteria
+ return false;
+ }
+
+ if (!pWhereClause || !SQL_ISRULE(pWhereClause,where_clause))
+ {
+ // The WHERE clause is optional most of the time; which means it could be a "optional_where_clause".
+ OSL_ENSURE(pWhereClause && SQL_ISRULE(pWhereClause,opt_where_clause),"OSQLParseTreeIterator: error in parse tree!");
+ return false;
+ }
+
+ // But if it's a where_clause, then it must not be empty
+ OSL_ENSURE(pWhereClause->count() == 2,"OSQLParseTreeIterator: error in parse tree!");
+
+ OSQLParseNode * pComparisonPredicate = pWhereClause->getChild(1);
+ OSL_ENSURE(pComparisonPredicate != nullptr,"OSQLParseTreeIterator: error in parse tree!");
+
+
+ // Process the comparison criteria now
+
+
+ traverseSearchCondition(pComparisonPredicate);
+
+ return !hasErrors();
+}
+
+
+void OSQLParseTreeIterator::traverseSearchCondition(OSQLParseNode const * pSearchCondition)
+{
+ if (
+ SQL_ISRULE(pSearchCondition,boolean_primary) &&
+ pSearchCondition->count() == 3 &&
+ SQL_ISPUNCTUATION(pSearchCondition->getChild(0),"(") &&
+ SQL_ISPUNCTUATION(pSearchCondition->getChild(2),")")
+ )
+ {
+ // Round brackets
+ traverseSearchCondition(pSearchCondition->getChild(1));
+ }
+ // The first element is an OR logical operation
+ else if ( SQL_ISRULE(pSearchCondition,search_condition) && pSearchCondition->count() == 3 )
+ {
+ // if this assert fails, the SQL grammar has changed!
+ assert(SQL_ISTOKEN(pSearchCondition->getChild(1),OR));
+ // Then process recursively (use the same row) ...
+ traverseSearchCondition(pSearchCondition->getChild(0));
+// if (! aIteratorStatus.IsSuccessful())
+// return;
+
+ // Continue with the right child
+ traverseSearchCondition(pSearchCondition->getChild(2));
+ }
+ // The first element is an AND logical operation (again)
+ else if ( SQL_ISRULE(pSearchCondition,boolean_term) && pSearchCondition->count() == 3 )
+ {
+ // Then process recursively (use the same row)
+ traverseSearchCondition(pSearchCondition->getChild(0));
+// if (! aIteratorStatus.IsSuccessful())
+// return;
+
+ // Continue with the right child
+ traverseSearchCondition(pSearchCondition->getChild(2));
+ }
+ // Else, process single search criteria (like =, !=, ..., LIKE, IS NULL etc.)
+ else if (SQL_ISRULE(pSearchCondition,comparison_predicate) )
+ {
+ OUString aValue;
+ pSearchCondition->getChild(2)->parseNodeToStr( aValue, m_pImpl->m_xConnection, nullptr, false, false );
+ traverseOnePredicate(pSearchCondition->getChild(0),aValue,pSearchCondition->getChild(2));
+ impl_fillJoinConditions(pSearchCondition);
+// if (! aIteratorStatus.IsSuccessful())
+// return;
+ }
+ else if (SQL_ISRULE(pSearchCondition,like_predicate) /*&& SQL_ISRULE(pSearchCondition->getChild(0),column_ref)*/)
+ {
+ OSL_ENSURE(pSearchCondition->count() == 2,"OSQLParseTreeIterator: error in parse tree!");
+ const OSQLParseNode* pPart2 = pSearchCondition->getChild(1);
+
+ sal_Int32 nCurrentPos = pPart2->count()-2;
+
+ OSQLParseNode * pNum_value_exp = pPart2->getChild(nCurrentPos);
+ OSQLParseNode * pOptEscape = pPart2->getChild(nCurrentPos+1);
+
+ OSL_ENSURE(pNum_value_exp != nullptr,"OSQLParseTreeIterator: error in parse tree!");
+ OSL_ENSURE(pOptEscape != nullptr,"OSQLParseTreeIterator: error in parse tree!");
+
+ if (pOptEscape->count() != 0)
+ {
+ // aIteratorStatus.setStatementTooComplex();
+ return;
+ }
+
+ OUString aValue;
+ OSQLParseNode * pParam = nullptr;
+ if (SQL_ISRULE(pNum_value_exp,parameter))
+ pParam = pNum_value_exp;
+ else if(pNum_value_exp->isToken())
+ // Normal value
+ aValue = pNum_value_exp->getTokenValue();
+ else
+ {
+ pNum_value_exp->parseNodeToStr( aValue, m_pImpl->m_xConnection, nullptr, false, false );
+ pParam = pNum_value_exp;
+ }
+
+ traverseOnePredicate(pSearchCondition->getChild(0),aValue,pParam);
+// if (! aIteratorStatus.IsSuccessful())
+// return;
+ }
+ else if (SQL_ISRULE(pSearchCondition,in_predicate))
+ {
+ OSL_ENSURE(pSearchCondition->count() == 2,"OSQLParseTreeIterator: error in parse tree!");
+ const OSQLParseNode* pPart2 = pSearchCondition->getChild(1);
+
+ traverseSearchCondition(pSearchCondition->getChild(0));
+ // if (! aIteratorStatus.IsSuccessful()) return;
+
+ OSQLParseNode* pChild = pPart2->getChild(2);
+ if ( SQL_ISRULE(pChild->getChild(0),subquery) )
+ {
+ traverseTableNames( *m_pImpl->m_pSubTables );
+ traverseSelectionCriteria(pChild->getChild(0)->getChild(1));
+ }
+ else
+ { // '(' value_exp_commalist ')'
+ pChild = pChild->getChild(1);
+ sal_Int32 nCount = pChild->count();
+ for (sal_Int32 i=0; i < nCount; ++i)
+ {
+ traverseSearchCondition(pChild->getChild(i));
+ }
+ }
+ }
+ else if (SQL_ISRULE(pSearchCondition,test_for_null) /*&& SQL_ISRULE(pSearchCondition->getChild(0),column_ref)*/)
+ {
+ OSL_ENSURE(pSearchCondition->count() == 2,"OSQLParseTreeIterator: error in parse tree!");
+ const OSQLParseNode* pPart2 = pSearchCondition->getChild(1);
+ OSL_ENSURE(SQL_ISTOKEN(pPart2->getChild(0),IS),"OSQLParseTreeIterator: error in parse tree!");
+
+ OUString aString;
+ traverseOnePredicate(pSearchCondition->getChild(0),aString,nullptr);
+ // if (! aIteratorStatus.IsSuccessful()) return;
+ }
+ else if (SQL_ISRULE(pSearchCondition,num_value_exp) || SQL_ISRULE(pSearchCondition,term))
+ {
+ OUString aString;
+ traverseOnePredicate(pSearchCondition->getChild(0),aString,pSearchCondition->getChild(0));
+ traverseOnePredicate(pSearchCondition->getChild(2),aString,pSearchCondition->getChild(2));
+ }
+ // Just pass on the error
+}
+
+void OSQLParseTreeIterator::traverseParameter(const OSQLParseNode* _pParseNode
+ ,const OSQLParseNode* _pParentNode
+ ,const OUString& _aColumnName
+ ,OUString& _aTableRange
+ ,const OUString& _rColumnAlias)
+{
+ if ( !SQL_ISRULE( _pParseNode, parameter ) )
+ return;
+
+ if ( !( m_pImpl->m_nIncludeMask & TraversalParts::Parameters ) )
+ // parameters not to be included in the traversal
+ return;
+
+ OSL_ENSURE(_pParseNode->count() > 0,"OSQLParseTreeIterator: error in parse tree!");
+ OSQLParseNode * pMark = _pParseNode->getChild(0);
+ OUString sParameterName;
+
+ if (SQL_ISPUNCTUATION(pMark,"?"))
+ {
+ sParameterName = !_rColumnAlias.isEmpty()
+ ? _rColumnAlias
+ : !_aColumnName.isEmpty()
+ ? _aColumnName
+ : OUString("?");
+ }
+ else if (SQL_ISPUNCTUATION(pMark,":"))
+ {
+ sParameterName = _pParseNode->getChild(1)->getTokenValue();
+ }
+ else if (SQL_ISPUNCTUATION(pMark,"["))
+ {
+ sParameterName = _pParseNode->getChild(1)->getTokenValue();
+ }
+ else
+ {
+ SAL_WARN( "connectivity.parse","OSQLParseTreeIterator: error in parse tree!");
+ }
+
+ // found a parameter
+ if ( _pParentNode && (SQL_ISRULE(_pParentNode,general_set_fct) || SQL_ISRULE(_pParentNode,set_fct_spec)) )
+ {// found a function as column_ref
+ OUString sFunctionName;
+ _pParentNode->getChild(0)->parseNodeToStr( sFunctionName, m_pImpl->m_xConnection, nullptr, false, false );
+ const sal_uInt32 nCount = _pParentNode->count();
+ sal_uInt32 i = 0;
+ for(; i < nCount;++i)
+ {
+ if ( _pParentNode->getChild(i) == _pParseNode )
+ break;
+ }
+ sal_Int32 nType = ::connectivity::OSQLParser::getFunctionParameterType( _pParentNode->getChild(0)->getTokenID(), i-1);
+
+ rtl::Reference<OParseColumn> pColumn = new OParseColumn( sParameterName,
+ OUString(),
+ OUString(),
+ OUString(),
+ ColumnValue::NULLABLE_UNKNOWN,
+ 0,
+ 0,
+ nType,
+ false,
+ false,
+ isCaseSensitive(),
+ OUString(),
+ OUString(),
+ OUString());
+ pColumn->setFunction(true);
+ pColumn->setAggregateFunction(true);
+ pColumn->setRealName(sFunctionName);
+ m_aParameters->push_back(pColumn);
+ }
+ else
+ {
+ bool bNotFound = true;
+ OSQLColumns::const_iterator aIter = ::connectivity::find(
+ m_aSelectColumns->begin(),
+ m_aSelectColumns->end(),
+ _aColumnName,::comphelper::UStringMixEqual( isCaseSensitive() )
+ );
+ if(aIter != m_aSelectColumns->end())
+ {
+ rtl::Reference<OParseColumn> pNewColumn = new OParseColumn(*aIter,isCaseSensitive());
+ pNewColumn->setName(sParameterName);
+ pNewColumn->setRealName(_aColumnName);
+ m_aParameters->push_back(pNewColumn);
+ bNotFound = false;
+ }
+ else if(!_aColumnName.isEmpty())// search in the tables for the right one
+ {
+
+ Reference<XPropertySet> xColumn = findColumn( _aColumnName, _aTableRange, true );
+
+ if ( xColumn.is() )
+ {
+ rtl::Reference<OParseColumn> pNewColumn = new OParseColumn(xColumn,isCaseSensitive());
+ pNewColumn->setName(sParameterName);
+ pNewColumn->setRealName(_aColumnName);
+ m_aParameters->push_back(pNewColumn);
+ bNotFound = false;
+ }
+ }
+ if ( bNotFound )
+ {
+ sal_Int32 nType = DataType::VARCHAR;
+ OSQLParseNode* pParent = _pParentNode ? _pParentNode->getParent() : nullptr;
+ if ( pParent && (SQL_ISRULE(pParent,general_set_fct) || SQL_ISRULE(pParent,set_fct_spec)) )
+ {
+ const sal_uInt32 nCount = _pParentNode->count();
+ sal_uInt32 i = 0;
+ for(; i < nCount;++i)
+ {
+ if ( _pParentNode->getChild(i) == _pParseNode )
+ break;
+ }
+ nType = ::connectivity::OSQLParser::getFunctionParameterType( pParent->getChild(0)->getTokenID(), i+1);
+ }
+
+ OUString aNewColName(getUniqueColumnName(getSelectColumnNames(), sParameterName));
+
+ rtl::Reference<OParseColumn> pColumn = new OParseColumn(aNewColName,
+ OUString(),
+ OUString(),
+ OUString(),
+ ColumnValue::NULLABLE_UNKNOWN,
+ 0,
+ 0,
+ nType,
+ false,
+ false,
+ isCaseSensitive(),
+ OUString(),
+ OUString(),
+ OUString());
+ pColumn->setName(aNewColName);
+ pColumn->setRealName(sParameterName);
+ m_aParameters->push_back(pColumn);
+ }
+ }
+}
+
+void OSQLParseTreeIterator::traverseOnePredicate(
+ OSQLParseNode const * pColumnRef,
+ OUString& rValue,
+ OSQLParseNode const * pParseNode)
+{
+ if ( !pParseNode )
+ return;
+
+ // Column name (and TableRange):
+ OUString aColumnName, aTableRange, sColumnAlias;
+ getColumnRange( pColumnRef, aColumnName, aTableRange, sColumnAlias);
+
+ OUString aName;
+
+ /*if (SQL_ISRULE(pParseNode,parameter))
+ traverseParameter( pParseNode, pColumnRef, aColumnName, aTableRange, sColumnAlias );
+ else */if (SQL_ISRULE(pParseNode,column_ref))// Column-Name (and TableRange):
+ getColumnRange(pParseNode,aName,rValue);
+ else
+ {
+ traverseSearchCondition(pParseNode);
+ // if (! aIteratorStatus.IsSuccessful()) return;
+ }
+}
+
+
+void OSQLParseTreeIterator::traverseAll()
+{
+ impl_traverse( TraversalParts::All );
+}
+
+
+void OSQLParseTreeIterator::impl_traverse( TraversalParts _nIncludeMask )
+{
+ // resets our errors
+ m_xErrors.reset();
+
+ m_pImpl->m_nIncludeMask = _nIncludeMask;
+
+ if ( !traverseTableNames( *m_pImpl->m_pTables ) )
+ return;
+
+ switch ( m_eStatementType )
+ {
+ case OSQLStatementType::Select:
+ {
+ const OSQLParseNode* pSelectNode = m_pParseTree;
+ traverseParameters( pSelectNode );
+ if ( !traverseSelectColumnNames( pSelectNode )
+ || !traverseOrderByColumnNames( pSelectNode )
+ || !traverseGroupByColumnNames( pSelectNode )
+ || !traverseSelectionCriteria( pSelectNode )
+ )
+ return;
+ }
+ break;
+ case OSQLStatementType::CreateTable:
+ {
+ //0 | 1 | 2 |3| 4 |5
+ //create table sc.foo ( a char(20), b char )
+ const OSQLParseNode* pCreateNode = m_pParseTree->getChild(4);
+ traverseCreateColumns(pCreateNode);
+ }
+ break;
+ case OSQLStatementType::Insert:
+ break;
+ default:
+ break;
+ }
+}
+
+// Dummy implementations
+
+
+OSQLTable OSQLParseTreeIterator::impl_createTableObject( const OUString& rTableName,
+ const OUString& rCatalogName, const OUString& rSchemaName )
+{
+ OSL_PRECOND( m_eStatementType == OSQLStatementType::CreateTable,
+ "OSQLParseTreeIterator::impl_createTableObject: only to be called for CREATE TABLE statements!" );
+ // (in all other cases, m_pTables is to contain the table objects as obtained from the tables
+ // container of the connection (m_xTablesContainer)
+
+ OSQLTable aReturnTable = new OTable(
+ nullptr,
+ false,
+ rTableName,
+ "Table",
+ "New Created Table",
+ rSchemaName,
+ rCatalogName
+ );
+ return aReturnTable;
+}
+
+void OSQLParseTreeIterator::appendColumns(const OUString& _rTableAlias, const OSQLTable& _rTable)
+{
+ if (!_rTable.is())
+ return;
+
+ Reference<XNameAccess> xColumns = _rTable->getColumns();
+ if ( !xColumns.is() )
+ return;
+
+ Sequence< OUString > aColNames = xColumns->getElementNames();
+ const OUString* pBegin = aColNames.getConstArray();
+ const OUString* pEnd = pBegin + aColNames.getLength();
+
+ ::comphelper::UStringMixLess aCompare(isCaseSensitive());
+ std::vector<OUString> aSelectColumnNames = getSelectColumnNames();
+
+ for(;pBegin != pEnd;++pBegin)
+ {
+ OUString aName(getUniqueColumnName(aSelectColumnNames, *pBegin));
+ Reference< XPropertySet > xColumn;
+ if(xColumns->hasByName(*pBegin) && (xColumns->getByName(*pBegin) >>= xColumn) && xColumn.is())
+ {
+ rtl::Reference<OParseColumn> pColumn = new OParseColumn(aName
+ , getString(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPENAME)))
+ , getString(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DEFAULTVALUE)))
+ , getString(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DESCRIPTION)))
+ , getINT32(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISNULLABLE)))
+ , getINT32(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PRECISION)))
+ , getINT32(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCALE)))
+ , getINT32(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE)))
+ , getBOOL(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISAUTOINCREMENT)))
+ , getBOOL(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISCURRENCY)))
+ , isCaseSensitive()
+ , getString(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_CATALOGNAME)))
+ , getString(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCHEMANAME)))
+ , getString(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TABLENAME))));
+
+ pColumn->setTableName(_rTableAlias);
+ pColumn->setRealName(*pBegin);
+ m_aSelectColumns->push_back(pColumn);
+ // update aSelectColumnNames with newly insert aName
+ aSelectColumnNames.insert(std::upper_bound(aSelectColumnNames.begin(), aSelectColumnNames.end(), aName, aCompare), aName);
+ }
+ else
+ impl_appendError( IParseContext::ErrorCode::InvalidColumn, pBegin, &_rTableAlias );
+ }
+}
+
+void OSQLParseTreeIterator::setSelectColumnName(const OUString & rColumnName,const OUString & rColumnAlias, const OUString & rTableRange, bool bFkt, sal_Int32 _nType, bool bAggFkt)
+{
+ if(rColumnName.toChar() == '*' && rTableRange.isEmpty())
+ { // SELECT * ...
+ for (auto const& table : *m_pImpl->m_pTables)
+ appendColumns(table.first, table.second);
+ }
+ else if( rColumnName.toChar() == '*' && !rTableRange.isEmpty() )
+ { // SELECT <table>.*
+ OSQLTables::const_iterator aFind = m_pImpl->m_pTables->find(rTableRange);
+
+ if(aFind != m_pImpl->m_pTables->end())
+ appendColumns(rTableRange, aFind->second);
+ }
+ else if ( rTableRange.isEmpty() )
+ { // SELECT <something> ...
+ // without table specified
+ if ( !bFkt )
+ {
+ Reference< XPropertySet> xNewColumn;
+
+ for (auto const& table : *m_pImpl->m_pTables)
+ {
+ if ( !table.second.is() )
+ continue;
+
+ Reference<XNameAccess> xColumns = table.second->getColumns();
+ Reference< XPropertySet > xColumn;
+ if ( !xColumns->hasByName( rColumnName )
+ || !( xColumns->getByName( rColumnName ) >>= xColumn )
+ )
+ continue;
+
+ OUString aNewColName(getUniqueColumnName(getSelectColumnNames(), rColumnAlias));
+
+ rtl::Reference<OParseColumn> pColumn = new OParseColumn(xColumn,isCaseSensitive());
+ xNewColumn = pColumn;
+ pColumn->setTableName(table.first);
+ pColumn->setName(aNewColName);
+ pColumn->setRealName(rColumnName);
+
+ break;
+ }
+
+ if ( !xNewColumn.is() )
+ {
+ // no function (due to the above !bFkt), no existing column
+ // => assume an expression
+ OUString aNewColName(getUniqueColumnName(getSelectColumnNames(), rColumnAlias));
+ // did not find a column with this name in any of the tables
+ rtl::Reference<OParseColumn> pColumn = new OParseColumn(
+ aNewColName,
+ "VARCHAR",
+ // TODO: does this match with _nType?
+ // Or should be fill this from the getTypeInfo of the connection?
+ OUString(),
+ OUString(),
+ ColumnValue::NULLABLE_UNKNOWN,
+ 0,
+ 0,
+ _nType,
+ false,
+ false,
+ isCaseSensitive(),
+ OUString(),
+ OUString(),
+ OUString()
+ );
+
+ xNewColumn = pColumn;
+ pColumn->setRealName( rColumnName );
+ }
+
+ m_aSelectColumns->push_back( xNewColumn );
+ }
+ else
+ {
+ OUString aNewColName(getUniqueColumnName(getSelectColumnNames(), rColumnAlias));
+
+ rtl::Reference<OParseColumn> pColumn = new OParseColumn(aNewColName,OUString(),OUString(),OUString(),
+ ColumnValue::NULLABLE_UNKNOWN,0,0,_nType,false,false,isCaseSensitive(),
+ OUString(),OUString(),OUString());
+ pColumn->setFunction(true);
+ pColumn->setAggregateFunction(bAggFkt);
+ pColumn->setRealName(rColumnName);
+
+ m_aSelectColumns->push_back(pColumn);
+ }
+ }
+ else // ColumnName and TableName exist
+ {
+ OSQLTables::const_iterator aFind = m_pImpl->m_pTables->find(rTableRange);
+
+ bool bError = false;
+ if (aFind != m_pImpl->m_pTables->end() && aFind->second.is())
+ {
+ if (bFkt)
+ {
+ OUString aNewColName(getUniqueColumnName(getSelectColumnNames(), rColumnAlias));
+
+ rtl::Reference<OParseColumn> pColumn = new OParseColumn(aNewColName,OUString(),OUString(),OUString(),
+ ColumnValue::NULLABLE_UNKNOWN,0,0,_nType,false,false,isCaseSensitive(),
+ OUString(),OUString(),OUString());
+ pColumn->setFunction(true);
+ pColumn->setAggregateFunction(bAggFkt);
+ pColumn->setRealName(rColumnName);
+ SAL_WARN("connectivity.parse", "Trying to construct a column with Function==true and a TableName; this makes no sense.");
+ assert(false);
+ pColumn->setTableName(aFind->first);
+
+ m_aSelectColumns->push_back(pColumn);
+ }
+ else
+ {
+ Reference< XPropertySet > xColumn;
+ if (aFind->second->getColumns()->hasByName(rColumnName) && (aFind->second->getColumns()->getByName(rColumnName) >>= xColumn))
+ {
+ OUString aNewColName(getUniqueColumnName(getSelectColumnNames(), rColumnAlias));
+
+ rtl::Reference<OParseColumn> pColumn = new OParseColumn(xColumn,isCaseSensitive());
+ pColumn->setName(aNewColName);
+ pColumn->setRealName(rColumnName);
+ pColumn->setTableName(aFind->first);
+
+ m_aSelectColumns->push_back(pColumn);
+ }
+ else
+ bError = true;
+ }
+ }
+ else
+ bError = true;
+
+ // Table does not exist or lacking field
+ if (bError)
+ {
+ OUString aNewColName(getUniqueColumnName(getSelectColumnNames(), rColumnAlias));
+
+ rtl::Reference<OParseColumn> pColumn = new OParseColumn(aNewColName,OUString(),OUString(),OUString(),
+ ColumnValue::NULLABLE_UNKNOWN,0,0,DataType::VARCHAR,false,false,isCaseSensitive(),
+ OUString(),OUString(),OUString());
+ pColumn->setFunction(true);
+ pColumn->setAggregateFunction(bAggFkt);
+
+ m_aSelectColumns->push_back(pColumn);
+ }
+ }
+}
+
+std::vector<OUString> OSQLParseTreeIterator::getSelectColumnNames() const
+{
+ ::comphelper::UStringMixLess aCompare(isCaseSensitive());
+
+ std::vector<OUString> aColumnNames;
+ OUString sPropertyName = OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME);
+ for (const auto& col : *m_aSelectColumns)
+ aColumnNames.push_back(getString(col->getPropertyValue(sPropertyName)));
+ std::sort(aColumnNames.begin(), aColumnNames.end(), aCompare);
+
+ return aColumnNames;
+}
+
+OUString OSQLParseTreeIterator::getUniqueColumnName(const std::vector<OUString>& rColumnNames, const OUString& rColumnName) const
+{
+ ::comphelper::UStringMixLess aCompare(isCaseSensitive());
+ if (!std::binary_search(rColumnNames.begin(), rColumnNames.end(), rColumnName, aCompare))
+ return rColumnName;
+
+ OUString aAlias;
+ sal_Int32 i=1;
+ do
+ {
+ aAlias = rColumnName + OUString::number(i++);
+ }
+ while (std::binary_search(rColumnNames.begin(), rColumnNames.end(), aAlias, aCompare));
+ return aAlias;
+}
+
+void OSQLParseTreeIterator::setOrderByColumnName(const OUString & rColumnName, OUString & rTableRange, bool bAscending)
+{
+ Reference<XPropertySet> xColumn = findSelectColumn( rColumnName );
+ if ( !xColumn.is() )
+ xColumn = findColumn ( rColumnName, rTableRange, false );
+ if ( xColumn.is() )
+ m_aOrderColumns->push_back(new OOrderColumn( xColumn, rTableRange, isCaseSensitive(), bAscending ) );
+ else
+ {
+ sal_Int32 nId = rColumnName.toInt32();
+ if ( nId > 0 && o3tl::make_unsigned(nId) < m_aSelectColumns->size() )
+ m_aOrderColumns->push_back( new OOrderColumn( (*m_aSelectColumns)[nId-1], isCaseSensitive(), bAscending ) );
+ }
+
+#ifdef SQL_TEST_PARSETREEITERATOR
+ cout << "OSQLParseTreeIterator::setOrderByColumnName: "
+ << (const char *) rColumnName << ", "
+ << (const char *) rTableRange << ", "
+ << (bAscending ? "true" : "false")
+ << "\n";
+#endif
+}
+
+void OSQLParseTreeIterator::setGroupByColumnName(const OUString & rColumnName, OUString & rTableRange)
+{
+ Reference<XPropertySet> xColumn = findColumn( rColumnName, rTableRange, false );
+ if ( xColumn.is() )
+ m_aGroupColumns->push_back(new OParseColumn(xColumn,isCaseSensitive()));
+ else
+ {
+ sal_Int32 nId = rColumnName.toInt32();
+ if ( nId > 0 && o3tl::make_unsigned(nId) < m_aSelectColumns->size() )
+ m_aGroupColumns->push_back(new OParseColumn((*m_aSelectColumns)[nId-1],isCaseSensitive()));
+ }
+
+#ifdef SQL_TEST_PARSETREEITERATOR
+ cout << "OSQLParseTreeIterator::setGroupByColumnName: "
+ << (const char *) rColumnName << ", "
+ << (const char *) rTableRange << ", "
+ << (bAscending ? "true" : "false")
+ << "\n";
+#endif
+}
+
+
+const OSQLParseNode* OSQLParseTreeIterator::getWhereTree() const
+{
+ if (!m_pParseTree)
+ return nullptr;
+
+ // Analyse parse tree (depending on statement type)
+ // and set pointer to WHERE clause:
+ OSQLParseNode * pWhereClause = nullptr;
+ if(getStatementType() == OSQLStatementType::Select)
+ {
+ OSL_ENSURE(m_pParseTree->count() >= 4,"ParseTreeIterator: error in parse tree!");
+ OSQLParseNode * pTableExp = m_pParseTree->getChild(3);
+ OSL_ENSURE(pTableExp != nullptr,"OSQLParseTreeIterator: error in parse tree!");
+ OSL_ENSURE(SQL_ISRULE(pTableExp,table_exp),"OSQLParseTreeIterator: error in parse tree!");
+ OSL_ENSURE(pTableExp->count() == TABLE_EXPRESSION_CHILD_COUNT,"OSQLParseTreeIterator: error in parse tree!");
+
+ pWhereClause = pTableExp->getChild(1);
+ }
+ else if (SQL_ISRULE(m_pParseTree,update_statement_searched) ||
+ SQL_ISRULE(m_pParseTree,delete_statement_searched))
+ {
+ pWhereClause = m_pParseTree->getChild(m_pParseTree->count()-1);
+ }
+ if(pWhereClause && pWhereClause->count() != 2)
+ pWhereClause = nullptr;
+ return pWhereClause;
+}
+
+
+const OSQLParseNode* OSQLParseTreeIterator::getOrderTree() const
+{
+ if (!m_pParseTree || getStatementType() != OSQLStatementType::Select)
+ return nullptr;
+
+ // Analyse parse tree (depending on statement type)
+ // and set pointer to ORDER clause:
+
+ assert(SQL_ISRULE(m_pParseTree, select_statement) || SQL_ISRULE(m_pParseTree, union_statement));
+
+ auto pParseTree = m_pParseTree;
+ if(SQL_ISRULE(m_pParseTree, union_statement))
+ {
+ assert(m_pParseTree->count() == 4);
+ pParseTree = pParseTree->getChild(3);
+ // since UNION is left-associative (at least in our grammar),
+ // possibly the left-hand (m_pParseTree->getChild(0)) is a union_statement,
+ // but the right hand cannot.
+ assert(SQL_ISRULE(pParseTree, select_statement));
+ }
+
+ OSQLParseNode * pOrderClause = nullptr;
+ OSL_ENSURE(pParseTree->count() == 4, "OSQLParseTreeIterator::getOrderTree: expected a SELECT, and a SELECT must have exactly four children");
+ OSQLParseNode * pTableExp = pParseTree->getChild(3);
+ OSL_ENSURE(pTableExp != nullptr, "OSQLParseTreeIterator::getOrderTree: got NULL table_exp");
+ OSL_ENSURE(SQL_ISRULE(pTableExp, table_exp), "OSQLParseTreeIterator::getOrderTree: expected table_exp but got something else");
+ OSL_ENSURE(pTableExp->count() == TABLE_EXPRESSION_CHILD_COUNT,"OSQLParseTreeIterator::getOrderTree: table_exp doesn't have the expected number of children");
+ // tdf#141115 upgrade the above to an assert;
+ // this cannot go well if there are too few children
+ assert(pTableExp->count() == TABLE_EXPRESSION_CHILD_COUNT);
+
+ pOrderClause = pTableExp->getChild(ORDER_BY_CHILD_POS);
+ // If it is an order_by, it must not be empty
+ if(pOrderClause->count() != 3)
+ pOrderClause = nullptr;
+ return pOrderClause;
+}
+
+const OSQLParseNode* OSQLParseTreeIterator::getGroupByTree() const
+{
+ if (!m_pParseTree || getStatementType() != OSQLStatementType::Select)
+ return nullptr;
+
+ // Analyse parse tree (depending on statement type)
+ // and set pointer to ORDER clause:
+ OSQLParseNode * pGroupClause = nullptr;
+ OSL_ENSURE(m_pParseTree->count() >= 4,"ParseTreeIterator: error in parse tree!");
+ OSQLParseNode * pTableExp = m_pParseTree->getChild(3);
+ OSL_ENSURE(pTableExp != nullptr,"OSQLParseTreeIterator: error in parse tree!");
+ OSL_ENSURE(SQL_ISRULE(pTableExp,table_exp),"OSQLParseTreeIterator: error in parse tree!");
+ OSL_ENSURE(pTableExp->count() == TABLE_EXPRESSION_CHILD_COUNT,"OSQLParseTreeIterator: error in parse tree!");
+
+ pGroupClause = pTableExp->getChild(2);
+ // If it is an order_by, it must not be empty
+ if(pGroupClause->count() != 3)
+ pGroupClause = nullptr;
+ return pGroupClause;
+}
+
+const OSQLParseNode* OSQLParseTreeIterator::getHavingTree() const
+{
+ if (!m_pParseTree || getStatementType() != OSQLStatementType::Select)
+ return nullptr;
+
+ // Analyse parse tree (depending on statement type)
+ // and set pointer to ORDER clause:
+ OSQLParseNode * pHavingClause = nullptr;
+ OSL_ENSURE(m_pParseTree->count() >= 4,"ParseTreeIterator: error in parse tree!");
+ OSQLParseNode * pTableExp = m_pParseTree->getChild(3);
+ OSL_ENSURE(pTableExp != nullptr,"OSQLParseTreeIterator: error in parse tree!");
+ OSL_ENSURE(SQL_ISRULE(pTableExp,table_exp),"OSQLParseTreeIterator: error in parse tree!");
+ OSL_ENSURE(pTableExp->count() == TABLE_EXPRESSION_CHILD_COUNT,"OSQLParseTreeIterator: error in parse tree!");
+
+ pHavingClause = pTableExp->getChild(3);
+ // If it is an order_by, then it must not be empty
+ if(pHavingClause->count() < 1)
+ pHavingClause = nullptr;
+ return pHavingClause;
+}
+
+bool OSQLParseTreeIterator::isTableNode(const OSQLParseNode* _pTableNode)
+{
+ return _pTableNode && (SQL_ISRULE(_pTableNode,catalog_name) ||
+ SQL_ISRULE(_pTableNode,schema_name) ||
+ SQL_ISRULE(_pTableNode,table_name));
+}
+
+const OSQLParseNode* OSQLParseTreeIterator::getSimpleWhereTree() const
+{
+ const OSQLParseNode* pNode = getWhereTree();
+ return pNode ? pNode->getChild(1) : nullptr;
+}
+
+const OSQLParseNode* OSQLParseTreeIterator::getSimpleOrderTree() const
+{
+ const OSQLParseNode* pNode = getOrderTree();
+ return pNode ? pNode->getChild(2) : nullptr;
+}
+
+const OSQLParseNode* OSQLParseTreeIterator::getSimpleGroupByTree() const
+{
+ const OSQLParseNode* pNode = getGroupByTree();
+ return pNode ? pNode->getChild(2) : nullptr;
+}
+
+const OSQLParseNode* OSQLParseTreeIterator::getSimpleHavingTree() const
+{
+ const OSQLParseNode* pNode = getHavingTree();
+ return pNode ? pNode->getChild(1) : nullptr;
+}
+
+
+Reference< XPropertySet > OSQLParseTreeIterator::findSelectColumn( std::u16string_view rColumnName )
+{
+ for (auto const& lookupColumn : *m_aSelectColumns)
+ {
+ Reference< XPropertySet > xColumn( lookupColumn );
+ try
+ {
+ OUString sName;
+ xColumn->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex( PROPERTY_ID_NAME ) ) >>= sName;
+ if ( sName == rColumnName )
+ return xColumn;
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("connectivity.parse");
+ }
+ }
+ return nullptr;
+}
+
+
+Reference< XPropertySet > OSQLParseTreeIterator::findColumn( const OUString & rColumnName, OUString & rTableRange, bool _bLookInSubTables )
+{
+ Reference< XPropertySet > xColumn = findColumn( *m_pImpl->m_pTables, rColumnName, rTableRange );
+ if ( !xColumn.is() && _bLookInSubTables )
+ xColumn = findColumn( *m_pImpl->m_pSubTables, rColumnName, rTableRange );
+ return xColumn;
+}
+
+
+Reference< XPropertySet > OSQLParseTreeIterator::findColumn(const OSQLTables& _rTables, const OUString & rColumnName, OUString & rTableRange)
+{
+ Reference< XPropertySet > xColumn;
+ if ( !rTableRange.isEmpty() )
+ {
+ OSQLTables::const_iterator aFind = _rTables.find(rTableRange);
+
+ if ( aFind != _rTables.end()
+ && aFind->second.is()
+ && aFind->second->getColumns().is()
+ && aFind->second->getColumns()->hasByName(rColumnName) )
+ aFind->second->getColumns()->getByName(rColumnName) >>= xColumn;
+ }
+ if ( !xColumn.is() )
+ {
+ for (auto const& table : _rTables)
+ {
+ if ( table.second.is() )
+ {
+ Reference<XNameAccess> xColumns = table.second->getColumns();
+ if( xColumns.is() && xColumns->hasByName(rColumnName) && (xColumns->getByName(rColumnName) >>= xColumn) )
+ {
+ OSL_ENSURE(xColumn.is(),"Column isn't a propertyset!");
+ // Cannot take "rTableRange = table.first" because that is the fully composed name
+ // that is, catalogName.schemaName.tableName
+ rTableRange = getString(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TABLENAME)));
+ break; // This column must only exits once
+ }
+ }
+ }
+ }
+ return xColumn;
+}
+
+
+void OSQLParseTreeIterator::impl_appendError( IParseContext::ErrorCode _eError, const OUString* _pReplaceToken1, const OUString* _pReplaceToken2 )
+{
+ OUString sErrorMessage = m_rParser.getContext().getErrorMessage( _eError );
+ if ( _pReplaceToken1 )
+ {
+ bool bTwoTokens = ( _pReplaceToken2 != nullptr );
+ const char* pPlaceHolder1 = bTwoTokens ? "#1" : "#";
+ const OUString sPlaceHolder1 = OUString::createFromAscii( pPlaceHolder1 );
+
+ sErrorMessage = sErrorMessage.replaceFirst( sPlaceHolder1, *_pReplaceToken1 );
+ if ( _pReplaceToken2 )
+ sErrorMessage = sErrorMessage.replaceFirst( "#2" , *_pReplaceToken2 );
+ }
+
+ impl_appendError( SQLException(
+ sErrorMessage, nullptr, getStandardSQLState( StandardSQLState::GENERAL_ERROR ), 1000, Any() ) );
+}
+
+
+void OSQLParseTreeIterator::impl_appendError( const SQLException& _rError )
+{
+ SAL_WARN("connectivity.parse", "Adding error " << exceptionToString(Any(_rError)));
+ if ( m_xErrors )
+ {
+ SQLException* pErrorChain = &*m_xErrors;
+ while ( pErrorChain->NextException.hasValue() )
+ pErrorChain = static_cast< SQLException* >( pErrorChain->NextException.pData );
+ pErrorChain->NextException <<= _rError;
+ }
+ else
+ m_xErrors = _rError;
+}
+
+sal_Int32 OSQLParseTreeIterator::getFunctionReturnType(const OSQLParseNode* _pNode )
+{
+ sal_Int32 nType = DataType::OTHER;
+ OUString sFunctionName;
+ if ( SQL_ISRULE(_pNode,length_exp) )
+ {
+ _pNode->getChild(0)->getChild(0)->parseNodeToStr(sFunctionName, m_pImpl->m_xConnection, nullptr, false, false );
+ nType = ::connectivity::OSQLParser::getFunctionReturnType( sFunctionName, &m_rParser.getContext() );
+ }
+ else if ( SQL_ISRULE(_pNode,num_value_exp) || SQL_ISRULE(_pNode,term) || SQL_ISRULE(_pNode,factor) )
+ {
+ nType = DataType::DOUBLE;
+ }
+ else
+ {
+ _pNode->getChild(0)->parseNodeToStr(sFunctionName, m_pImpl->m_xConnection, nullptr, false, false );
+
+ // MIN and MAX have another return type, we have to check the expression itself.
+ // @see http://qa.openoffice.org/issues/show_bug.cgi?id=99566
+ if ( SQL_ISRULE(_pNode,general_set_fct) && (SQL_ISTOKEN(_pNode->getChild(0),MIN) || SQL_ISTOKEN(_pNode->getChild(0),MAX) ))
+ {
+ const OSQLParseNode* pValueExp = _pNode->getChild(3);
+ if (SQL_ISRULE(pValueExp,column_ref))
+ {
+ OUString sColumnName;
+ OUString aTableRange;
+ getColumnRange(pValueExp,sColumnName,aTableRange);
+ OSL_ENSURE(!sColumnName.isEmpty(),"Columnname must not be empty!");
+ Reference<XPropertySet> xColumn = findColumn( sColumnName, aTableRange, true );
+
+ if ( xColumn.is() )
+ {
+ xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex( PROPERTY_ID_TYPE)) >>= nType;
+ }
+ }
+ else
+ {
+ if ( SQL_ISRULE(pValueExp,num_value_exp) || SQL_ISRULE(pValueExp,term) || SQL_ISRULE(pValueExp,factor) )
+ {
+ nType = DataType::DOUBLE;
+ }
+ else if ( SQL_ISRULE(pValueExp,datetime_primary) )
+ {
+ switch(pValueExp->getChild(0)->getTokenID() )
+ {
+ case SQL_TOKEN_CURRENT_DATE:
+ nType = DataType::DATE;
+ break;
+ case SQL_TOKEN_CURRENT_TIME:
+ nType = DataType::TIME;
+ break;
+ case SQL_TOKEN_CURRENT_TIMESTAMP:
+ nType = DataType::TIMESTAMP;
+ break;
+ }
+ }
+ else if ( SQL_ISRULE(pValueExp,value_exp_primary) )
+ {
+ nType = getFunctionReturnType(pValueExp->getChild(1));
+ }
+ else if ( SQL_ISRULE(pValueExp,concatenation)
+ || SQL_ISRULE(pValueExp,char_factor)
+ || SQL_ISRULE(pValueExp,bit_value_fct)
+ || SQL_ISRULE(pValueExp,char_value_fct)
+ || SQL_ISRULE(pValueExp,char_substring_fct)
+ || SQL_ISRULE(pValueExp,fold)
+ || SQL_ISTOKEN(pValueExp,STRING) )
+ {
+ nType = DataType::VARCHAR;
+ }
+ }
+ if ( nType == DataType::OTHER )
+ nType = DataType::DOUBLE;
+ }
+ else
+ {
+ nType = ::connectivity::OSQLParser::getFunctionReturnType( sFunctionName, &m_rParser.getContext() );
+ if (nType == DataType::SQLNULL)
+ nType = ::connectivity::OSQLParser::getFunctionReturnType( sFunctionName, m_rParser.getNeutral() );
+ }
+ }
+
+ return nType;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/parse/sqlnode.cxx b/connectivity/source/parse/sqlnode.cxx
new file mode 100644
index 0000000000..45030592cf
--- /dev/null
+++ b/connectivity/source/parse/sqlnode.cxx
@@ -0,0 +1,2775 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/macros.h>
+#include <connectivity/sqlnode.hxx>
+#include <connectivity/sqlerror.hxx>
+#include <connectivity/sqlbison_exports.hxx>
+#include <connectivity/internalnode.hxx>
+#define YYBISON 1
+#include <sqlbison.hxx>
+#include <connectivity/sqlparse.hxx>
+#include <connectivity/sqlscan.hxx>
+#include <com/sun/star/lang/Locale.hpp>
+#include <com/sun/star/util/XNumberFormatter.hpp>
+#include <com/sun/star/util/XNumberFormatTypes.hpp>
+#include <com/sun/star/i18n/LocaleData.hpp>
+#include <com/sun/star/i18n/NumberFormatIndex.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/sdbc/XDatabaseMetaData.hpp>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <com/sun/star/sdb/XQueriesSupplier.hpp>
+#include <com/sun/star/sdb/ErrorCondition.hpp>
+#include <com/sun/star/util/XNumberFormatsSupplier.hpp>
+#include <com/sun/star/util/XNumberFormats.hpp>
+#include <com/sun/star/util/NumberFormat.hpp>
+#include <com/sun/star/i18n/KParseType.hpp>
+#include <com/sun/star/i18n/KParseTokens.hpp>
+#include <com/sun/star/i18n/CharacterClassification.hpp>
+#include <connectivity/dbconversion.hxx>
+#include <com/sun/star/util/DateTime.hpp>
+#include <com/sun/star/util/Time.hpp>
+#include <com/sun/star/util/Date.hpp>
+#include <TConnection.hxx>
+#include <comphelper/numbers.hxx>
+#include <connectivity/dbtools.hxx>
+#include <connectivity/dbmetadata.hxx>
+#include <comphelper/diagnose_ex.hxx>
+#include <string.h>
+#include <algorithm>
+#include <functional>
+#include <memory>
+#include <string_view>
+
+#include <rtl/ustrbuf.hxx>
+#include <sal/log.hxx>
+#include <utility>
+
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::util;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::i18n;
+using namespace ::com::sun::star;
+using namespace ::osl;
+using namespace ::dbtools;
+using namespace ::comphelper;
+
+namespace
+{
+
+ bool lcl_saveConvertToNumber(const Reference< XNumberFormatter > & _xFormatter,sal_Int32 _nKey,const OUString& _sValue,double& _nrValue)
+ {
+ bool bRet = false;
+ try
+ {
+ _nrValue = _xFormatter->convertStringToNumber(_nKey, _sValue);
+ bRet = true;
+ }
+ catch(Exception&)
+ {
+ }
+ return bRet;
+ }
+
+ void replaceAndReset(connectivity::OSQLParseNode*& _pResetNode,connectivity::OSQLParseNode* _pNewNode)
+ {
+ _pResetNode->getParent()->replaceAndDelete(_pResetNode, _pNewNode);
+ _pResetNode = _pNewNode;
+ }
+
+ /** quotes a string and search for quotes inside the string and replace them with the new quote
+ @param rValue
+ The value to be quoted.
+ @param rQuote
+ The quote
+ @param rQuoteToReplace
+ The quote to replace with
+ @return
+ The quoted string.
+ */
+ OUString SetQuotation(const OUString& rValue, std::u16string_view rQuote, std::u16string_view rQuoteToReplace)
+ {
+ // Replace quotes with double quotes or the parser gets into problems
+ if (!rQuote.empty())
+ return rQuote + rValue.replaceAll(rQuote, rQuoteToReplace) + rQuote;
+ return rValue;
+ }
+
+ bool columnMatchP(const connectivity::OSQLParseNode* pSubTree, const connectivity::SQLParseNodeParameter& rParam)
+ {
+ using namespace connectivity;
+ assert(SQL_ISRULE(pSubTree,column_ref));
+
+ if(!rParam.xField.is())
+ return false;
+
+ // retrieve the field's name & table range
+ OUString aFieldName;
+ try
+ {
+ sal_Int32 nNamePropertyId = PROPERTY_ID_NAME;
+ if ( rParam.xField->getPropertySetInfo()->hasPropertyByName( OMetaConnection::getPropMap().getNameByIndex( PROPERTY_ID_REALNAME ) ) )
+ nNamePropertyId = PROPERTY_ID_REALNAME;
+ rParam.xField->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex( nNamePropertyId ) ) >>= aFieldName;
+ }
+ catch ( Exception& )
+ {
+ }
+
+ if(!pSubTree->count())
+ return false;
+
+ const OSQLParseNode* pCol = pSubTree->getChild(pSubTree->count()-1);
+ if (SQL_ISRULE(pCol,column_val))
+ {
+ assert(pCol->count() == 1);
+ pCol = pCol->getChild(0);
+ }
+ const OSQLParseNode* pTable(nullptr);
+ switch (pSubTree->count())
+ {
+ case 1:
+ break;
+ case 3:
+ pTable = pSubTree->getChild(0);
+ break;
+ case 5:
+ case 7:
+ SAL_WARN("connectivity.parse", "SQL: catalog and/or schema in column_ref in predicate");
+ break;
+ default:
+ SAL_WARN("connectivity.parse", "columnMatchP: SQL grammar changed; column_ref has " << pSubTree->count() << " children");
+ assert(false);
+ break;
+ }
+ // TODO: not all DBMS match column names case-insensitively...
+ // see XDatabaseMetaData::supportsMixedCaseIdentifiers()
+ // and XDatabaseMetaData::supportsMixedCaseQuotedIdentifiers()
+ if ( // table name matches (or no table name)?
+ ( !pTable || pTable->getTokenValue().equalsIgnoreAsciiCase(rParam.sPredicateTableAlias) )
+ && // column name matches?
+ pCol->getTokenValue().equalsIgnoreAsciiCase(aFieldName)
+ )
+ return true;
+ return false;
+ }
+}
+
+namespace connectivity
+{
+
+SQLParseNodeParameter::SQLParseNodeParameter( const Reference< XConnection >& _rxConnection,
+ const Reference< XNumberFormatter >& _xFormatter, const Reference< XPropertySet >& _xField,
+ OUString _sPredicateTableAlias,
+ const Locale& _rLocale, const IParseContext* _pContext,
+ bool _bIntl, bool _bQuote, OUString _sDecSep, bool _bPredicate, bool _bParseToSDBC )
+ :rLocale(_rLocale)
+ ,aMetaData( _rxConnection )
+ ,pParser( nullptr )
+ ,pSubQueryHistory( std::make_shared<QueryNameSet>() )
+ ,xFormatter(_xFormatter)
+ ,xField(_xField)
+ ,sPredicateTableAlias(std::move(_sPredicateTableAlias))
+ ,m_rContext( _pContext ? *_pContext : OSQLParser::s_aDefaultContext )
+ ,sDecSep(std::move(_sDecSep))
+ ,bQuote(_bQuote)
+ ,bInternational(_bIntl)
+ ,bPredicate(_bPredicate)
+ ,bParseToSDBCLevel( _bParseToSDBC )
+{
+}
+
+OUString OSQLParseNode::convertDateString(const SQLParseNodeParameter& rParam, std::u16string_view rString)
+{
+ Date aDate = DBTypeConversion::toDate(rString);
+ Reference< XNumberFormatsSupplier > xSupplier(rParam.xFormatter->getNumberFormatsSupplier());
+ Reference< XNumberFormatTypes > xTypes(xSupplier->getNumberFormats(), UNO_QUERY);
+
+ double fDate = DBTypeConversion::toDouble(aDate,DBTypeConversion::getNULLDate(xSupplier));
+ sal_Int32 nKey = xTypes->getFormatIndex(NumberFormatIndex::DATE_SYS_DDMMYYYY, rParam.rLocale);
+ return rParam.xFormatter->convertNumberToString(nKey, fDate);
+}
+
+
+OUString OSQLParseNode::convertDateTimeString(const SQLParseNodeParameter& rParam, const OUString& rString)
+{
+ DateTime aDate = DBTypeConversion::toDateTime(rString);
+ Reference< XNumberFormatsSupplier > xSupplier(rParam.xFormatter->getNumberFormatsSupplier());
+ Reference< XNumberFormatTypes > xTypes(xSupplier->getNumberFormats(), UNO_QUERY);
+
+ double fDateTime = DBTypeConversion::toDouble(aDate,DBTypeConversion::getNULLDate(xSupplier));
+ sal_Int32 nKey = xTypes->getFormatIndex(NumberFormatIndex::DATETIME_SYS_DDMMYYYY_HHMMSS, rParam.rLocale);
+ return rParam.xFormatter->convertNumberToString(nKey, fDateTime);
+}
+
+
+OUString OSQLParseNode::convertTimeString(const SQLParseNodeParameter& rParam, std::u16string_view rString)
+{
+ css::util::Time aTime = DBTypeConversion::toTime(rString);
+ Reference< XNumberFormatsSupplier > xSupplier(rParam.xFormatter->getNumberFormatsSupplier());
+
+ Reference< XNumberFormatTypes > xTypes(xSupplier->getNumberFormats(), UNO_QUERY);
+
+ double fTime = DBTypeConversion::toDouble(aTime);
+ sal_Int32 nKey = xTypes->getFormatIndex(NumberFormatIndex::TIME_HHMMSS, rParam.rLocale);
+ return rParam.xFormatter->convertNumberToString(nKey, fTime);
+}
+
+
+void OSQLParseNode::parseNodeToStr(OUString& rString,
+ const Reference< XConnection >& _rxConnection,
+ const IParseContext* pContext,
+ bool _bIntl,
+ bool _bQuote) const
+{
+ parseNodeToStr(
+ rString, _rxConnection, nullptr, nullptr, OUString(),
+ pContext ? pContext->getPreferredLocale() : OParseContext::getDefaultLocale(),
+ pContext, _bIntl, _bQuote, OUString("."), false );
+}
+
+
+void OSQLParseNode::parseNodeToPredicateStr(OUString& rString,
+ const Reference< XConnection >& _rxConnection,
+ const Reference< XNumberFormatter > & xFormatter,
+ const css::lang::Locale& rIntl,
+ const OUString& rDec,
+ const IParseContext* pContext ) const
+{
+ OSL_ENSURE(xFormatter.is(), "OSQLParseNode::parseNodeToPredicateStr:: no formatter!");
+
+ if (xFormatter.is())
+ parseNodeToStr(rString, _rxConnection, xFormatter, nullptr, OUString(), rIntl, pContext, true, true, rDec, true);
+}
+
+
+void OSQLParseNode::parseNodeToPredicateStr(OUString& rString,
+ const Reference< XConnection > & _rxConnection,
+ const Reference< XNumberFormatter > & xFormatter,
+ const Reference< XPropertySet > & _xField,
+ const OUString &_sPredicateTableAlias,
+ const css::lang::Locale& rIntl,
+ const OUString& rDec,
+ const IParseContext* pContext ) const
+{
+ OSL_ENSURE(xFormatter.is(), "OSQLParseNode::parseNodeToPredicateStr:: no formatter!");
+
+ if (xFormatter.is())
+ parseNodeToStr( rString, _rxConnection, xFormatter, _xField, _sPredicateTableAlias, rIntl, pContext, true, true, rDec, true );
+}
+
+
+void OSQLParseNode::parseNodeToStr(OUString& rString,
+ const Reference< XConnection > & _rxConnection,
+ const Reference< XNumberFormatter > & xFormatter,
+ const Reference< XPropertySet > & _xField,
+ const OUString &_sPredicateTableAlias,
+ const css::lang::Locale& rIntl,
+ const IParseContext* pContext,
+ bool _bIntl,
+ bool _bQuote,
+ OUString _sDecSep,
+ bool _bPredicate) const
+{
+ OSL_ENSURE( _rxConnection.is(), "OSQLParseNode::parseNodeToStr: invalid connection!" );
+
+ if ( !_rxConnection.is() )
+ return;
+
+ OUStringBuffer sBuffer(rString);
+ try
+ {
+ OSQLParseNode::impl_parseNodeToString_throw( sBuffer,
+ SQLParseNodeParameter(
+ _rxConnection, xFormatter, _xField, _sPredicateTableAlias, rIntl, pContext,
+ _bIntl, _bQuote, _sDecSep, _bPredicate, false
+ ) );
+ }
+ catch( const SQLException& )
+ {
+ SAL_WARN( "connectivity.parse", "OSQLParseNode::parseNodeToStr: this should not throw!" );
+ // our callers don't expect this method to throw anything. The only known situation
+ // where impl_parseNodeToString_throw can throw is when there is a cyclic reference
+ // in the sub queries, but this cannot be the case here, as we do not parse to
+ // SDBC level.
+ }
+ rString = sBuffer.makeStringAndClear();
+}
+
+bool OSQLParseNode::parseNodeToExecutableStatement( OUString& _out_rString, const Reference< XConnection >& _rxConnection,
+ OSQLParser& _rParser, css::sdbc::SQLException* _pErrorHolder ) const
+{
+ OSL_PRECOND( _rxConnection.is(), "OSQLParseNode::parseNodeToExecutableStatement: invalid connection!" );
+ SQLParseNodeParameter aParseParam( _rxConnection,
+ nullptr, nullptr, OUString(), OParseContext::getDefaultLocale(), nullptr, false, true, OUString("."), false, true );
+
+ if ( aParseParam.aMetaData.supportsSubqueriesInFrom() )
+ {
+ Reference< XQueriesSupplier > xSuppQueries( _rxConnection, UNO_QUERY );
+ OSL_ENSURE( xSuppQueries.is(), "OSQLParseNode::parseNodeToExecutableStatement: cannot substitute everything without a QueriesSupplier!" );
+ if ( xSuppQueries.is() )
+ aParseParam.xQueries = xSuppQueries->getQueries();
+ }
+
+ aParseParam.pParser = &_rParser;
+
+ // LIMIT keyword differs in Firebird
+ OSQLParseNode* pTableExp = getChild(3);
+ Reference< XDatabaseMetaData > xMeta( _rxConnection->getMetaData() );
+ OUString sLimitValue;
+ if( pTableExp->getChild(6)->count() >= 2 && pTableExp->getChild(6)->getChild(1)
+ && (xMeta->getURL().equalsIgnoreAsciiCase("sdbc:embedded:firebird")
+ || xMeta->getURL().startsWithIgnoreAsciiCase("sdbc:firebird:")))
+ {
+ sLimitValue = pTableExp->getChild(6)->getChild(1)->getTokenValue();
+ delete pTableExp->removeAt(6);
+ }
+
+ _out_rString.clear();
+ OUStringBuffer sBuffer;
+ bool bSuccess = false;
+ try
+ {
+ impl_parseNodeToString_throw( sBuffer, aParseParam );
+ bSuccess = true;
+ }
+ catch( const SQLException& e )
+ {
+ if ( _pErrorHolder )
+ *_pErrorHolder = e;
+ }
+
+ if(sLimitValue.getLength() > 0)
+ {
+ constexpr char SELECT_KEYWORD[] = "SELECT";
+ sBuffer.insert(sBuffer.indexOf(SELECT_KEYWORD) + strlen(SELECT_KEYWORD),
+ Concat2View(" FIRST " + sLimitValue));
+ }
+
+ _out_rString = sBuffer.makeStringAndClear();
+ return bSuccess;
+}
+
+
+namespace
+{
+ bool lcl_isAliasNamePresent( const OSQLParseNode& _rTableNameNode )
+ {
+ return !OSQLParseNode::getTableRange(_rTableNameNode.getParent()).isEmpty();
+ }
+}
+
+
+void OSQLParseNode::impl_parseNodeToString_throw(OUStringBuffer& rString, const SQLParseNodeParameter& rParam, bool bSimple) const
+{
+ if ( isToken() )
+ {
+ parseLeaf(rString,rParam);
+ return;
+ }
+
+ // Lets see how many nodes this subtree has
+ sal_uInt32 nCount = count();
+
+ bool bHandled = false;
+ switch ( getKnownRuleID() )
+ {
+ // special handling for parameters
+ case parameter:
+ {
+ bSimple=false;
+ if(!rString.isEmpty())
+ rString.append(" ");
+ if (nCount == 1) // ?
+ m_aChildren[0]->impl_parseNodeToString_throw( rString, rParam, false );
+ else if (rParam.bParseToSDBCLevel && rParam.aMetaData.shouldSubstituteParameterNames())
+ {
+ rString.append("?");
+ }
+ else if (nCount == 2) // :Name
+ {
+ m_aChildren[0]->impl_parseNodeToString_throw( rString, rParam, false );
+ rString.append(m_aChildren[1]->m_aNodeValue);
+ } // [Name]
+ else
+ {
+ assert (nCount == 3);
+ m_aChildren[0]->impl_parseNodeToString_throw( rString, rParam, false );
+ rString.append(m_aChildren[1]->m_aNodeValue);
+ rString.append(m_aChildren[2]->m_aNodeValue);
+ }
+ bHandled = true;
+ }
+ break;
+
+ // table refs
+ case table_ref:
+ bSimple=false;
+ if ( ( nCount == 2 ) || ( nCount == 3 ) || ( nCount == 5 ) )
+ {
+ impl_parseTableRangeNodeToString_throw( rString, rParam );
+ bHandled = true;
+ }
+ break;
+
+ // table name - might be a query name
+ case table_name:
+ bSimple=false;
+ bHandled = impl_parseTableNameNodeToString_throw( rString, rParam );
+ break;
+
+ case as_clause:
+ bSimple=false;
+ assert(nCount == 0 || nCount == 2);
+ if (nCount == 2)
+ {
+ if ( rParam.aMetaData.generateASBeforeCorrelationName() )
+ rString.append(" AS ");
+ m_aChildren[1]->impl_parseNodeToString_throw( rString, rParam, false );
+ }
+ bHandled = true;
+ break;
+
+ case opt_as:
+ assert(nCount == 0);
+ bHandled = true;
+ break;
+
+ case like_predicate:
+ // Depending on whether international is given, LIKE is treated differently
+ // international: *, ? are placeholders
+ // else SQL92 conform: %, _
+ impl_parseLikeNodeToString_throw( rString, rParam, bSimple );
+ bHandled = true;
+ break;
+
+ case general_set_fct:
+ case set_fct_spec:
+ case position_exp:
+ case extract_exp:
+ case length_exp:
+ case char_value_fct:
+ bSimple=false;
+ if (!addDateValue(rString, rParam))
+ {
+ // Do not quote function name
+ SQLParseNodeParameter aNewParam(rParam);
+ aNewParam.bQuote = ( SQL_ISRULE(this,length_exp) || SQL_ISRULE(this,char_value_fct) );
+
+ m_aChildren[0]->impl_parseNodeToString_throw( rString, aNewParam, false );
+ aNewParam.bQuote = rParam.bQuote;
+ //aNewParam.bPredicate = sal_False; // disable [ ] around names // look at i73215
+ OUStringBuffer aStringPara;
+ for (sal_uInt32 i=1; i<nCount; i++)
+ {
+ const OSQLParseNode * pSubTree = m_aChildren[i].get();
+ if (pSubTree)
+ {
+ pSubTree->impl_parseNodeToString_throw( aStringPara, aNewParam, false );
+
+ // In the comma lists, put commas in-between all subtrees
+ if ((m_eNodeType == SQLNodeType::CommaListRule) && (i < (nCount - 1)))
+ aStringPara.append(",");
+ }
+ else
+ i++;
+ }
+ rString.append(aStringPara);
+ }
+ bHandled = true;
+ break;
+ case odbc_call_spec:
+ case subquery:
+ case term:
+ case factor:
+ case window_function:
+ case cast_spec:
+ case num_value_exp:
+ bSimple = false;
+ break;
+ default:
+ break;
+ } // switch ( getKnownRuleID() )
+
+ if ( bHandled )
+ return;
+
+ for (auto i = m_aChildren.begin(); i != m_aChildren.end();)
+ {
+ const OSQLParseNode* pSubTree = i->get();
+ if ( !pSubTree )
+ {
+ ++i;
+ continue;
+ }
+
+ SQLParseNodeParameter aNewParam(rParam);
+
+ // don't replace the field for subqueries
+ if (rParam.xField.is() && SQL_ISRULE(pSubTree,subquery))
+ aNewParam.xField = nullptr;
+
+ // When we are building a criterion inside a query view,
+ // simplify criterion display by removing:
+ // "currentFieldName"
+ // "currentFieldName" =
+ // but only in simple expressions.
+ // This means anything that is made of:
+ // (see the rules conditionalised by inPredicateCheck() in sqlbison.y).
+ // - parentheses
+ // - logical operators (and, or, not)
+ // - comparison operators (IS, =, >, <, BETWEEN, LIKE, ...)
+ // but *not* e.g. in function arguments
+ if (bSimple && rParam.bPredicate && rParam.xField.is() && SQL_ISRULE(pSubTree,column_ref))
+ {
+ if (columnMatchP(pSubTree, rParam))
+ {
+ // skip field
+ ++i;
+ // if the following node is the comparison operator'=',
+ // we filter it as well
+ if (SQL_ISRULE(this, comparison_predicate))
+ {
+ if(i != m_aChildren.end())
+ {
+ pSubTree = i->get();
+ if (pSubTree && pSubTree->getNodeType() == SQLNodeType::Equal)
+ ++i;
+ }
+ }
+ }
+ else
+ {
+ pSubTree->impl_parseNodeToString_throw( rString, aNewParam, bSimple );
+ ++i;
+
+ // In the comma lists, put commas in-between all subtrees
+ if ((m_eNodeType == SQLNodeType::CommaListRule) && (i != m_aChildren.end()))
+ rString.append(",");
+ }
+ }
+ else
+ {
+ pSubTree->impl_parseNodeToString_throw( rString, aNewParam, bSimple );
+ ++i;
+
+ // In the comma lists, put commas in-between all subtrees
+ if ((m_eNodeType == SQLNodeType::CommaListRule) && (i != m_aChildren.end()))
+ {
+ if (SQL_ISRULE(this,value_exp_commalist) && rParam.bPredicate)
+ rString.append(";");
+ else
+ rString.append(",");
+ }
+ }
+ // The right hand-side of these operators is not simple
+ switch ( getKnownRuleID() )
+ {
+ case general_set_fct:
+ case set_fct_spec:
+ case position_exp:
+ case extract_exp:
+ case length_exp:
+ case char_value_fct:
+ case odbc_call_spec:
+ case subquery:
+ case comparison_predicate:
+ case between_predicate:
+ case like_predicate:
+ case test_for_null:
+ case in_predicate:
+ case existence_test:
+ case unique_test:
+ case all_or_any_predicate:
+ case join_condition:
+ case comparison_predicate_part_2:
+ case parenthesized_boolean_value_expression:
+ case other_like_predicate_part_2:
+ case between_predicate_part_2:
+ bSimple=false;
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+
+bool OSQLParseNode::impl_parseTableNameNodeToString_throw( OUStringBuffer& rString, const SQLParseNodeParameter& rParam ) const
+{
+ // is the table_name part of a table_ref?
+ OSL_ENSURE( getParent(), "OSQLParseNode::impl_parseTableNameNodeToString_throw: table_name without parent?" );
+ if ( !getParent() || ( getParent()->getKnownRuleID() != table_ref ) )
+ return false;
+
+ // if it's a query, maybe we need to substitute the SQL statement ...
+ if ( !rParam.bParseToSDBCLevel )
+ return false;
+
+ if ( !rParam.xQueries.is() )
+ // connection does not support queries in queries, or was no query supplier
+ return false;
+
+ try
+ {
+ OUString sTableOrQueryName( getChild(0)->getTokenValue() );
+ bool bIsQuery = rParam.xQueries->hasByName( sTableOrQueryName );
+ if ( !bIsQuery )
+ return false;
+
+ // avoid recursion (e.g. "foo" defined as "SELECT * FROM bar" and "bar" defined as "SELECT * FROM foo".
+ if ( rParam.pSubQueryHistory->find( sTableOrQueryName ) != rParam.pSubQueryHistory->end() )
+ {
+ OSL_ENSURE( rParam.pParser, "OSQLParseNode::impl_parseTableNameNodeToString_throw: no parser?" );
+ if ( rParam.pParser )
+ {
+ const SQLError& rErrors( rParam.pParser->getErrorHelper() );
+ rErrors.raiseException( sdb::ErrorCondition::PARSER_CYCLIC_SUB_QUERIES );
+ }
+ else
+ {
+ SQLError aErrors;
+ aErrors.raiseException( sdb::ErrorCondition::PARSER_CYCLIC_SUB_QUERIES );
+ }
+ }
+ rParam.pSubQueryHistory->insert( sTableOrQueryName );
+
+ Reference< XPropertySet > xQuery( rParam.xQueries->getByName( sTableOrQueryName ), UNO_QUERY_THROW );
+
+ // substitute the query name with the constituting command
+ OUString sCommand;
+ OSL_VERIFY( xQuery->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex( PROPERTY_ID_COMMAND ) ) >>= sCommand );
+
+ bool bEscapeProcessing = false;
+ OSL_VERIFY( xQuery->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex( PROPERTY_ID_ESCAPEPROCESSING ) ) >>= bEscapeProcessing );
+
+ // the query we found here might itself be based on another query, so parse it recursively
+ OSL_ENSURE( rParam.pParser, "OSQLParseNode::impl_parseTableNameNodeToString_throw: cannot analyze sub queries without a parser!" );
+ if ( bEscapeProcessing && rParam.pParser )
+ {
+ OUString sError;
+ std::unique_ptr< OSQLParseNode > pSubQueryNode( rParam.pParser->parseTree( sError, sCommand ) );
+ if (pSubQueryNode)
+ {
+ // parse the sub-select to SDBC level, too
+ OUStringBuffer sSubSelect;
+ pSubQueryNode->impl_parseNodeToString_throw( sSubSelect, rParam, false );
+ if ( !sSubSelect.isEmpty() )
+ sCommand = sSubSelect.makeStringAndClear();
+ }
+ }
+
+ rString.append( " ( " );
+ rString.append(sCommand);
+ rString.append( " )" );
+
+ // append the query name as table alias, since it might be referenced in other
+ // parts of the statement - but only if there's no other alias name present
+ if ( !lcl_isAliasNamePresent( *this ) )
+ {
+ rString.append( " AS " );
+ if ( rParam.bQuote )
+ rString.append(SetQuotation( sTableOrQueryName,
+ rParam.aMetaData.getIdentifierQuoteString(), rParam.aMetaData.getIdentifierQuoteString() ));
+ }
+
+ // don't forget to remove the query name from the history, else multiple inclusions
+ // won't work
+ // #i69227# / 2006-10-10 / frank.schoenheit@sun.com
+ rParam.pSubQueryHistory->erase( sTableOrQueryName );
+
+ return true;
+ }
+ catch( const SQLException& )
+ {
+ throw;
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("connectivity.parse");
+ }
+ return false;
+}
+
+
+void OSQLParseNode::impl_parseTableRangeNodeToString_throw(OUStringBuffer& rString, const SQLParseNodeParameter& rParam) const
+{
+ OSL_PRECOND( ( count() == 2 ) || ( count() == 3 ) || ( count() == 5 ) ,"Illegal count");
+
+ // rString += " ";
+ std::for_each(m_aChildren.begin(),m_aChildren.end(),
+ [&] (std::unique_ptr<OSQLParseNode> const & pNode) { pNode->impl_parseNodeToString_throw(rString, rParam, false); });
+}
+
+
+void OSQLParseNode::impl_parseLikeNodeToString_throw( OUStringBuffer& rString, const SQLParseNodeParameter& rParam, bool bSimple ) const
+{
+ assert(SQL_ISRULE(this,like_predicate));
+ OSL_ENSURE(count() == 2,"count != 2: Prepare for GPF");
+
+ const OSQLParseNode* pEscNode = nullptr;
+ const OSQLParseNode* pParaNode = nullptr;
+
+ SQLParseNodeParameter aNewParam(rParam);
+ //aNewParam.bQuote = sal_True; // why setting this to true? @see https://bz.apache.org/ooo/show_bug.cgi?id=75557
+
+ if ( !(bSimple && rParam.bPredicate && rParam.xField.is() && SQL_ISRULE(m_aChildren[0],column_ref) && columnMatchP(m_aChildren[0].get(), rParam)) )
+ m_aChildren[0]->impl_parseNodeToString_throw( rString, aNewParam, bSimple );
+
+ const OSQLParseNode* pPart2 = m_aChildren[1].get();
+ pPart2->getChild(0)->impl_parseNodeToString_throw( rString, aNewParam, false );
+ pPart2->getChild(1)->impl_parseNodeToString_throw( rString, aNewParam, false );
+ pParaNode = pPart2->getChild(2);
+ pEscNode = pPart2->getChild(3);
+
+ if (pParaNode->isToken())
+ {
+ OUString aStr = ConvertLikeToken(pParaNode, pEscNode, rParam.bInternational);
+ rString.append(" ");
+ rString.append(SetQuotation(aStr, u"\'", u"\'\'"));
+ }
+ else
+ pParaNode->impl_parseNodeToString_throw( rString, aNewParam, false );
+
+ pEscNode->impl_parseNodeToString_throw( rString, aNewParam, false );
+}
+
+
+bool OSQLParseNode::getTableComponents(const OSQLParseNode* _pTableNode,
+ css::uno::Any &_rCatalog,
+ OUString &_rSchema,
+ OUString &_rTable,
+ const Reference< XDatabaseMetaData >& _xMetaData)
+{
+ OSL_ENSURE(_pTableNode,"Wrong use of getTableComponents! _pTableNode is not allowed to be null!");
+ if(_pTableNode)
+ {
+ const bool bSupportsCatalog = _xMetaData.is() && _xMetaData->supportsCatalogsInDataManipulation();
+ const bool bSupportsSchema = _xMetaData.is() && _xMetaData->supportsSchemasInDataManipulation();
+ const OSQLParseNode* pTableNode = _pTableNode;
+ // clear the parameter given
+ _rCatalog = Any();
+ _rSchema.clear();
+ _rTable.clear();
+ // see rule catalog_name: in sqlbison.y
+ if (SQL_ISRULE(pTableNode,catalog_name))
+ {
+ OSL_ENSURE(pTableNode->getChild(0) && pTableNode->getChild(0)->isToken(),"Invalid parsenode!");
+ _rCatalog <<= pTableNode->getChild(0)->getTokenValue();
+ pTableNode = pTableNode->getChild(2);
+ }
+ // check if we have schema_name rule
+ if(SQL_ISRULE(pTableNode,schema_name))
+ {
+ if ( bSupportsCatalog && !bSupportsSchema )
+ _rCatalog <<= pTableNode->getChild(0)->getTokenValue();
+ else
+ _rSchema = pTableNode->getChild(0)->getTokenValue();
+ pTableNode = pTableNode->getChild(2);
+ }
+ // check if we have table_name rule
+ if(SQL_ISRULE(pTableNode,table_name))
+ {
+ _rTable = pTableNode->getChild(0)->getTokenValue();
+ }
+ else
+ {
+ SAL_WARN( "connectivity.parse","Error in parse tree!");
+ }
+ }
+ return !_rTable.isEmpty();
+}
+
+void OSQLParser::killThousandSeparator(OSQLParseNode* pLiteral)
+{
+ if ( pLiteral )
+ {
+ if ( s_xLocaleData.get()->get()->getLocaleItem( m_pData->aLocale ).decimalSeparator.toChar() == ',' )
+ {
+ pLiteral->m_aNodeValue = pLiteral->m_aNodeValue.replace('.', sal_Unicode());
+ // and replace decimal
+ pLiteral->m_aNodeValue = pLiteral->m_aNodeValue.replace(',', '.');
+ }
+ else
+ pLiteral->m_aNodeValue = pLiteral->m_aNodeValue.replace(',', sal_Unicode());
+ }
+}
+
+OSQLParseNode* OSQLParser::convertNode(sal_Int32 nType, OSQLParseNode* pLiteral)
+{
+ if ( !pLiteral )
+ return nullptr;
+
+ OSQLParseNode* pReturn = pLiteral;
+
+ if ( ( pLiteral->isRule() && !SQL_ISRULE(pLiteral,value_exp) ) || SQL_ISTOKEN(pLiteral,FALSE) || SQL_ISTOKEN(pLiteral,TRUE) )
+ {
+ switch(nType)
+ {
+ case DataType::CHAR:
+ case DataType::VARCHAR:
+ case DataType::LONGVARCHAR:
+ case DataType::CLOB:
+ if ( !SQL_ISRULE(pReturn,char_value_exp) && !buildStringNodes(pReturn) )
+ pReturn = nullptr;
+ break;
+ default:
+ break;
+ }
+ }
+ else
+ {
+ switch(pLiteral->getNodeType())
+ {
+ case SQLNodeType::String:
+ switch(nType)
+ {
+ case DataType::CHAR:
+ case DataType::VARCHAR:
+ case DataType::LONGVARCHAR:
+ case DataType::CLOB:
+ break;
+ case DataType::DATE:
+ case DataType::TIME:
+ case DataType::TIMESTAMP:
+ if (m_xFormatter.is())
+ pReturn = buildDate( nType, pReturn);
+ break;
+ default:
+ m_sErrorMessage = m_pContext->getErrorMessage(IParseContext::ErrorCode::InvalidCompare);
+ break;
+ }
+ break;
+ case SQLNodeType::AccessDate:
+ switch(nType)
+ {
+ case DataType::DATE:
+ case DataType::TIME:
+ case DataType::TIMESTAMP:
+ if ( m_xFormatter.is() )
+ pReturn = buildDate( nType, pReturn);
+ else
+ m_sErrorMessage = m_pContext->getErrorMessage(IParseContext::ErrorCode::InvalidDateCompare);
+ break;
+ default:
+ m_sErrorMessage = m_pContext->getErrorMessage(IParseContext::ErrorCode::InvalidCompare);
+ break;
+ }
+ break;
+ case SQLNodeType::IntNum:
+ switch(nType)
+ {
+ case DataType::BIT:
+ case DataType::BOOLEAN:
+ case DataType::DECIMAL:
+ case DataType::NUMERIC:
+ case DataType::TINYINT:
+ case DataType::SMALLINT:
+ case DataType::INTEGER:
+ case DataType::BIGINT:
+ case DataType::FLOAT:
+ case DataType::REAL:
+ case DataType::DOUBLE:
+ // kill thousand separators if any
+ killThousandSeparator(pReturn);
+ break;
+ case DataType::CHAR:
+ case DataType::VARCHAR:
+ case DataType::LONGVARCHAR:
+ case DataType::CLOB:
+ pReturn = buildNode_STR_NUM(pReturn);
+ break;
+ default:
+ m_sErrorMessage = m_pContext->getErrorMessage(IParseContext::ErrorCode::InvalidIntCompare);
+ break;
+ }
+ break;
+ case SQLNodeType::ApproxNum:
+ switch(nType)
+ {
+ case DataType::DECIMAL:
+ case DataType::NUMERIC:
+ case DataType::FLOAT:
+ case DataType::REAL:
+ case DataType::DOUBLE:
+ // kill thousand separators if any
+ killThousandSeparator(pReturn);
+ break;
+ case DataType::CHAR:
+ case DataType::VARCHAR:
+ case DataType::LONGVARCHAR:
+ case DataType::CLOB:
+ pReturn = buildNode_STR_NUM(pReturn);
+ break;
+ case DataType::INTEGER:
+ default:
+ m_sErrorMessage = m_pContext->getErrorMessage(IParseContext::ErrorCode::InvalidRealCompare);
+ break;
+ }
+ break;
+ default:
+ ;
+ }
+ }
+ return pReturn;
+}
+
+sal_Int16 OSQLParser::buildPredicateRule(OSQLParseNode*& pAppend, OSQLParseNode* pLiteral, OSQLParseNode* pCompare, OSQLParseNode* pLiteral2)
+{
+ OSL_ENSURE(inPredicateCheck(),"Only in predicate check allowed!");
+ sal_Int16 nErg = 0;
+ if ( m_xField.is() )
+ {
+ sal_Int32 nType = 0;
+ try
+ {
+ m_xField->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE)) >>= nType;
+ }
+ catch( Exception& )
+ {
+ return nErg;
+ }
+
+ OSQLParseNode* pNode1 = convertNode(nType,pLiteral);
+ if ( pNode1 )
+ {
+ OSQLParseNode* pNode2 = convertNode(nType,pLiteral2);
+ if ( m_sErrorMessage.isEmpty() )
+ nErg = buildNode(pAppend,pCompare,pNode1,pNode2);
+ }
+ }
+ if (!pCompare->getParent()) // I have no parent so I was not used and I must die :-)
+ delete pCompare;
+ return nErg;
+}
+
+sal_Int16 OSQLParser::buildLikeRule(OSQLParseNode* pAppend, OSQLParseNode*& pLiteral, const OSQLParseNode* pEscape)
+{
+ sal_Int16 nErg = 0;
+ sal_Int32 nType = 0;
+
+ if (!m_xField.is())
+ return nErg;
+ try
+ {
+ Any aValue;
+ {
+ aValue = m_xField->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE));
+ aValue >>= nType;
+ }
+ }
+ catch( Exception& )
+ {
+ return nErg;
+ }
+
+ switch (nType)
+ {
+ case DataType::CHAR:
+ case DataType::VARCHAR:
+ case DataType::LONGVARCHAR:
+ case DataType::CLOB:
+ if(pLiteral->isRule())
+ {
+ pAppend->append(pLiteral);
+ nErg = 1;
+ }
+ else
+ {
+ switch(pLiteral->getNodeType())
+ {
+ case SQLNodeType::String:
+ pLiteral->m_aNodeValue = ConvertLikeToken(pLiteral, pEscape, false);
+ pAppend->append(pLiteral);
+ nErg = 1;
+ break;
+ case SQLNodeType::ApproxNum:
+ if (m_xFormatter.is() && m_nFormatKey)
+ {
+ sal_Int16 nScale = 0;
+ try
+ {
+ Any aValue = getNumberFormatProperty( m_xFormatter, m_nFormatKey, "Decimals" );
+ aValue >>= nScale;
+ }
+ catch( Exception& )
+ {
+ }
+
+ pAppend->append(new OSQLInternalNode(stringToDouble(pLiteral->getTokenValue(),nScale),SQLNodeType::String));
+ }
+ else
+ pAppend->append(new OSQLInternalNode(pLiteral->getTokenValue(),SQLNodeType::String));
+
+ delete pLiteral;
+ nErg = 1;
+ break;
+ default:
+ m_sErrorMessage = m_pContext->getErrorMessage(IParseContext::ErrorCode::ValueNoLike);
+ m_sErrorMessage = m_sErrorMessage.replaceAt(m_sErrorMessage.indexOf("#1"),2,pLiteral->getTokenValue());
+ break;
+ }
+ }
+ break;
+ default:
+ m_sErrorMessage = m_pContext->getErrorMessage(IParseContext::ErrorCode::FieldNoLike);
+ break;
+ }
+ return nErg;
+}
+
+OSQLParseNode* OSQLParser::buildNode_Date(const double& fValue, sal_Int32 nType)
+{
+ OSQLParseNode* pNewNode = new OSQLInternalNode("", SQLNodeType::Rule,OSQLParser::RuleID(OSQLParseNode::set_fct_spec));
+ pNewNode->append(new OSQLInternalNode("{", SQLNodeType::Punctuation));
+ OSQLParseNode* pDateNode = new OSQLInternalNode("", SQLNodeType::Rule,OSQLParser::RuleID(OSQLParseNode::odbc_fct_spec));
+ pNewNode->append(pDateNode);
+ pNewNode->append(new OSQLInternalNode("}", SQLNodeType::Punctuation));
+
+ switch (nType)
+ {
+ case DataType::DATE:
+ {
+ Date aDate = DBTypeConversion::toDate(fValue,DBTypeConversion::getNULLDate(m_xFormatter->getNumberFormatsSupplier()));
+ OUString aString = DBTypeConversion::toDateString(aDate);
+ pDateNode->append(new OSQLInternalNode("", SQLNodeType::Keyword, SQL_TOKEN_D));
+ pDateNode->append(new OSQLInternalNode(aString, SQLNodeType::String));
+ break;
+ }
+ case DataType::TIME:
+ {
+ css::util::Time aTime = DBTypeConversion::toTime(fValue);
+ OUString aString = DBTypeConversion::toTimeString(aTime);
+ pDateNode->append(new OSQLInternalNode("", SQLNodeType::Keyword, SQL_TOKEN_T));
+ pDateNode->append(new OSQLInternalNode(aString, SQLNodeType::String));
+ break;
+ }
+ case DataType::TIMESTAMP:
+ {
+ DateTime aDateTime = DBTypeConversion::toDateTime(fValue,DBTypeConversion::getNULLDate(m_xFormatter->getNumberFormatsSupplier()));
+ if (aDateTime.Seconds || aDateTime.Minutes || aDateTime.Hours)
+ {
+ OUString aString = DBTypeConversion::toDateTimeString(aDateTime);
+ pDateNode->append(new OSQLInternalNode("", SQLNodeType::Keyword, SQL_TOKEN_TS));
+ pDateNode->append(new OSQLInternalNode(aString, SQLNodeType::String));
+ }
+ else
+ {
+ Date aDate(aDateTime.Day,aDateTime.Month,aDateTime.Year);
+ pDateNode->append(new OSQLInternalNode("", SQLNodeType::Keyword, SQL_TOKEN_D));
+ pDateNode->append(new OSQLInternalNode(DBTypeConversion::toDateString(aDate), SQLNodeType::String));
+ }
+ break;
+ }
+ }
+
+ return pNewNode;
+}
+
+OSQLParseNode* OSQLParser::buildNode_STR_NUM(OSQLParseNode*& _pLiteral)
+{
+ OSQLParseNode* pReturn = nullptr;
+ if ( _pLiteral )
+ {
+ if (m_nFormatKey)
+ {
+ sal_Int16 nScale = 0;
+ try
+ {
+ Any aValue = getNumberFormatProperty( m_xFormatter, m_nFormatKey, "Decimals" );
+ aValue >>= nScale;
+ }
+ catch( Exception& )
+ {
+ }
+
+ pReturn = new OSQLInternalNode(stringToDouble(_pLiteral->getTokenValue(),nScale),SQLNodeType::String);
+ }
+ else
+ pReturn = new OSQLInternalNode(_pLiteral->getTokenValue(),SQLNodeType::String);
+
+ delete _pLiteral;
+ _pLiteral = nullptr;
+ }
+ return pReturn;
+}
+
+OUString OSQLParser::stringToDouble(const OUString& _rValue,sal_Int16 _nScale)
+{
+ OUString aValue;
+ if(!m_xCharClass.is())
+ m_xCharClass = CharacterClassification::create( m_xContext );
+ if( s_xLocaleData.get() )
+ {
+ try
+ {
+ ParseResult aResult = m_xCharClass->parsePredefinedToken(KParseType::ANY_NUMBER,_rValue,0,m_pData->aLocale,0,OUString(),KParseType::ANY_NUMBER,OUString());
+ if((aResult.TokenType & KParseType::IDENTNAME) && aResult.EndPos == _rValue.getLength())
+ {
+ aValue = OUString::number(aResult.Value);
+ sal_Int32 nPos = aValue.lastIndexOf('.');
+ if((nPos+_nScale) < aValue.getLength())
+ aValue = aValue.replaceAt(nPos+_nScale,aValue.getLength()-nPos-_nScale, u"");
+ OUString sDecimalSeparator = s_xLocaleData.get()->get()->getLocaleItem(m_pData->aLocale).decimalSeparator;
+ aValue = aValue.replaceAt(aValue.lastIndexOf('.'), 1, sDecimalSeparator);
+ return aValue;
+ }
+ }
+ catch(Exception&)
+ {
+ }
+ }
+ return aValue;
+}
+
+
+std::mutex& OSQLParser::getMutex()
+{
+ static std::mutex aMutex;
+ return aMutex;
+}
+
+
+std::unique_ptr<OSQLParseNode> OSQLParser::predicateTree(OUString& rErrorMessage, const OUString& rStatement,
+ const Reference< css::util::XNumberFormatter > & xFormatter,
+ const Reference< XPropertySet > & xField,
+ bool bUseRealName)
+{
+ // Guard the parsing
+ std::unique_lock aGuard(getMutex());
+ // must be reset
+ setParser(this);
+
+
+ // reset the parser
+ m_xField = xField;
+ m_xFormatter = xFormatter;
+
+ if (m_xField.is())
+ {
+ sal_Int32 nType=0;
+ try
+ {
+ // get the field name
+ OUString aString;
+
+ // retrieve the fields name
+ // #75243# use the RealName of the column if there is any otherwise the name which could be the alias
+ // of the field
+ Reference< XPropertySetInfo> xInfo = m_xField->getPropertySetInfo();
+ if ( bUseRealName && xInfo->hasPropertyByName(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_REALNAME)))
+ m_xField->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_REALNAME)) >>= aString;
+ else
+ m_xField->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME)) >>= aString;
+
+ m_sFieldName = aString;
+
+ // get the field format key
+ if ( xInfo->hasPropertyByName(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FORMATKEY)))
+ m_xField->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FORMATKEY)) >>= m_nFormatKey;
+ else
+ m_nFormatKey = 0;
+
+ // get the field type
+ m_xField->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE)) >>= nType;
+ }
+ catch ( Exception& )
+ {
+ OSL_ASSERT(false);
+ }
+
+ if (m_nFormatKey && m_xFormatter.is())
+ {
+ Any aValue = getNumberFormatProperty( m_xFormatter, m_nFormatKey, OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_LOCALE) );
+ OSL_ENSURE(aValue.getValueType() == cppu::UnoType<css::lang::Locale>::get(), "OSQLParser::PredicateTree : invalid language property !");
+
+ if (aValue.getValueType() == cppu::UnoType<css::lang::Locale>::get())
+ aValue >>= m_pData->aLocale;
+ }
+ else
+ m_pData->aLocale = m_pContext->getPreferredLocale();
+
+ if ( m_xFormatter.is() )
+ {
+ try
+ {
+ Reference< css::util::XNumberFormatsSupplier > xFormatSup = m_xFormatter->getNumberFormatsSupplier();
+ if ( xFormatSup.is() )
+ {
+ Reference< css::util::XNumberFormats > xFormats = xFormatSup->getNumberFormats();
+ if ( xFormats.is() )
+ {
+ css::lang::Locale aLocale;
+ aLocale.Language = "en";
+ aLocale.Country = "US";
+ OUString sFormat("YYYY-MM-DD");
+ m_nDateFormatKey = xFormats->queryKey(sFormat,aLocale,false);
+ if ( m_nDateFormatKey == sal_Int32(-1) )
+ m_nDateFormatKey = xFormats->addNew(sFormat, aLocale);
+ }
+ }
+ }
+ catch ( Exception& )
+ {
+ SAL_WARN( "connectivity.parse","DateFormatKey");
+ }
+ }
+
+ switch (nType)
+ {
+ case DataType::DATE:
+ case DataType::TIME:
+ case DataType::TIMESTAMP:
+ s_pScanner->SetRule(OSQLScanner::GetDATERule());
+ break;
+ case DataType::CHAR:
+ case DataType::VARCHAR:
+ case DataType::LONGVARCHAR:
+ case DataType::CLOB:
+ s_pScanner->SetRule(OSQLScanner::GetSTRINGRule());
+ break;
+ default:
+ if ( s_xLocaleData.get()->get()->getLocaleItem( m_pData->aLocale ).decimalSeparator.toChar() == ',' )
+ s_pScanner->SetRule(OSQLScanner::GetGERRule());
+ else
+ s_pScanner->SetRule(OSQLScanner::GetENGRule());
+ }
+
+ }
+ else
+ s_pScanner->SetRule(OSQLScanner::GetSQLRule());
+
+ s_pScanner->prepareScan(rStatement, m_pContext, true);
+
+ SQLyylval.pParseNode = nullptr;
+ // SQLyypvt = NULL;
+ m_pParseTree = nullptr;
+ m_sErrorMessage.clear();
+
+ // Start the parser
+ if (SQLyyparse() != 0)
+ {
+ m_sFieldName.clear();
+ m_xField.clear();
+ m_xFormatter.clear();
+ m_nFormatKey = 0;
+ m_nDateFormatKey = 0;
+
+ if (m_sErrorMessage.isEmpty())
+ m_sErrorMessage = s_pScanner->getErrorMessage();
+ if (m_sErrorMessage.isEmpty())
+ m_sErrorMessage = m_pContext->getErrorMessage(IParseContext::ErrorCode::General);
+
+ rErrorMessage = m_sErrorMessage;
+
+ // clear the garbage collector
+ (*s_pGarbageCollector)->clearAndDelete();
+ // coverity[leaked_storage : FALSE] - because the garbage collector deleted it
+ m_pParseTree.release();
+ return nullptr;
+ }
+ else
+ {
+ (*s_pGarbageCollector)->clear();
+
+ m_sFieldName.clear();
+ m_xField.clear();
+ m_xFormatter.clear();
+ m_nFormatKey = 0;
+ m_nDateFormatKey = 0;
+
+ // Return the result (the root parse node):
+
+ // Instead, the parse method sets the member pParseTree and simply returns that
+ OSL_ENSURE(m_pParseTree != nullptr,"OSQLParser: Parser did not return a ParseTree!");
+ return std::move(m_pParseTree);
+ }
+}
+
+
+OSQLParser::OSQLParser(css::uno::Reference< css::uno::XComponentContext > xContext,
+ const IParseContext* _pContext,
+ const IParseContext* _pNeutral)
+ :m_pContext(_pContext)
+ ,m_pNeutral(_pNeutral)
+ ,m_pData( new OSQLParser_Data )
+ ,m_nFormatKey(0)
+ ,m_nDateFormatKey(0)
+ ,m_xContext(std::move(xContext))
+{
+
+
+ setParser(this);
+
+#ifdef SQLYYDEBUG
+#ifdef SQLYYDEBUG_ON
+ SQLyydebug = 1;
+#endif
+#endif
+
+ std::unique_lock aGuard(getMutex());
+ // Do we have to initialize the data?
+ if (s_nRefCount == 0)
+ {
+ s_pScanner = new OSQLScanner();
+ s_pScanner->setScanner();
+ s_pGarbageCollector = new OSQLParseNodesGarbageCollector();
+
+ if(!s_xLocaleData.get())
+ s_xLocaleData.set(LocaleData::create(m_xContext));
+
+ // reset to UNKNOWN_RULE
+ static_assert(OSQLParseNode::UNKNOWN_RULE==0, "UNKNOWN_RULE must be 0 for memset to 0 to work");
+ memset(OSQLParser::s_nRuleIDs,0,sizeof(OSQLParser::s_nRuleIDs));
+
+ const struct
+ {
+ OSQLParseNode::Rule eRule; // the parse node's ID for the rule
+ OString sRuleName; // the name of the rule ("select_statement")
+ } aRuleDescriptions[] =
+ {
+ { OSQLParseNode::select_statement, "select_statement"_ostr },
+ { OSQLParseNode::table_exp, "table_exp"_ostr },
+ { OSQLParseNode::table_ref_commalist, "table_ref_commalist"_ostr },
+ { OSQLParseNode::table_ref, "table_ref"_ostr },
+ { OSQLParseNode::catalog_name, "catalog_name"_ostr },
+ { OSQLParseNode::schema_name, "schema_name"_ostr },
+ { OSQLParseNode::table_name, "table_name"_ostr },
+ { OSQLParseNode::opt_column_commalist, "opt_column_commalist"_ostr },
+ { OSQLParseNode::column_commalist, "column_commalist"_ostr },
+ { OSQLParseNode::column_ref_commalist, "column_ref_commalist"_ostr },
+ { OSQLParseNode::column_ref, "column_ref"_ostr },
+ { OSQLParseNode::opt_order_by_clause, "opt_order_by_clause"_ostr },
+ { OSQLParseNode::ordering_spec_commalist, "ordering_spec_commalist"_ostr },
+ { OSQLParseNode::ordering_spec, "ordering_spec"_ostr },
+ { OSQLParseNode::opt_asc_desc, "opt_asc_desc"_ostr },
+ { OSQLParseNode::where_clause, "where_clause"_ostr },
+ { OSQLParseNode::opt_where_clause, "opt_where_clause"_ostr },
+ { OSQLParseNode::search_condition, "search_condition"_ostr },
+ { OSQLParseNode::comparison, "comparison"_ostr },
+ { OSQLParseNode::comparison_predicate, "comparison_predicate"_ostr },
+ { OSQLParseNode::between_predicate, "between_predicate"_ostr },
+ { OSQLParseNode::like_predicate, "like_predicate"_ostr },
+ { OSQLParseNode::opt_escape, "opt_escape"_ostr },
+ { OSQLParseNode::test_for_null, "test_for_null"_ostr },
+ { OSQLParseNode::scalar_exp_commalist, "scalar_exp_commalist"_ostr },
+ { OSQLParseNode::scalar_exp, "scalar_exp"_ostr },
+ { OSQLParseNode::parameter_ref, "parameter_ref"_ostr },
+ { OSQLParseNode::parameter, "parameter"_ostr },
+ { OSQLParseNode::general_set_fct, "general_set_fct"_ostr },
+ { OSQLParseNode::range_variable, "range_variable"_ostr },
+ { OSQLParseNode::column, "column"_ostr },
+ { OSQLParseNode::delete_statement_positioned, "delete_statement_positioned"_ostr },
+ { OSQLParseNode::delete_statement_searched, "delete_statement_searched"_ostr },
+ { OSQLParseNode::update_statement_positioned, "update_statement_positioned"_ostr },
+ { OSQLParseNode::update_statement_searched, "update_statement_searched"_ostr },
+ { OSQLParseNode::assignment_commalist, "assignment_commalist"_ostr },
+ { OSQLParseNode::assignment, "assignment"_ostr },
+ { OSQLParseNode::values_or_query_spec, "values_or_query_spec"_ostr },
+ { OSQLParseNode::insert_statement, "insert_statement"_ostr },
+ { OSQLParseNode::insert_atom_commalist, "insert_atom_commalist"_ostr },
+ { OSQLParseNode::insert_atom, "insert_atom"_ostr },
+ { OSQLParseNode::from_clause, "from_clause"_ostr },
+ { OSQLParseNode::qualified_join, "qualified_join"_ostr },
+ { OSQLParseNode::cross_union, "cross_union"_ostr },
+ { OSQLParseNode::select_sublist, "select_sublist"_ostr },
+ { OSQLParseNode::derived_column, "derived_column"_ostr },
+ { OSQLParseNode::column_val, "column_val"_ostr },
+ { OSQLParseNode::set_fct_spec, "set_fct_spec"_ostr },
+ { OSQLParseNode::boolean_term, "boolean_term"_ostr },
+ { OSQLParseNode::boolean_primary, "boolean_primary"_ostr },
+ { OSQLParseNode::num_value_exp, "num_value_exp"_ostr },
+ { OSQLParseNode::join_type, "join_type"_ostr },
+ { OSQLParseNode::position_exp, "position_exp"_ostr },
+ { OSQLParseNode::extract_exp, "extract_exp"_ostr },
+ { OSQLParseNode::length_exp, "length_exp"_ostr },
+ { OSQLParseNode::char_value_fct, "char_value_fct"_ostr },
+ { OSQLParseNode::odbc_call_spec, "odbc_call_spec"_ostr },
+ { OSQLParseNode::in_predicate, "in_predicate"_ostr },
+ { OSQLParseNode::existence_test, "existence_test"_ostr },
+ { OSQLParseNode::unique_test, "unique_test"_ostr },
+ { OSQLParseNode::all_or_any_predicate, "all_or_any_predicate"_ostr },
+ { OSQLParseNode::named_columns_join, "named_columns_join"_ostr },
+ { OSQLParseNode::join_condition, "join_condition"_ostr },
+ { OSQLParseNode::joined_table, "joined_table"_ostr },
+ { OSQLParseNode::boolean_factor, "boolean_factor"_ostr },
+ { OSQLParseNode::sql_not, "sql_not"_ostr },
+ { OSQLParseNode::manipulative_statement, "manipulative_statement"_ostr },
+ { OSQLParseNode::subquery, "subquery"_ostr },
+ { OSQLParseNode::value_exp_commalist, "value_exp_commalist"_ostr },
+ { OSQLParseNode::odbc_fct_spec, "odbc_fct_spec"_ostr },
+ { OSQLParseNode::union_statement, "union_statement"_ostr },
+ { OSQLParseNode::outer_join_type, "outer_join_type"_ostr },
+ { OSQLParseNode::char_value_exp, "char_value_exp"_ostr },
+ { OSQLParseNode::term, "term"_ostr },
+ { OSQLParseNode::value_exp_primary, "value_exp_primary"_ostr },
+ { OSQLParseNode::value_exp, "value_exp"_ostr },
+ { OSQLParseNode::selection, "selection"_ostr },
+ { OSQLParseNode::fold, "fold"_ostr },
+ { OSQLParseNode::char_substring_fct, "char_substring_fct"_ostr },
+ { OSQLParseNode::factor, "factor"_ostr },
+ { OSQLParseNode::base_table_def, "base_table_def"_ostr },
+ { OSQLParseNode::base_table_element_commalist, "base_table_element_commalist"_ostr },
+ { OSQLParseNode::data_type, "data_type"_ostr },
+ { OSQLParseNode::column_def, "column_def"_ostr },
+ { OSQLParseNode::table_node, "table_node"_ostr },
+ { OSQLParseNode::as_clause, "as_clause"_ostr },
+ { OSQLParseNode::opt_as, "opt_as"_ostr },
+ { OSQLParseNode::op_column_commalist, "op_column_commalist"_ostr },
+ { OSQLParseNode::table_primary_as_range_column, "table_primary_as_range_column"_ostr },
+ { OSQLParseNode::datetime_primary, "datetime_primary"_ostr },
+ { OSQLParseNode::concatenation, "concatenation"_ostr },
+ { OSQLParseNode::char_factor, "char_factor"_ostr },
+ { OSQLParseNode::bit_value_fct, "bit_value_fct"_ostr },
+ { OSQLParseNode::comparison_predicate_part_2, "comparison_predicate_part_2"_ostr },
+ { OSQLParseNode::parenthesized_boolean_value_expression, "parenthesized_boolean_value_expression"_ostr },
+ { OSQLParseNode::character_string_type, "character_string_type"_ostr },
+ { OSQLParseNode::other_like_predicate_part_2, "other_like_predicate_part_2"_ostr },
+ { OSQLParseNode::between_predicate_part_2, "between_predicate_part_2"_ostr },
+ { OSQLParseNode::null_predicate_part_2, "null_predicate_part_2"_ostr },
+ { OSQLParseNode::cast_spec, "cast_spec"_ostr },
+ { OSQLParseNode::window_function, "window_function"_ostr }
+ };
+ const size_t nRuleMapCount = std::size( aRuleDescriptions );
+ // added a new rule? Adjust this map!
+ // +1 for UNKNOWN_RULE
+ static_assert(nRuleMapCount + 1 == static_cast<size_t>(OSQLParseNode::rule_count), "must be equal");
+
+ for (const auto & aRuleDescription : aRuleDescriptions)
+ {
+ // look up the rule description in the our identifier map
+ sal_uInt32 nParserRuleID = StrToRuleID( aRuleDescription.sRuleName );
+ // map the parser's rule ID to the OSQLParseNode::Rule
+ s_aReverseRuleIDLookup[ nParserRuleID ] = aRuleDescription.eRule;
+ // and map the OSQLParseNode::Rule to the parser's rule ID
+ s_nRuleIDs[ aRuleDescription.eRule ] = nParserRuleID;
+ }
+ }
+ ++s_nRefCount;
+
+ if (m_pContext == nullptr)
+ // take the default context
+ m_pContext = &s_aDefaultContext;
+
+ m_pData->aLocale = m_pContext->getPreferredLocale();
+}
+
+
+OSQLParser::~OSQLParser()
+{
+ std::unique_lock aGuard(getMutex());
+ OSL_ENSURE(s_nRefCount > 0, "OSQLParser::~OSQLParser() : suspicious call : has a refcount of 0 !");
+ if (!--s_nRefCount)
+ {
+ s_pScanner->setScanner(true);
+ delete s_pScanner;
+ s_pScanner = nullptr;
+
+ delete s_pGarbageCollector;
+ s_pGarbageCollector = nullptr;
+
+ RuleIDMap().swap(s_aReverseRuleIDLookup);
+ }
+ m_pParseTree = nullptr;
+}
+
+void OSQLParseNode::substituteParameterNames(OSQLParseNode const * _pNode)
+{
+ sal_Int32 nCount = _pNode->count();
+ for(sal_Int32 i=0;i < nCount;++i)
+ {
+ OSQLParseNode* pChildNode = _pNode->getChild(i);
+ if(SQL_ISRULE(pChildNode,parameter) && pChildNode->count() > 1)
+ {
+ OSQLParseNode* pNewNode = new OSQLParseNode("?" ,SQLNodeType::Punctuation,0);
+ pChildNode->replaceAndDelete(pChildNode->getChild(0), pNewNode);
+ sal_Int32 nChildCount = pChildNode->count();
+ for(sal_Int32 j=1;j < nChildCount;++j)
+ delete pChildNode->removeAt(1);
+ }
+ else
+ substituteParameterNames(pChildNode);
+
+ }
+}
+
+bool OSQLParser::extractDate(OSQLParseNode const * pLiteral,double& _rfValue)
+{
+ Reference< XNumberFormatsSupplier > xFormatSup = m_xFormatter->getNumberFormatsSupplier();
+ Reference< XNumberFormatTypes > xFormatTypes;
+ if ( xFormatSup.is() )
+ xFormatTypes.set(xFormatSup->getNumberFormats(), css::uno::UNO_QUERY);
+
+ // if there is no format key, yet, make sure we have a feasible one for our locale
+ try
+ {
+ if ( !m_nFormatKey && xFormatTypes.is() )
+ m_nFormatKey = ::dbtools::getDefaultNumberFormat( m_xField, xFormatTypes, m_pData->aLocale );
+ }
+ catch( Exception& ) { }
+ const OUString& sValue = pLiteral->getTokenValue();
+ sal_Int32 nTryFormat = m_nFormatKey;
+ bool bSuccess = lcl_saveConvertToNumber( m_xFormatter, nTryFormat, sValue, _rfValue );
+
+ // If our format key didn't do, try the default date format for our locale.
+ if ( !bSuccess && xFormatTypes.is() )
+ {
+ try
+ {
+ nTryFormat = xFormatTypes->getStandardFormat( NumberFormat::DATE, m_pData->aLocale );
+ }
+ catch( Exception& ) { }
+ bSuccess = lcl_saveConvertToNumber( m_xFormatter, nTryFormat, sValue, _rfValue );
+ }
+
+ // if this also didn't do, try ISO format
+ if ( !bSuccess && xFormatTypes.is() )
+ {
+ try
+ {
+ nTryFormat = xFormatTypes->getFormatIndex( NumberFormatIndex::DATE_DIN_YYYYMMDD, m_pData->aLocale );
+ }
+ catch( Exception& ) { }
+ bSuccess = lcl_saveConvertToNumber( m_xFormatter, nTryFormat, sValue, _rfValue );
+ }
+
+ // if this also didn't do, try fallback date format (en-US)
+ if ( !bSuccess )
+ {
+ nTryFormat = m_nDateFormatKey;
+ bSuccess = lcl_saveConvertToNumber( m_xFormatter, nTryFormat, sValue, _rfValue );
+ }
+ return bSuccess;
+}
+
+OSQLParseNode* OSQLParser::buildDate(sal_Int32 _nType,OSQLParseNode*& pLiteral)
+{
+ // try converting the string into a date, according to our format key
+ double fValue = 0.0;
+ OSQLParseNode* pFCTNode = nullptr;
+
+ if ( extractDate(pLiteral,fValue) )
+ pFCTNode = buildNode_Date( fValue, _nType);
+
+ delete pLiteral;
+ pLiteral = nullptr;
+
+ if ( !pFCTNode )
+ m_sErrorMessage = m_pContext->getErrorMessage(IParseContext::ErrorCode::InvalidDateCompare);
+
+ return pFCTNode;
+}
+
+
+OSQLParseNode::OSQLParseNode(const char * pNewValue,
+ SQLNodeType eNewNodeType,
+ sal_uInt32 nNewNodeID)
+ :m_pParent(nullptr)
+ ,m_aNodeValue(pNewValue,strlen(pNewValue),RTL_TEXTENCODING_UTF8)
+ ,m_eNodeType(eNewNodeType)
+ ,m_nNodeID(nNewNodeID)
+{
+ OSL_ENSURE(m_eNodeType >= SQLNodeType::Rule && m_eNodeType <= SQLNodeType::Concat,"OSQLParseNode: created with invalid NodeType");
+}
+
+OSQLParseNode::OSQLParseNode(std::string_view _rNewValue,
+ SQLNodeType eNewNodeType,
+ sal_uInt32 nNewNodeID)
+ :m_pParent(nullptr)
+ ,m_aNodeValue(OStringToOUString(_rNewValue,RTL_TEXTENCODING_UTF8))
+ ,m_eNodeType(eNewNodeType)
+ ,m_nNodeID(nNewNodeID)
+{
+ OSL_ENSURE(m_eNodeType >= SQLNodeType::Rule && m_eNodeType <= SQLNodeType::Concat,"OSQLParseNode: created with invalid NodeType");
+}
+
+OSQLParseNode::OSQLParseNode(OUString _aNewValue,
+ SQLNodeType eNewNodeType,
+ sal_uInt32 nNewNodeID)
+ :m_pParent(nullptr)
+ ,m_aNodeValue(std::move(_aNewValue))
+ ,m_eNodeType(eNewNodeType)
+ ,m_nNodeID(nNewNodeID)
+{
+ OSL_ENSURE(m_eNodeType >= SQLNodeType::Rule && m_eNodeType <= SQLNodeType::Concat,"OSQLParseNode: created with invalid NodeType");
+}
+
+OSQLParseNode::OSQLParseNode(const OSQLParseNode& rParseNode)
+{
+ // Set the getParent to NULL
+ m_pParent = nullptr;
+
+ // Copy the members
+ m_aNodeValue = rParseNode.m_aNodeValue;
+ m_eNodeType = rParseNode.m_eNodeType;
+ m_nNodeID = rParseNode.m_nNodeID;
+
+
+ // Remember that we derived from Container. According to SV-Help the Container's
+ // copy ctor creates a new Container with the same pointers for content.
+ // This means after copying the Container, for all non-NULL pointers a copy is
+ // created and reattached instead of the old pointer.
+
+ // If not a leaf, then process SubTrees
+ for (auto const& child : rParseNode.m_aChildren)
+ append(new OSQLParseNode(*child));
+}
+
+
+OSQLParseNode& OSQLParseNode::operator=(const OSQLParseNode& rParseNode)
+{
+ if (this != &rParseNode)
+ {
+ // Copy the members - pParent remains the same
+ m_aNodeValue = rParseNode.m_aNodeValue;
+ m_eNodeType = rParseNode.m_eNodeType;
+ m_nNodeID = rParseNode.m_nNodeID;
+
+ m_aChildren.clear();
+
+ for (auto const& child : rParseNode.m_aChildren)
+ append(new OSQLParseNode(*child));
+ }
+ return *this;
+}
+
+
+bool OSQLParseNode::operator==(OSQLParseNode const & rParseNode) const
+{
+ // The members must be equal
+ bool bResult = (m_nNodeID == rParseNode.m_nNodeID) &&
+ (m_eNodeType == rParseNode.m_eNodeType) &&
+ (m_aNodeValue == rParseNode.m_aNodeValue) &&
+ count() == rParseNode.count();
+
+ // Parameters are not equal!
+ bResult = bResult && !SQL_ISRULE(this, parameter);
+
+ // compare children
+ for (size_t i=0; bResult && i < count(); i++)
+ bResult = *getChild(i) == *rParseNode.getChild(i);
+
+ return bResult;
+}
+
+
+OSQLParseNode::~OSQLParseNode()
+{
+}
+
+
+void OSQLParseNode::append(OSQLParseNode* pNewNode)
+{
+ OSL_ENSURE(pNewNode != nullptr, "OSQLParseNode: invalid NewSubTree");
+ OSL_ENSURE(pNewNode->getParent() == nullptr, "OSQLParseNode: Node is not an orphan");
+ OSL_ENSURE(std::none_of(m_aChildren.begin(), m_aChildren.end(),
+ [&] (std::unique_ptr<OSQLParseNode> const & r) { return r.get() == pNewNode; }),
+ "OSQLParseNode::append() Node already element of parent");
+
+ // Create connection to getParent
+ pNewNode->setParent( this );
+ // and attach the SubTree at the end
+ m_aChildren.emplace_back(pNewNode);
+}
+
+bool OSQLParseNode::addDateValue(OUStringBuffer& rString, const SQLParseNodeParameter& rParam) const
+{
+ // special display for date/time values
+ if (!SQL_ISRULE(this,set_fct_spec) || !SQL_ISPUNCTUATION(m_aChildren[0],"{"))
+ return false;
+
+ const OSQLParseNode* pODBCNode = m_aChildren[1].get();
+ const OSQLParseNode* pODBCNodeChild = pODBCNode->m_aChildren[0].get();
+
+ if (pODBCNodeChild->getNodeType() != SQLNodeType::Keyword || !(
+ SQL_ISTOKEN(pODBCNodeChild, D) ||
+ SQL_ISTOKEN(pODBCNodeChild, T) ||
+ SQL_ISTOKEN(pODBCNodeChild, TS) ))
+ return false;
+
+ OUString suQuote("'");
+ if (rParam.bPredicate)
+ {
+ if (rParam.aMetaData.shouldEscapeDateTime())
+ {
+ suQuote = "#";
+ }
+ }
+ else
+ {
+ if (rParam.aMetaData.shouldEscapeDateTime())
+ {
+ // suQuote = "'";
+ return false;
+ }
+ }
+
+ if (!rString.isEmpty())
+ rString.append(" ");
+ rString.append(suQuote);
+ const OUString sTokenValue = pODBCNode->m_aChildren[1]->getTokenValue();
+ if (SQL_ISTOKEN(pODBCNodeChild, D))
+ {
+ rString.append(rParam.bPredicate ? convertDateString(rParam, sTokenValue) : sTokenValue);
+ }
+ else if (SQL_ISTOKEN(pODBCNodeChild, T))
+ {
+ rString.append(rParam.bPredicate ? convertTimeString(rParam, sTokenValue) : sTokenValue);
+ }
+ else
+ {
+ rString.append(rParam.bPredicate ? convertDateTimeString(rParam, sTokenValue) : sTokenValue);
+ }
+ rString.append(suQuote);
+ return true;
+}
+
+void OSQLParseNode::replaceNodeValue(const OUString& rTableAlias, const OUString& rColumnName)
+{
+ for (size_t i=0;i<count();++i)
+ {
+ if (SQL_ISRULE(this,column_ref) && count() == 1 && getChild(0)->getTokenValue() == rColumnName)
+ {
+ OSQLParseNode * pCol = removeAt(sal_uInt32(0));
+ append(new OSQLParseNode(rTableAlias,SQLNodeType::Name));
+ append(new OSQLParseNode(".",SQLNodeType::Punctuation));
+ append(pCol);
+ }
+ else
+ getChild(i)->replaceNodeValue(rTableAlias,rColumnName);
+ }
+}
+
+OSQLParseNode* OSQLParseNode::getByRule(OSQLParseNode::Rule eRule) const
+{
+ OSQLParseNode* pRetNode = nullptr;
+ if (isRule() && OSQLParser::RuleID(eRule) == getRuleID())
+ pRetNode = const_cast<OSQLParseNode*>(this);
+ else
+ {
+ for (auto const& child : m_aChildren)
+ {
+ pRetNode = child->getByRule(eRule);
+ if (pRetNode)
+ break;
+ }
+ }
+ return pRetNode;
+}
+
+static OSQLParseNode* MakeANDNode(OSQLParseNode *pLeftLeaf,OSQLParseNode *pRightLeaf)
+{
+ OSQLParseNode* pNewNode = new OSQLParseNode(OUString(),SQLNodeType::Rule,OSQLParser::RuleID(OSQLParseNode::boolean_term));
+ pNewNode->append(pLeftLeaf);
+ pNewNode->append(new OSQLParseNode("AND",SQLNodeType::Keyword,SQL_TOKEN_AND));
+ pNewNode->append(pRightLeaf);
+ return pNewNode;
+}
+
+static OSQLParseNode* MakeORNode(OSQLParseNode *pLeftLeaf,OSQLParseNode *pRightLeaf)
+{
+ OSQLParseNode* pNewNode = new OSQLParseNode(OUString(),SQLNodeType::Rule,OSQLParser::RuleID(OSQLParseNode::search_condition));
+ pNewNode->append(pLeftLeaf);
+ pNewNode->append(new OSQLParseNode("OR",SQLNodeType::Keyword,SQL_TOKEN_OR));
+ pNewNode->append(pRightLeaf);
+ return pNewNode;
+}
+
+void OSQLParseNode::disjunctiveNormalForm(OSQLParseNode*& pSearchCondition)
+{
+ if(!pSearchCondition) // no where condition at entry point
+ return;
+
+ OSQLParseNode::absorptions(pSearchCondition);
+ // '(' search_condition ')'
+ if (SQL_ISRULE(pSearchCondition,boolean_primary))
+ {
+ OSQLParseNode* pLeft = pSearchCondition->getChild(1);
+ disjunctiveNormalForm(pLeft);
+ }
+ // search_condition SQL_TOKEN_OR boolean_term
+ else if (SQL_ISRULE(pSearchCondition,search_condition))
+ {
+ OSQLParseNode* pLeft = pSearchCondition->getChild(0);
+ disjunctiveNormalForm(pLeft);
+
+ OSQLParseNode* pRight = pSearchCondition->getChild(2);
+ disjunctiveNormalForm(pRight);
+ }
+ // boolean_term SQL_TOKEN_AND boolean_factor
+ else if (SQL_ISRULE(pSearchCondition,boolean_term))
+ {
+ OSQLParseNode* pLeft = pSearchCondition->getChild(0);
+ disjunctiveNormalForm(pLeft);
+
+ OSQLParseNode* pRight = pSearchCondition->getChild(2);
+ disjunctiveNormalForm(pRight);
+
+ OSQLParseNode* pNewNode = nullptr;
+ // '(' search_condition ')' on left side
+ if(pLeft->count() == 3 && SQL_ISRULE(pLeft,boolean_primary) && SQL_ISRULE(pLeft->getChild(1),search_condition))
+ {
+ // and-or tree on left side
+ OSQLParseNode* pOr = pLeft->getChild(1);
+ OSQLParseNode* pNewLeft = nullptr;
+ OSQLParseNode* pNewRight = nullptr;
+
+ // cut right from parent
+ OSQLParseNode* pOldRight = pSearchCondition->removeAt(2);
+ assert(pOldRight == pRight);
+
+ pNewRight = MakeANDNode(pOr->removeAt(2), pOldRight);
+ pNewLeft = MakeANDNode(pOr->removeAt(sal_uInt32(0)), new OSQLParseNode(*pOldRight));
+ pNewNode = MakeORNode(pNewLeft,pNewRight);
+ // and append new Node
+ replaceAndReset(pSearchCondition,pNewNode);
+
+ disjunctiveNormalForm(pSearchCondition);
+ }
+ else if(pRight->count() == 3 && SQL_ISRULE(pRight,boolean_primary) && SQL_ISRULE(pRight->getChild(1),search_condition))
+ { // '(' search_condition ')' on right side
+ // and-or tree on right side
+ // a and (b or c)
+ OSQLParseNode* pOr = pRight->getChild(1);
+ OSQLParseNode* pNewLeft = nullptr;
+ OSQLParseNode* pNewRight = nullptr;
+
+ // cut left from parent
+ OSQLParseNode* pOldLeft = pSearchCondition->removeAt(sal_uInt32(0));
+ assert(pOldLeft == pLeft);
+
+ pNewRight = MakeANDNode(pOldLeft, pOr->removeAt(2));
+ pNewLeft = MakeANDNode(new OSQLParseNode(*pOldLeft), pOr->removeAt(sal_uInt32(0)));
+ pNewNode = MakeORNode(pNewLeft,pNewRight);
+
+ // and append new Node
+ replaceAndReset(pSearchCondition,pNewNode);
+ disjunctiveNormalForm(pSearchCondition);
+ }
+ else if(SQL_ISRULE(pLeft,boolean_primary) && (!SQL_ISRULE(pLeft->getChild(1),search_condition) || !SQL_ISRULE(pLeft->getChild(1),boolean_term)))
+ pSearchCondition->replaceAndDelete(pLeft, pLeft->removeAt(1));
+ else if(SQL_ISRULE(pRight,boolean_primary) && (!SQL_ISRULE(pRight->getChild(1),search_condition) || !SQL_ISRULE(pRight->getChild(1),boolean_term)))
+ pSearchCondition->replaceAndDelete(pRight, pRight->removeAt(1));
+ }
+}
+
+void OSQLParseNode::negateSearchCondition(OSQLParseNode*& pSearchCondition, bool bNegate)
+{
+ if(!pSearchCondition) // no where condition at entry point
+ return;
+ // '(' search_condition ')'
+ if (pSearchCondition->count() == 3 && SQL_ISRULE(pSearchCondition,boolean_primary))
+ {
+ OSQLParseNode* pRight = pSearchCondition->getChild(1);
+ negateSearchCondition(pRight,bNegate);
+ }
+ // search_condition SQL_TOKEN_OR boolean_term
+ else if (SQL_ISRULE(pSearchCondition,search_condition))
+ {
+ OSQLParseNode* pLeft = pSearchCondition->getChild(0);
+ OSQLParseNode* pRight = pSearchCondition->getChild(2);
+ if(bNegate)
+ {
+ OSQLParseNode* pNewNode = new OSQLParseNode(OUString(),SQLNodeType::Rule,OSQLParser::RuleID(OSQLParseNode::boolean_term));
+ pNewNode->append(pSearchCondition->removeAt(sal_uInt32(0)));
+ pNewNode->append(new OSQLParseNode("AND",SQLNodeType::Keyword,SQL_TOKEN_AND));
+ pNewNode->append(pSearchCondition->removeAt(sal_uInt32(1)));
+ replaceAndReset(pSearchCondition,pNewNode);
+
+ pLeft = pNewNode->getChild(0);
+ pRight = pNewNode->getChild(2);
+ }
+
+ negateSearchCondition(pLeft,bNegate);
+ negateSearchCondition(pRight,bNegate);
+ }
+ // boolean_term SQL_TOKEN_AND boolean_factor
+ else if (SQL_ISRULE(pSearchCondition,boolean_term))
+ {
+ OSQLParseNode* pLeft = pSearchCondition->getChild(0);
+ OSQLParseNode* pRight = pSearchCondition->getChild(2);
+ if(bNegate)
+ {
+ OSQLParseNode* pNewNode = new OSQLParseNode(OUString(),SQLNodeType::Rule,OSQLParser::RuleID(OSQLParseNode::search_condition));
+ pNewNode->append(pSearchCondition->removeAt(sal_uInt32(0)));
+ pNewNode->append(new OSQLParseNode("OR",SQLNodeType::Keyword,SQL_TOKEN_OR));
+ pNewNode->append(pSearchCondition->removeAt(sal_uInt32(1)));
+ replaceAndReset(pSearchCondition,pNewNode);
+
+ pLeft = pNewNode->getChild(0);
+ pRight = pNewNode->getChild(2);
+ }
+
+ negateSearchCondition(pLeft,bNegate);
+ negateSearchCondition(pRight,bNegate);
+ }
+ // SQL_TOKEN_NOT ( boolean_primary )
+ else if (SQL_ISRULE(pSearchCondition,boolean_factor))
+ {
+ OSQLParseNode *pNot = pSearchCondition->removeAt(sal_uInt32(0));
+ delete pNot;
+ OSQLParseNode *pBooleanTest = pSearchCondition->removeAt(sal_uInt32(0));
+ // TODO is this needed // pBooleanTest->setParent(NULL);
+ replaceAndReset(pSearchCondition,pBooleanTest);
+
+ if (!bNegate)
+ negateSearchCondition(pSearchCondition, true); // negate all deeper values
+ }
+ // row_value_constructor comparison row_value_constructor
+ // row_value_constructor comparison any_all_some subquery
+ else if(bNegate && (SQL_ISRULE(pSearchCondition,comparison_predicate) || SQL_ISRULE(pSearchCondition,all_or_any_predicate)))
+ {
+ assert(pSearchCondition->count() == 3);
+ OSQLParseNode* pComparison = pSearchCondition->getChild(1);
+ if(SQL_ISRULE(pComparison, comparison))
+ {
+ assert(pComparison->count() == 2 ||
+ pComparison->count() == 4);
+ assert(SQL_ISTOKEN(pComparison->getChild(0), IS));
+
+ OSQLParseNode* pNot = pComparison->getChild(1);
+ OSQLParseNode* pNotNot = nullptr;
+ if(pNot->isRule()) // no NOT token (empty rule)
+ pNotNot = new OSQLParseNode("NOT",SQLNodeType::Keyword,SQL_TOKEN_NOT);
+ else
+ {
+ assert(SQL_ISTOKEN(pNot,NOT));
+ pNotNot = new OSQLParseNode(OUString(),SQLNodeType::Rule,OSQLParser::RuleID(OSQLParseNode::sql_not));
+ }
+ pComparison->replaceAndDelete(pNot, pNotNot);
+ }
+ else
+ {
+ OSQLParseNode* pNewComparison;
+ switch(pComparison->getNodeType())
+ {
+ default:
+ case SQLNodeType::Equal:
+ assert(pComparison->getNodeType() == SQLNodeType::Equal &&
+ "OSQLParseNode::negateSearchCondition: unexpected node type!");
+ pNewComparison = new OSQLParseNode("<>",SQLNodeType::NotEqual,SQL_NOTEQUAL);
+ break;
+ case SQLNodeType::Less:
+ pNewComparison = new OSQLParseNode(">=",SQLNodeType::GreatEq,SQL_GREATEQ);
+ break;
+ case SQLNodeType::Great:
+ pNewComparison = new OSQLParseNode("<=",SQLNodeType::LessEq,SQL_LESSEQ);
+ break;
+ case SQLNodeType::LessEq:
+ pNewComparison = new OSQLParseNode(">",SQLNodeType::Great,SQL_GREAT);
+ break;
+ case SQLNodeType::GreatEq:
+ pNewComparison = new OSQLParseNode("<",SQLNodeType::Less,SQL_LESS);
+ break;
+ case SQLNodeType::NotEqual:
+ pNewComparison = new OSQLParseNode("=",SQLNodeType::Equal,SQL_EQUAL);
+ break;
+ }
+ pSearchCondition->replaceAndDelete(pComparison, pNewComparison);
+ }
+ }
+
+ else if(bNegate && (SQL_ISRULE(pSearchCondition,test_for_null) ||
+ SQL_ISRULE(pSearchCondition,in_predicate) ||
+ SQL_ISRULE(pSearchCondition,between_predicate) ))
+ {
+ OSQLParseNode* pPart2 = pSearchCondition->getChild(1);
+ sal_uInt32 nNotPos = 0;
+ if ( SQL_ISRULE( pSearchCondition, test_for_null ) )
+ nNotPos = 1;
+
+ OSQLParseNode* pNot = pPart2->getChild(nNotPos);
+ OSQLParseNode* pNotNot = nullptr;
+ if(pNot->isRule()) // no NOT token (empty rule)
+ pNotNot = new OSQLParseNode("NOT",SQLNodeType::Keyword,SQL_TOKEN_NOT);
+ else
+ {
+ assert(SQL_ISTOKEN(pNot,NOT));
+ pNotNot = new OSQLParseNode(OUString(),SQLNodeType::Rule,OSQLParser::RuleID(OSQLParseNode::sql_not));
+ }
+ pPart2->replaceAndDelete(pNot, pNotNot);
+ }
+ else if(bNegate && SQL_ISRULE(pSearchCondition,like_predicate))
+ {
+ OSQLParseNode* pNot = pSearchCondition->getChild( 1 )->getChild( 0 );
+ OSQLParseNode* pNotNot = nullptr;
+ if(pNot->isRule())
+ pNotNot = new OSQLParseNode("NOT",SQLNodeType::Keyword,SQL_TOKEN_NOT);
+ else
+ pNotNot = new OSQLParseNode(OUString(),SQLNodeType::Rule,OSQLParser::RuleID(OSQLParseNode::sql_not));
+ pSearchCondition->getChild( 1 )->replaceAndDelete(pNot, pNotNot);
+ }
+}
+
+void OSQLParseNode::eraseBraces(OSQLParseNode*& pSearchCondition)
+{
+ if (!(pSearchCondition && (SQL_ISRULE(pSearchCondition,boolean_primary) || (pSearchCondition->count() == 3 && SQL_ISPUNCTUATION(pSearchCondition->getChild(0),"(") &&
+ SQL_ISPUNCTUATION(pSearchCondition->getChild(2),")")))))
+ return;
+
+ OSQLParseNode* pRight = pSearchCondition->getChild(1);
+ absorptions(pRight);
+ // if child is not an or and tree then delete () around child
+ if(!(SQL_ISRULE(pSearchCondition->getChild(1),boolean_term) || SQL_ISRULE(pSearchCondition->getChild(1),search_condition)) ||
+ SQL_ISRULE(pSearchCondition->getChild(1),boolean_term) || // and can always stand without ()
+ (SQL_ISRULE(pSearchCondition->getChild(1),search_condition) && SQL_ISRULE(pSearchCondition->getParent(),search_condition)))
+ {
+ OSQLParseNode* pNode = pSearchCondition->removeAt(1);
+ replaceAndReset(pSearchCondition,pNode);
+ }
+}
+
+void OSQLParseNode::absorptions(OSQLParseNode*& pSearchCondition)
+{
+ if(!pSearchCondition) // no where condition at entry point
+ return;
+
+ eraseBraces(pSearchCondition);
+
+ if(SQL_ISRULE(pSearchCondition,boolean_term) || SQL_ISRULE(pSearchCondition,search_condition))
+ {
+ OSQLParseNode* pLeft = pSearchCondition->getChild(0);
+ absorptions(pLeft);
+ OSQLParseNode* pRight = pSearchCondition->getChild(2);
+ absorptions(pRight);
+ }
+
+ sal_uInt32 nPos = 0;
+ // a and a || a or a
+ OSQLParseNode* pNewNode = nullptr;
+ if(( SQL_ISRULE(pSearchCondition,boolean_term) || SQL_ISRULE(pSearchCondition,search_condition))
+ && *pSearchCondition->getChild(0) == *pSearchCondition->getChild(2))
+ {
+ pNewNode = pSearchCondition->removeAt(sal_uInt32(0));
+ replaceAndReset(pSearchCondition,pNewNode);
+ }
+ // ( a or b ) and a || ( b or c ) and a
+ // a and ( a or b ) || a and ( b or c )
+ else if ( SQL_ISRULE(pSearchCondition,boolean_term)
+ && (
+ ( SQL_ISRULE(pSearchCondition->getChild(nPos = 0),boolean_primary)
+ || SQL_ISRULE(pSearchCondition->getChild(nPos),search_condition)
+ )
+ || ( SQL_ISRULE(pSearchCondition->getChild(nPos = 2),boolean_primary)
+ || SQL_ISRULE(pSearchCondition->getChild(nPos),search_condition)
+ )
+ )
+ )
+ {
+ OSQLParseNode* p2ndSearch = pSearchCondition->getChild(nPos);
+ if ( SQL_ISRULE(p2ndSearch,boolean_primary) )
+ p2ndSearch = p2ndSearch->getChild(1);
+
+ if ( *p2ndSearch->getChild(0) == *pSearchCondition->getChild(2-nPos) ) // a and ( a or b) -> a or b
+ {
+ pNewNode = pSearchCondition->removeAt(sal_uInt32(0));
+ replaceAndReset(pSearchCondition,pNewNode);
+
+ }
+ else if ( *p2ndSearch->getChild(2) == *pSearchCondition->getChild(2-nPos) ) // a and ( b or a) -> a or b
+ {
+ pNewNode = pSearchCondition->removeAt(sal_uInt32(2));
+ replaceAndReset(pSearchCondition,pNewNode);
+ }
+ else if ( p2ndSearch->getByRule(OSQLParseNode::search_condition) )
+ {
+ // a and ( b or c ) -> ( a and b ) or ( a and c )
+ // ( b or c ) and a -> ( a and b ) or ( a and c )
+ OSQLParseNode* pC = p2ndSearch->removeAt(sal_uInt32(2));
+ OSQLParseNode* pB = p2ndSearch->removeAt(sal_uInt32(0));
+ OSQLParseNode* pA = pSearchCondition->removeAt(sal_uInt32(2)-nPos);
+
+ OSQLParseNode* p1stAnd = MakeANDNode(pA,pB);
+ OSQLParseNode* p2ndAnd = MakeANDNode(new OSQLParseNode(*pA),pC);
+ pNewNode = MakeORNode(p1stAnd,p2ndAnd);
+ OSQLParseNode* pNode = new OSQLParseNode(OUString(),SQLNodeType::Rule,OSQLParser::RuleID(OSQLParseNode::boolean_primary));
+ pNode->append(new OSQLParseNode("(",SQLNodeType::Punctuation));
+ pNode->append(pNewNode);
+ pNode->append(new OSQLParseNode(")",SQLNodeType::Punctuation));
+ OSQLParseNode::eraseBraces(p1stAnd);
+ OSQLParseNode::eraseBraces(p2ndAnd);
+ replaceAndReset(pSearchCondition,pNode);
+ }
+ }
+ // a or a and b || a or b and a
+ else if(SQL_ISRULE(pSearchCondition,search_condition) && SQL_ISRULE(pSearchCondition->getChild(2),boolean_term))
+ {
+ if(*pSearchCondition->getChild(2)->getChild(0) == *pSearchCondition->getChild(0))
+ {
+ pNewNode = pSearchCondition->removeAt(sal_uInt32(0));
+ replaceAndReset(pSearchCondition,pNewNode);
+ }
+ else if(*pSearchCondition->getChild(2)->getChild(2) == *pSearchCondition->getChild(0))
+ {
+ pNewNode = pSearchCondition->removeAt(sal_uInt32(0));
+ replaceAndReset(pSearchCondition,pNewNode);
+ }
+ }
+ // a and b or a || b and a or a
+ else if(SQL_ISRULE(pSearchCondition,search_condition) && SQL_ISRULE(pSearchCondition->getChild(0),boolean_term))
+ {
+ if(*pSearchCondition->getChild(0)->getChild(0) == *pSearchCondition->getChild(2))
+ {
+ pNewNode = pSearchCondition->removeAt(sal_uInt32(2));
+ replaceAndReset(pSearchCondition,pNewNode);
+ }
+ else if(*pSearchCondition->getChild(0)->getChild(2) == *pSearchCondition->getChild(2))
+ {
+ pNewNode = pSearchCondition->removeAt(sal_uInt32(2));
+ replaceAndReset(pSearchCondition,pNewNode);
+ }
+ }
+ eraseBraces(pSearchCondition);
+}
+
+void OSQLParseNode::compress(OSQLParseNode *&pSearchCondition)
+{
+ if(!pSearchCondition) // no WHERE condition at entry point
+ return;
+
+ OSQLParseNode::eraseBraces(pSearchCondition);
+
+ if(SQL_ISRULE(pSearchCondition,boolean_term) || SQL_ISRULE(pSearchCondition,search_condition))
+ {
+ OSQLParseNode* pLeft = pSearchCondition->getChild(0);
+ compress(pLeft);
+
+ OSQLParseNode* pRight = pSearchCondition->getChild(2);
+ compress(pRight);
+ }
+ else if( SQL_ISRULE(pSearchCondition,boolean_primary) || (pSearchCondition->count() == 3 && SQL_ISPUNCTUATION(pSearchCondition->getChild(0),"(") &&
+ SQL_ISPUNCTUATION(pSearchCondition->getChild(2),")")))
+ {
+ OSQLParseNode* pRight = pSearchCondition->getChild(1);
+ compress(pRight);
+ // if child is not an or and tree then delete () around child
+ if(!(SQL_ISRULE(pSearchCondition->getChild(1),boolean_term) || SQL_ISRULE(pSearchCondition->getChild(1),search_condition)) ||
+ (SQL_ISRULE(pSearchCondition->getChild(1),boolean_term) && SQL_ISRULE(pSearchCondition->getParent(),boolean_term)) ||
+ (SQL_ISRULE(pSearchCondition->getChild(1),search_condition) && SQL_ISRULE(pSearchCondition->getParent(),search_condition)))
+ {
+ OSQLParseNode* pNode = pSearchCondition->removeAt(1);
+ replaceAndReset(pSearchCondition,pNode);
+ }
+ }
+
+ // or with two and trees where one element of the and trees are equal
+ if(!(SQL_ISRULE(pSearchCondition,search_condition) && SQL_ISRULE(pSearchCondition->getChild(0),boolean_term) && SQL_ISRULE(pSearchCondition->getChild(2),boolean_term)))
+ return;
+
+ if(*pSearchCondition->getChild(0)->getChild(0) == *pSearchCondition->getChild(2)->getChild(0))
+ {
+ OSQLParseNode* pLeft = pSearchCondition->getChild(0)->removeAt(2);
+ OSQLParseNode* pRight = pSearchCondition->getChild(2)->removeAt(2);
+ OSQLParseNode* pNode = MakeORNode(pLeft,pRight);
+
+ OSQLParseNode* pNewRule = new OSQLParseNode(OUString(),SQLNodeType::Rule,OSQLParser::RuleID(OSQLParseNode::boolean_primary));
+ pNewRule->append(new OSQLParseNode("(",SQLNodeType::Punctuation));
+ pNewRule->append(pNode);
+ pNewRule->append(new OSQLParseNode(")",SQLNodeType::Punctuation));
+
+ OSQLParseNode::eraseBraces(pLeft);
+ OSQLParseNode::eraseBraces(pRight);
+
+ pNode = MakeANDNode(pSearchCondition->getChild(0)->removeAt(sal_uInt32(0)),pNewRule);
+ replaceAndReset(pSearchCondition,pNode);
+ }
+ else if(*pSearchCondition->getChild(0)->getChild(2) == *pSearchCondition->getChild(2)->getChild(0))
+ {
+ OSQLParseNode* pLeft = pSearchCondition->getChild(0)->removeAt(sal_uInt32(0));
+ OSQLParseNode* pRight = pSearchCondition->getChild(2)->removeAt(2);
+ OSQLParseNode* pNode = MakeORNode(pLeft,pRight);
+
+ OSQLParseNode* pNewRule = new OSQLParseNode(OUString(),SQLNodeType::Rule,OSQLParser::RuleID(OSQLParseNode::boolean_primary));
+ pNewRule->append(new OSQLParseNode("(",SQLNodeType::Punctuation));
+ pNewRule->append(pNode);
+ pNewRule->append(new OSQLParseNode(")",SQLNodeType::Punctuation));
+
+ OSQLParseNode::eraseBraces(pLeft);
+ OSQLParseNode::eraseBraces(pRight);
+
+ pNode = MakeANDNode(pSearchCondition->getChild(0)->removeAt(1),pNewRule);
+ replaceAndReset(pSearchCondition,pNode);
+ }
+ else if(*pSearchCondition->getChild(0)->getChild(0) == *pSearchCondition->getChild(2)->getChild(2))
+ {
+ OSQLParseNode* pLeft = pSearchCondition->getChild(0)->removeAt(2);
+ OSQLParseNode* pRight = pSearchCondition->getChild(2)->removeAt(sal_uInt32(0));
+ OSQLParseNode* pNode = MakeORNode(pLeft,pRight);
+
+ OSQLParseNode* pNewRule = new OSQLParseNode(OUString(),SQLNodeType::Rule,OSQLParser::RuleID(OSQLParseNode::boolean_primary));
+ pNewRule->append(new OSQLParseNode("(",SQLNodeType::Punctuation));
+ pNewRule->append(pNode);
+ pNewRule->append(new OSQLParseNode(")",SQLNodeType::Punctuation));
+
+ OSQLParseNode::eraseBraces(pLeft);
+ OSQLParseNode::eraseBraces(pRight);
+
+ pNode = MakeANDNode(pSearchCondition->getChild(0)->removeAt(sal_uInt32(0)),pNewRule);
+ replaceAndReset(pSearchCondition,pNode);
+ }
+ else if(*pSearchCondition->getChild(0)->getChild(2) == *pSearchCondition->getChild(2)->getChild(2))
+ {
+ OSQLParseNode* pLeft = pSearchCondition->getChild(0)->removeAt(sal_uInt32(0));
+ OSQLParseNode* pRight = pSearchCondition->getChild(2)->removeAt(sal_uInt32(0));
+ OSQLParseNode* pNode = MakeORNode(pLeft,pRight);
+
+ OSQLParseNode* pNewRule = new OSQLParseNode(OUString(),SQLNodeType::Rule,OSQLParser::RuleID(OSQLParseNode::boolean_primary));
+ pNewRule->append(new OSQLParseNode("(",SQLNodeType::Punctuation));
+ pNewRule->append(pNode);
+ pNewRule->append(new OSQLParseNode(")",SQLNodeType::Punctuation));
+
+ OSQLParseNode::eraseBraces(pLeft);
+ OSQLParseNode::eraseBraces(pRight);
+
+ pNode = MakeANDNode(pSearchCondition->getChild(0)->removeAt(1),pNewRule);
+ replaceAndReset(pSearchCondition,pNode);
+ }
+}
+#if OSL_DEBUG_LEVEL > 1
+
+void OSQLParseNode::showParseTree( OUString& rString ) const
+{
+ OUStringBuffer aBuf;
+ showParseTree( aBuf, 0 );
+ rString = aBuf.makeStringAndClear();
+}
+
+
+void OSQLParseNode::showParseTree( OUStringBuffer& _inout_rBuffer, sal_uInt32 nLevel ) const
+{
+ for ( sal_uInt32 j=0; j<nLevel; ++j)
+ _inout_rBuffer.appendAscii( " " );
+
+ if ( !isToken() )
+ {
+ // Rule name as rule
+ _inout_rBuffer.appendAscii( "RULE_ID: " );
+ _inout_rBuffer.append( (sal_Int32)getRuleID() );
+ _inout_rBuffer.append( '(' );
+ _inout_rBuffer.append( OSQLParser::RuleIDToStr( getRuleID() ) );
+ _inout_rBuffer.append( ')' );
+ _inout_rBuffer.append( '\n' );
+
+ // Get the first sub tree
+ for (auto const& child : m_aChildren)
+ child->showParseTree( _inout_rBuffer, nLevel+1 );
+ }
+ else
+ {
+ // Found a token
+ switch (m_eNodeType)
+ {
+
+ case SQLNodeType::Keyword:
+ _inout_rBuffer.appendAscii( "SQL_KEYWORD: " );
+ _inout_rBuffer.append( OStringToOUString( OSQLParser::TokenIDToStr( getTokenID() ), RTL_TEXTENCODING_UTF8 ) );
+ _inout_rBuffer.append( '\n' );
+ break;
+
+ case SQLNodeType::Name:
+ _inout_rBuffer.appendAscii( "SQL_NAME: " );
+ _inout_rBuffer.append( '"' );
+ _inout_rBuffer.append( m_aNodeValue );
+ _inout_rBuffer.append( '"' );
+ _inout_rBuffer.append( '\n' );
+ break;
+
+ case SQLNodeType::String:
+ _inout_rBuffer.appendAscii( "SQL_STRING: " );
+ _inout_rBuffer.append( '\'' );
+ _inout_rBuffer.append( m_aNodeValue );
+ _inout_rBuffer.append( '\'' );
+ _inout_rBuffer.append( '\n' );
+ break;
+
+ case SQLNodeType::IntNum:
+ _inout_rBuffer.appendAscii( "SQL_INTNUM: " );
+ _inout_rBuffer.append( m_aNodeValue );
+ _inout_rBuffer.append( '\n' );
+ break;
+
+ case SQLNodeType::ApproxNum:
+ _inout_rBuffer.appendAscii( "SQL_APPROXNUM: " );
+ _inout_rBuffer.append( m_aNodeValue );
+ _inout_rBuffer.append( '\n' );
+ break;
+
+ case SQLNodeType::Punctuation:
+ _inout_rBuffer.appendAscii( "SQL_PUNCTUATION: " );
+ _inout_rBuffer.append( m_aNodeValue );
+ _inout_rBuffer.append( '\n' );
+ break;
+
+ case SQLNodeType::Equal:
+ case SQLNodeType::Less:
+ case SQLNodeType::Great:
+ case SQLNodeType::LessEq:
+ case SQLNodeType::GreatEq:
+ case SQLNodeType::NotEqual:
+ _inout_rBuffer.append( m_aNodeValue );
+ _inout_rBuffer.append( '\n' );
+ break;
+
+ case SQLNodeType::AccessDate:
+ _inout_rBuffer.appendAscii( "SQL_ACCESS_DATE: " );
+ _inout_rBuffer.append( m_aNodeValue );
+ _inout_rBuffer.append( '\n' );
+ break;
+
+ case SQLNodeType::Concat:
+ _inout_rBuffer.appendAscii( "||" );
+ _inout_rBuffer.append( '\n' );
+ break;
+
+ default:
+ SAL_INFO( "connectivity.parse", "-- " << int( m_eNodeType ) );
+ SAL_WARN( "connectivity.parse", "OSQLParser::ShowParseTree: unzulaessiger NodeType" );
+ }
+ }
+}
+#endif // OSL_DEBUG_LEVEL > 0
+
+// Insert methods
+
+void OSQLParseNode::insert(sal_uInt32 nPos, OSQLParseNode* pNewSubTree)
+{
+ assert(pNewSubTree != nullptr && "OSQLParseNode: invalid NewSubTree");
+ OSL_ENSURE(pNewSubTree->getParent() == nullptr, "OSQLParseNode: Node is not an orphan");
+
+ // Create connection to getParent
+ pNewSubTree->setParent( this );
+ m_aChildren.emplace(m_aChildren.begin() + nPos, pNewSubTree);
+}
+
+// removeAt methods
+
+OSQLParseNode* OSQLParseNode::removeAt(sal_uInt32 nPos)
+{
+ assert(nPos < m_aChildren.size() && "Illegal position for removeAt");
+ auto aPos(m_aChildren.begin() + nPos);
+ auto pNode = std::move(*aPos);
+
+ // Set the getParent of the removed node to NULL
+ pNode->setParent( nullptr );
+
+ m_aChildren.erase(aPos);
+ return pNode.release();
+}
+
+// Replace methods
+
+void OSQLParseNode::replaceAndDelete(OSQLParseNode* pOldSubNode, OSQLParseNode* pNewSubNode )
+{
+ assert(pOldSubNode != nullptr && pNewSubNode != nullptr && "OSQLParseNode: invalid nodes");
+ assert(pOldSubNode != pNewSubNode && "OSQLParseNode: same node");
+ assert(pNewSubNode->getParent() == nullptr && "OSQLParseNode: node already has getParent");
+ assert(std::any_of(m_aChildren.begin(), m_aChildren.end(),
+ [&] (std::unique_ptr<OSQLParseNode> const & r) { return r.get() == pOldSubNode; })
+ && "OSQLParseNode::Replace() Node not element of parent");
+ assert(std::none_of(m_aChildren.begin(), m_aChildren.end(),
+ [&] (std::unique_ptr<OSQLParseNode> const & r) { return r.get() == pNewSubNode; })
+ && "OSQLParseNode::Replace() Node already element of parent");
+
+ pOldSubNode->setParent( nullptr );
+ pNewSubNode->setParent( this );
+ auto it = std::find_if(m_aChildren.begin(), m_aChildren.end(),
+ [&pOldSubNode](const std::unique_ptr<OSQLParseNode>& rxChild) { return rxChild.get() == pOldSubNode; });
+ assert(it != m_aChildren.end());
+ it->reset(pNewSubNode);
+}
+
+void OSQLParseNode::parseLeaf(OUStringBuffer& rString, const SQLParseNodeParameter& rParam) const
+{
+ // Found a leaf
+ // Append content to the output string
+ switch (m_eNodeType)
+ {
+ case SQLNodeType::Keyword:
+ {
+ if (!rString.isEmpty())
+ rString.append(" ");
+
+ const OString sT = OSQLParser::TokenIDToStr(m_nNodeID, rParam.bInternational ? &rParam.m_rContext : nullptr);
+ rString.append(OStringToOUString(sT,RTL_TEXTENCODING_UTF8));
+ } break;
+ case SQLNodeType::String:
+ if (!rString.isEmpty())
+ rString.append(" ");
+ rString.append(SetQuotation(m_aNodeValue, u"\'", u"\'\'"));
+ break;
+ case SQLNodeType::Name:
+ if (!rString.isEmpty())
+ {
+ switch(rString[rString.getLength()-1])
+ {
+ case ' ' :
+ case '.' : break;
+ default :
+ if ( rParam.aMetaData.getCatalogSeparator().isEmpty()
+ || rString[rString.getLength() - 1] != rParam.aMetaData.getCatalogSeparator().toChar()
+ )
+ rString.append(" ");
+ break;
+ }
+ }
+ if (rParam.bQuote)
+ {
+ if (rParam.bPredicate)
+ {
+ rString.append("[");
+ rString.append(m_aNodeValue);
+ rString.append("]");
+ }
+ else
+ rString.append(SetQuotation(m_aNodeValue,
+ rParam.aMetaData.getIdentifierQuoteString(), rParam.aMetaData.getIdentifierQuoteString() ));
+ }
+ else
+ rString.append(m_aNodeValue);
+ break;
+ case SQLNodeType::AccessDate:
+ if (!rString.isEmpty())
+ rString.append(" ");
+ rString.append("#");
+ rString.append(m_aNodeValue);
+ rString.append("#");
+ break;
+
+ case SQLNodeType::IntNum:
+ case SQLNodeType::ApproxNum:
+ {
+ OUString aTmp = m_aNodeValue;
+ static constexpr OUString strPoint(u"."_ustr);
+ if (rParam.bInternational && rParam.bPredicate && rParam.sDecSep != strPoint)
+ aTmp = aTmp.replaceAll(strPoint, rParam.sDecSep);
+
+ if (!rString.isEmpty())
+ rString.append(" ");
+ rString.append(aTmp);
+
+ } break;
+ case SQLNodeType::Punctuation:
+ if ( getParent() && SQL_ISRULE(getParent(),cast_spec) && m_aNodeValue.toChar() == '(' ) // no spaces in front of '('
+ {
+ rString.append(m_aNodeValue);
+ break;
+ }
+ [[fallthrough]];
+ default:
+ if (!rString.isEmpty() && m_aNodeValue.toChar() != '.' && m_aNodeValue.toChar() != ':' )
+ {
+ switch( rString[rString.getLength() - 1] )
+ {
+ case ' ' :
+ case '.' : break;
+ default :
+ if ( rParam.aMetaData.getCatalogSeparator().isEmpty()
+ || rString[rString.getLength() - 1] != rParam.aMetaData.getCatalogSeparator().toChar()
+ )
+ rString.append(" ");
+ break;
+ }
+ }
+ rString.append(m_aNodeValue);
+ }
+}
+
+
+sal_Int32 OSQLParser::getFunctionReturnType(std::u16string_view _sFunctionName, const IParseContext* pContext)
+{
+ sal_Int32 nType = DataType::SQLNULL;
+ OString sFunctionName(OUStringToOString(_sFunctionName,RTL_TEXTENCODING_UTF8));
+
+ if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_ASCII,pContext))) nType = DataType::INTEGER;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_BIT_LENGTH,pContext))) nType = DataType::INTEGER;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_CHAR,pContext))) nType = DataType::VARCHAR;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_CHAR_LENGTH,pContext))) nType = DataType::INTEGER;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_CONCAT,pContext))) nType = DataType::VARCHAR;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_DIFFERENCE,pContext))) nType = DataType::VARCHAR;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_INSERT,pContext))) nType = DataType::VARCHAR;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_LCASE,pContext))) nType = DataType::VARCHAR;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_LEFT,pContext))) nType = DataType::VARCHAR;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_LENGTH,pContext))) nType = DataType::INTEGER;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_LOCATE,pContext))) nType = DataType::VARCHAR;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_LOCATE_2,pContext))) nType = DataType::VARCHAR;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_LTRIM,pContext))) nType = DataType::VARCHAR;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_OCTET_LENGTH,pContext))) nType = DataType::INTEGER;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_POSITION,pContext))) nType = DataType::INTEGER;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_REPEAT,pContext))) nType = DataType::VARCHAR;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_REPLACE,pContext))) nType = DataType::VARCHAR;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_RIGHT,pContext))) nType = DataType::VARCHAR;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_RTRIM,pContext))) nType = DataType::VARCHAR;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_SOUNDEX,pContext))) nType = DataType::VARCHAR;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_SPACE,pContext))) nType = DataType::VARCHAR;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_SUBSTRING,pContext))) nType = DataType::VARCHAR;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_UCASE,pContext))) nType = DataType::VARCHAR;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_CURRENT_DATE,pContext))) nType = DataType::DATE;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_CURRENT_TIME,pContext))) nType = DataType::TIME;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_CURRENT_TIMESTAMP,pContext))) nType = DataType::TIMESTAMP;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_CURDATE,pContext))) nType = DataType::DATE;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_DATEDIFF,pContext))) nType = DataType::INTEGER;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_DATEVALUE,pContext))) nType = DataType::DATE;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_CURTIME,pContext))) nType = DataType::TIME;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_DAYNAME,pContext))) nType = DataType::VARCHAR;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_DAYOFMONTH,pContext))) nType = DataType::INTEGER;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_DAYOFWEEK,pContext))) nType = DataType::INTEGER;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_DAYOFYEAR,pContext))) nType = DataType::INTEGER;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_EXTRACT,pContext))) nType = DataType::VARCHAR;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_HOUR,pContext))) nType = DataType::INTEGER;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_MINUTE,pContext))) nType = DataType::INTEGER;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_MONTH,pContext))) nType = DataType::INTEGER;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_MONTHNAME,pContext))) nType = DataType::VARCHAR;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_NOW,pContext))) nType = DataType::TIMESTAMP;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_QUARTER,pContext))) nType = DataType::INTEGER;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_SECOND,pContext))) nType = DataType::INTEGER;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_TIMESTAMPADD,pContext))) nType = DataType::TIMESTAMP;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_TIMESTAMPDIFF,pContext))) nType = DataType::TIMESTAMP;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_TIMEVALUE,pContext))) nType = DataType::TIMESTAMP;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_WEEK,pContext))) nType = DataType::INTEGER;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_YEAR,pContext))) nType = DataType::INTEGER;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_ABS,pContext))) nType = DataType::DOUBLE;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_ACOS,pContext))) nType = DataType::DOUBLE;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_ASIN,pContext))) nType = DataType::DOUBLE;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_ATAN,pContext))) nType = DataType::DOUBLE;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_ATAN2,pContext))) nType = DataType::DOUBLE;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_CEILING,pContext))) nType = DataType::DOUBLE;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_COS,pContext))) nType = DataType::DOUBLE;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_COT,pContext))) nType = DataType::DOUBLE;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_DEGREES,pContext))) nType = DataType::DOUBLE;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_EXP,pContext))) nType = DataType::DOUBLE;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_FLOOR,pContext))) nType = DataType::DOUBLE;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_LOGF,pContext))) nType = DataType::DOUBLE;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_LOG,pContext))) nType = DataType::DOUBLE;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_LOG10,pContext))) nType = DataType::DOUBLE;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_LN,pContext))) nType = DataType::DOUBLE;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_MOD,pContext))) nType = DataType::DOUBLE;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_PI,pContext))) nType = DataType::DOUBLE;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_POWER,pContext))) nType = DataType::DOUBLE;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_RADIANS,pContext))) nType = DataType::DOUBLE;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_RAND,pContext))) nType = DataType::DOUBLE;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_ROUND,pContext))) nType = DataType::DOUBLE;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_ROUNDMAGIC,pContext))) nType = DataType::DOUBLE;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_SIGN,pContext))) nType = DataType::DOUBLE;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_SIN,pContext))) nType = DataType::DOUBLE;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_SQRT,pContext))) nType = DataType::DOUBLE;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_TAN,pContext))) nType = DataType::DOUBLE;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_TRUNCATE,pContext))) nType = DataType::DOUBLE;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_COUNT,pContext))) nType = DataType::INTEGER;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_MAX,pContext))) nType = DataType::DOUBLE;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_MIN,pContext))) nType = DataType::DOUBLE;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_AVG,pContext))) nType = DataType::DOUBLE;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_SUM,pContext))) nType = DataType::DOUBLE;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_LOWER,pContext))) nType = DataType::VARCHAR;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_UPPER,pContext))) nType = DataType::VARCHAR;
+
+ return nType;
+}
+
+sal_Int32 OSQLParser::getFunctionParameterType(sal_uInt32 _nTokenId, sal_uInt32 _nPos)
+{
+ sal_Int32 nType = DataType::VARCHAR;
+
+ if(_nTokenId == SQL_TOKEN_CHAR) nType = DataType::INTEGER;
+ else if(_nTokenId == SQL_TOKEN_INSERT)
+ {
+ if ( _nPos == 2 || _nPos == 3 )
+ nType = DataType::INTEGER;
+ }
+ else if(_nTokenId == SQL_TOKEN_LEFT)
+ {
+ if ( _nPos == 2 )
+ nType = DataType::INTEGER;
+ }
+ else if(_nTokenId == SQL_TOKEN_LOCATE)
+ {
+ if ( _nPos == 3 )
+ nType = DataType::INTEGER;
+ }
+ else if(_nTokenId == SQL_TOKEN_LOCATE_2)
+ {
+ if ( _nPos == 3 )
+ nType = DataType::INTEGER;
+ }
+ else if( _nTokenId == SQL_TOKEN_REPEAT || _nTokenId == SQL_TOKEN_RIGHT )
+ {
+ if ( _nPos == 2 )
+ nType = DataType::INTEGER;
+ }
+ else if(_nTokenId == SQL_TOKEN_SPACE )
+ {
+ nType = DataType::INTEGER;
+ }
+ else if(_nTokenId == SQL_TOKEN_SUBSTRING)
+ {
+ if ( _nPos != 1 )
+ nType = DataType::INTEGER;
+ }
+ else if(_nTokenId == SQL_TOKEN_DATEDIFF)
+ {
+ if ( _nPos != 1 )
+ nType = DataType::TIMESTAMP;
+ }
+ else if(_nTokenId == SQL_TOKEN_DATEVALUE)
+ nType = DataType::DATE;
+ else if(_nTokenId == SQL_TOKEN_DAYNAME)
+ nType = DataType::DATE;
+ else if(_nTokenId == SQL_TOKEN_DAYOFMONTH)
+ nType = DataType::DATE;
+ else if(_nTokenId == SQL_TOKEN_DAYOFWEEK)
+ nType = DataType::DATE;
+ else if(_nTokenId == SQL_TOKEN_DAYOFYEAR)
+ nType = DataType::DATE;
+ else if(_nTokenId == SQL_TOKEN_EXTRACT) nType = DataType::VARCHAR;
+ else if(_nTokenId == SQL_TOKEN_HOUR) nType = DataType::TIME;
+ else if(_nTokenId == SQL_TOKEN_MINUTE) nType = DataType::TIME;
+ else if(_nTokenId == SQL_TOKEN_MONTH) nType = DataType::DATE;
+ else if(_nTokenId == SQL_TOKEN_MONTHNAME) nType = DataType::DATE;
+ else if(_nTokenId == SQL_TOKEN_NOW) nType = DataType::TIMESTAMP;
+ else if(_nTokenId == SQL_TOKEN_QUARTER) nType = DataType::DATE;
+ else if(_nTokenId == SQL_TOKEN_SECOND) nType = DataType::TIME;
+ else if(_nTokenId == SQL_TOKEN_TIMESTAMPADD) nType = DataType::TIMESTAMP;
+ else if(_nTokenId == SQL_TOKEN_TIMESTAMPDIFF) nType = DataType::TIMESTAMP;
+ else if(_nTokenId == SQL_TOKEN_TIMEVALUE) nType = DataType::TIMESTAMP;
+ else if(_nTokenId == SQL_TOKEN_WEEK) nType = DataType::DATE;
+ else if(_nTokenId == SQL_TOKEN_YEAR) nType = DataType::DATE;
+
+ else if(_nTokenId == SQL_TOKEN_ABS) nType = DataType::DOUBLE;
+ else if(_nTokenId == SQL_TOKEN_ACOS) nType = DataType::DOUBLE;
+ else if(_nTokenId == SQL_TOKEN_ASIN) nType = DataType::DOUBLE;
+ else if(_nTokenId == SQL_TOKEN_ATAN) nType = DataType::DOUBLE;
+ else if(_nTokenId == SQL_TOKEN_ATAN2) nType = DataType::DOUBLE;
+ else if(_nTokenId == SQL_TOKEN_CEILING) nType = DataType::DOUBLE;
+ else if(_nTokenId == SQL_TOKEN_COS) nType = DataType::DOUBLE;
+ else if(_nTokenId == SQL_TOKEN_COT) nType = DataType::DOUBLE;
+ else if(_nTokenId == SQL_TOKEN_DEGREES) nType = DataType::DOUBLE;
+ else if(_nTokenId == SQL_TOKEN_EXP) nType = DataType::DOUBLE;
+ else if(_nTokenId == SQL_TOKEN_FLOOR) nType = DataType::DOUBLE;
+ else if(_nTokenId == SQL_TOKEN_LOGF) nType = DataType::DOUBLE;
+ else if(_nTokenId == SQL_TOKEN_LOG) nType = DataType::DOUBLE;
+ else if(_nTokenId == SQL_TOKEN_LOG10) nType = DataType::DOUBLE;
+ else if(_nTokenId == SQL_TOKEN_LN) nType = DataType::DOUBLE;
+ else if(_nTokenId == SQL_TOKEN_MOD) nType = DataType::DOUBLE;
+ else if(_nTokenId == SQL_TOKEN_PI) nType = DataType::DOUBLE;
+ else if(_nTokenId == SQL_TOKEN_POWER) nType = DataType::DOUBLE;
+ else if(_nTokenId == SQL_TOKEN_RADIANS) nType = DataType::DOUBLE;
+ else if(_nTokenId == SQL_TOKEN_RAND) nType = DataType::DOUBLE;
+ else if(_nTokenId == SQL_TOKEN_ROUND) nType = DataType::DOUBLE;
+ else if(_nTokenId == SQL_TOKEN_ROUNDMAGIC) nType = DataType::DOUBLE;
+ else if(_nTokenId == SQL_TOKEN_SIGN) nType = DataType::DOUBLE;
+ else if(_nTokenId == SQL_TOKEN_SIN) nType = DataType::DOUBLE;
+ else if(_nTokenId == SQL_TOKEN_SQRT) nType = DataType::DOUBLE;
+ else if(_nTokenId == SQL_TOKEN_TAN) nType = DataType::DOUBLE;
+ else if(_nTokenId == SQL_TOKEN_TRUNCATE) nType = DataType::DOUBLE;
+ else if(_nTokenId == SQL_TOKEN_COUNT) nType = DataType::INTEGER;
+ else if(_nTokenId == SQL_TOKEN_MAX) nType = DataType::DOUBLE;
+ else if(_nTokenId == SQL_TOKEN_MIN) nType = DataType::DOUBLE;
+ else if(_nTokenId == SQL_TOKEN_AVG) nType = DataType::DOUBLE;
+ else if(_nTokenId == SQL_TOKEN_SUM) nType = DataType::DOUBLE;
+
+ else if(_nTokenId == SQL_TOKEN_LOWER) nType = DataType::VARCHAR;
+ else if(_nTokenId == SQL_TOKEN_UPPER) nType = DataType::VARCHAR;
+
+ return nType;
+}
+
+
+const SQLError& OSQLParser::getErrorHelper() const
+{
+ return m_pData->aErrors;
+}
+
+
+OSQLParseNode::Rule OSQLParseNode::getKnownRuleID() const
+{
+ if ( !isRule() )
+ return UNKNOWN_RULE;
+ return OSQLParser::RuleIDToRule( getRuleID() );
+}
+
+OUString OSQLParseNode::getTableRange(const OSQLParseNode* _pTableRef)
+{
+ OSL_ENSURE(_pTableRef && _pTableRef->count() > 1 && _pTableRef->getKnownRuleID() == OSQLParseNode::table_ref,"Invalid node give, only table ref is allowed!");
+ const sal_uInt32 nCount = _pTableRef->count();
+ OUString sTableRange;
+ if ( nCount == 2 || (nCount == 3 && !_pTableRef->getChild(0)->isToken()) )
+ {
+ const OSQLParseNode* pNode = _pTableRef->getChild(nCount - (nCount == 2 ? 1 : 2));
+ OSL_ENSURE(pNode && (pNode->getKnownRuleID() == OSQLParseNode::table_primary_as_range_column
+ || pNode->getKnownRuleID() == OSQLParseNode::range_variable)
+ ,"SQL grammar changed!");
+ if ( !pNode->isLeaf() )
+ sTableRange = pNode->getChild(1)->getTokenValue();
+ } // if ( nCount == 2 || nCount == 3 )
+
+ return sTableRange;
+}
+
+OSQLParseNodesContainer::OSQLParseNodesContainer()
+{
+}
+
+OSQLParseNodesContainer::~OSQLParseNodesContainer()
+{
+}
+
+void OSQLParseNodesContainer::push_back(OSQLParseNode* _pNode)
+{
+ std::unique_lock aGuard(m_aMutex);
+ m_aNodes.push_back(_pNode);
+}
+
+void OSQLParseNodesContainer::erase(OSQLParseNode* _pNode)
+{
+ std::unique_lock aGuard(m_aMutex);
+ if ( !m_aNodes.empty() )
+ {
+ std::vector< OSQLParseNode* >::iterator aFind = std::find(m_aNodes.begin(), m_aNodes.end(),_pNode);
+ if ( aFind != m_aNodes.end() )
+ m_aNodes.erase(aFind);
+ }
+}
+
+void OSQLParseNodesContainer::clear()
+{
+ std::unique_lock aGuard(m_aMutex);
+ m_aNodes.clear();
+}
+
+void OSQLParseNodesContainer::clearAndDelete()
+{
+ std::unique_lock aGuard(m_aMutex);
+ // clear the garbage collector
+ while ( !m_aNodes.empty() )
+ {
+ OSQLParseNode* pNode = m_aNodes[0];
+ while ( pNode->getParent() )
+ {
+ pNode = pNode->getParent();
+ }
+ aGuard.unlock(); // can call back into this object during destruction
+ delete pNode;
+ aGuard.lock();
+ }
+}
+} // namespace connectivity
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/resource/sharedresources.cxx b/connectivity/source/resource/sharedresources.cxx
new file mode 100644
index 0000000000..cc6f65e645
--- /dev/null
+++ b/connectivity/source/resource/sharedresources.cxx
@@ -0,0 +1,184 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <resource/sharedresources.hxx>
+
+#include <unotools/resmgr.hxx>
+#include <osl/diagnose.h>
+#include <osl/mutex.hxx>
+#include <sal/log.hxx>
+
+namespace connectivity
+{
+ namespace {
+
+ class SharedResources_Impl
+ {
+ private:
+ static SharedResources_Impl* s_pInstance;
+ static oslInterlockedCount s_nClients;
+
+ private:
+ std::locale m_aLocale;
+
+ public:
+ static void registerClient();
+ static void revokeClient();
+
+ static SharedResources_Impl&
+ getInstance();
+
+ OUString getResourceString(TranslateId pId) const;
+
+ private:
+ SharedResources_Impl();
+
+ static ::osl::Mutex& getMutex()
+ {
+ static ::osl::Mutex s_aMutex;
+ return s_aMutex;
+ }
+ };
+
+ }
+
+ SharedResources_Impl* SharedResources_Impl::s_pInstance( nullptr );
+ oslInterlockedCount SharedResources_Impl::s_nClients( 0 );
+
+ SharedResources_Impl::SharedResources_Impl()
+ : m_aLocale(Translate::Create("cnr"))
+ {
+ }
+
+ OUString SharedResources_Impl::getResourceString(TranslateId pId) const
+ {
+ return Translate::get(pId, m_aLocale);
+ }
+
+ void SharedResources_Impl::registerClient()
+ {
+ osl_atomic_increment( &s_nClients );
+ }
+
+ void SharedResources_Impl::revokeClient()
+ {
+ ::osl::MutexGuard aGuard( getMutex() );
+ if ( 0 == osl_atomic_decrement( &s_nClients ) )
+ {
+ delete s_pInstance;
+ s_pInstance = nullptr;
+ }
+ }
+
+
+ SharedResources_Impl& SharedResources_Impl::getInstance()
+ {
+ ::osl::MutexGuard aGuard( getMutex() );
+ OSL_ENSURE( s_nClients > 0, "SharedResources_Impl::getInstance: no active clients!" );
+
+ if ( !s_pInstance )
+ s_pInstance = new SharedResources_Impl;
+
+ return *s_pInstance;
+ }
+
+ namespace
+ {
+ bool lcl_substitute( OUString& _inout_rString,
+ const char* _pAsciiPattern, std::u16string_view _rReplace )
+ {
+ OUString oldString = _inout_rString;
+ OUString sPattern( OUString::createFromAscii( _pAsciiPattern ) );
+ _inout_rString = _inout_rString.replaceAll(sPattern, _rReplace);
+ return oldString != _inout_rString;
+ }
+ }
+
+ SharedResources::SharedResources()
+ {
+ SharedResources_Impl::registerClient();
+ }
+
+
+ SharedResources::~SharedResources()
+ {
+ SharedResources_Impl::revokeClient();
+ }
+
+
+ OUString SharedResources::getResourceString(TranslateId pResId) const
+ {
+ return SharedResources_Impl::getInstance().getResourceString(pResId);
+ }
+
+
+ OUString SharedResources::getResourceStringWithSubstitution(TranslateId pResId,
+ const char* _pAsciiPatternToReplace, const OUString& _rStringToSubstitute ) const
+ {
+ OUString sString( SharedResources_Impl::getInstance().getResourceString(pResId) );
+ if ( !lcl_substitute( sString, _pAsciiPatternToReplace, _rStringToSubstitute ) )
+ SAL_WARN("connectivity.resource", "Unable to substitute " << _pAsciiPatternToReplace << " with " << _rStringToSubstitute);
+ return sString;
+ }
+
+
+ OUString SharedResources::getResourceStringWithSubstitution(TranslateId pResId,
+ const char* _pAsciiPatternToReplace1, const OUString& _rStringToSubstitute1,
+ const char* _pAsciiPatternToReplace2, const OUString& _rStringToSubstitute2 ) const
+ {
+ OUString sString( SharedResources_Impl::getInstance().getResourceString(pResId) );
+ if( !lcl_substitute( sString, _pAsciiPatternToReplace1, _rStringToSubstitute1 ) )
+ SAL_WARN("connectivity.resource", "Unable to substitute " << _pAsciiPatternToReplace1 << " with " << _rStringToSubstitute1);
+ if( !lcl_substitute( sString, _pAsciiPatternToReplace2, _rStringToSubstitute2 ) )
+ SAL_WARN("connectivity.resource", "Unable to substitute " << _pAsciiPatternToReplace2 << " with " << _rStringToSubstitute2);
+ return sString;
+ }
+
+
+ OUString SharedResources::getResourceStringWithSubstitution(TranslateId pResId,
+ const char* _pAsciiPatternToReplace1, const OUString& _rStringToSubstitute1,
+ const char* _pAsciiPatternToReplace2, const OUString& _rStringToSubstitute2,
+ const char* _pAsciiPatternToReplace3, const OUString& _rStringToSubstitute3 ) const
+ {
+ OUString sString( SharedResources_Impl::getInstance().getResourceString(pResId) );
+ if( !lcl_substitute( sString, _pAsciiPatternToReplace1, _rStringToSubstitute1 ) )
+ SAL_WARN("connectivity.resource", "Unable to substitute " << _pAsciiPatternToReplace1 << " with " << _rStringToSubstitute1);
+ if( !lcl_substitute( sString, _pAsciiPatternToReplace2, _rStringToSubstitute2 ) )
+ SAL_WARN("connectivity.resource", "Unable to substitute " << _pAsciiPatternToReplace2 << " with " << _rStringToSubstitute2);
+ if( !lcl_substitute( sString, _pAsciiPatternToReplace3, _rStringToSubstitute3 ) )
+ SAL_WARN("connectivity.resource", "Unable to substitute " << _pAsciiPatternToReplace3 << " with " << _rStringToSubstitute3);
+ return sString;
+ }
+
+ OUString SharedResources::getResourceStringWithSubstitution(TranslateId pResId,
+ const std::vector< std::pair<const char* , OUString > >& _rStringToSubstitutes) const
+ {
+ OUString sString( SharedResources_Impl::getInstance().getResourceString(pResId) );
+ for(const auto& [rPattern, rReplace] : _rStringToSubstitutes)
+ if( !lcl_substitute( sString, rPattern, rReplace ) )
+ SAL_WARN("connectivity.resource", "Unable to substitute " << rPattern << " with " << rReplace);
+
+ return sString;
+ }
+
+
+} // namespace connectivity
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/sdbcx/VCatalog.cxx b/connectivity/source/sdbcx/VCatalog.cxx
new file mode 100644
index 0000000000..b30519fcaa
--- /dev/null
+++ b/connectivity/source/sdbcx/VCatalog.cxx
@@ -0,0 +1,211 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <comphelper/types.hxx>
+#include <sdbcx/VCatalog.hxx>
+#include <connectivity/sdbcx/VCollection.hxx>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <connectivity/sdbcx/VDescriptor.hxx>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <TConnection.hxx>
+#include <connectivity/dbtools.hxx>
+
+using namespace connectivity;
+using namespace connectivity::sdbcx;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+
+IMPLEMENT_SERVICE_INFO(OCatalog,"com.sun.star.comp.connectivity.OCatalog","com.sun.star.sdbcx.DatabaseDefinition")
+
+OCatalog::OCatalog(const Reference< XConnection> &_xConnection) : OCatalog_BASE(m_aMutex)
+{
+ try
+ {
+ m_xMetaData = _xConnection->getMetaData();
+ }
+ catch(const Exception&)
+ {
+ OSL_FAIL("No Metadata available!");
+ }
+}
+
+OCatalog::~OCatalog()
+{
+}
+
+void SAL_CALL OCatalog::disposing()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+
+ if(m_pTables)
+ m_pTables->disposing();
+ if(m_pViews)
+ m_pViews->disposing();
+ if(m_pGroups)
+ m_pGroups->disposing();
+ if(m_pUsers)
+ m_pUsers->disposing();
+
+ OCatalog_BASE::disposing();
+}
+
+// XTablesSupplier
+Reference< XNameAccess > SAL_CALL OCatalog::getTables( )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(OCatalog_BASE::rBHelper.bDisposed);
+
+ try
+ {
+ if(!m_pTables)
+ refreshTables();
+ }
+ catch( const RuntimeException& )
+ {
+ // allowed to leave this method
+ throw;
+ }
+ catch( const Exception& )
+ {
+ // allowed
+ }
+
+ return m_pTables.get();
+}
+
+// XViewsSupplier
+Reference< XNameAccess > SAL_CALL OCatalog::getViews( )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(OCatalog_BASE::rBHelper.bDisposed);
+
+ try
+ {
+ if(!m_pViews)
+ refreshViews();
+ }
+ catch( const RuntimeException& )
+ {
+ // allowed to leave this method
+ throw;
+ }
+ catch( const Exception& )
+ {
+ // allowed
+ }
+
+ return m_pViews.get();
+}
+
+// XUsersSupplier
+Reference< XNameAccess > SAL_CALL OCatalog::getUsers( )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(OCatalog_BASE::rBHelper.bDisposed);
+
+ try
+ {
+ if(!m_pUsers)
+ refreshUsers();
+ }
+ catch( const RuntimeException& )
+ {
+ // allowed to leave this method
+ throw;
+ }
+ catch( const Exception& )
+ {
+ // allowed
+ }
+
+ return m_pUsers.get();
+}
+
+// XGroupsSupplier
+Reference< XNameAccess > SAL_CALL OCatalog::getGroups( )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(OCatalog_BASE::rBHelper.bDisposed);
+
+ try
+ {
+ if(!m_pGroups)
+ refreshGroups();
+ }
+ catch( const RuntimeException& )
+ {
+ // allowed to leave this method
+ throw;
+ }
+ catch( const Exception& )
+ {
+ // allowed
+ }
+
+ return m_pGroups.get();
+}
+
+OUString OCatalog::buildName(const Reference< XRow >& _xRow)
+{
+ OUString sCatalog = _xRow->getString(1);
+ if ( _xRow->wasNull() )
+ sCatalog.clear();
+ OUString sSchema = _xRow->getString(2);
+ if ( _xRow->wasNull() )
+ sSchema.clear();
+ OUString sTable = _xRow->getString(3);
+ if ( _xRow->wasNull() )
+ sTable.clear();
+
+ OUString sComposedName(
+ ::dbtools::composeTableName( m_xMetaData, sCatalog, sSchema, sTable, false, ::dbtools::EComposeRule::InDataManipulation ) );
+ return sComposedName;
+}
+
+void OCatalog::fillNames(Reference< XResultSet >& _xResult,::std::vector< OUString>& _rNames)
+{
+ if ( _xResult.is() )
+ {
+ _rNames.reserve(20);
+ Reference< XRow > xRow(_xResult,UNO_QUERY);
+ while ( _xResult->next() )
+ {
+ _rNames.push_back( buildName(xRow) );
+ }
+ xRow.clear();
+ ::comphelper::disposeComponent(_xResult);
+ }
+}
+
+void ODescriptor::construct()
+{
+ sal_Int32 nAttrib = isNew() ? 0 : css::beans::PropertyAttribute::READONLY;
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME), PROPERTY_ID_NAME ,nAttrib,&m_Name,::cppu::UnoType<OUString>::get());
+}
+
+ODescriptor::~ODescriptor()
+{
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/sdbcx/VCollection.cxx b/connectivity/source/sdbcx/VCollection.cxx
new file mode 100644
index 0000000000..0fa6cace50
--- /dev/null
+++ b/connectivity/source/sdbcx/VCollection.cxx
@@ -0,0 +1,582 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <algorithm>
+#include <com/sun/star/container/ElementExistException.hpp>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <connectivity/sdbcx/VCollection.hxx>
+#include <connectivity/sdbcx/VDescriptor.hxx>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <connectivity/dbexception.hxx>
+#include <comphelper/enumhelper.hxx>
+#include <comphelper/types.hxx>
+#include <comphelper/property.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+#include <o3tl/unreachable.hxx>
+#include <TConnection.hxx>
+#include <strings.hrc>
+#include <resource/sharedresources.hxx>
+
+using namespace connectivity::sdbcx;
+using namespace connectivity;
+using namespace comphelper;
+using namespace ::cppu;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::util;
+
+namespace
+{
+ template < typename T> class OHardRefMap : public connectivity::sdbcx::IObjectCollection
+ {
+ typedef std::multimap< OUString, T , ::comphelper::UStringMixLess> ObjectMap;
+ typedef typename ObjectMap::iterator ObjectIter;
+ typedef typename ObjectMap::value_type ObjectEntry;
+
+ // private:
+ // this combination of map and vector is used to have a fast name and index access
+ std::vector< ObjectIter > m_aElements; // hold the iterators which point to map
+ ObjectMap m_aNameMap; // hold the elements and a name
+ public:
+ OHardRefMap(bool _bCase)
+ : m_aNameMap(_bCase)
+ {
+ }
+
+ virtual bool exists(const OUString& _sName ) override
+ {
+ return m_aNameMap.find(_sName) != m_aNameMap.end();
+ }
+
+ virtual bool empty() override
+ {
+ return m_aNameMap.empty();
+ }
+
+ virtual void swapAll() override
+ {
+ std::vector< ObjectIter >(m_aElements).swap(m_aElements);
+ ObjectMap(m_aNameMap).swap(m_aNameMap);
+ }
+
+ virtual void swap() override
+ {
+ std::vector< ObjectIter >().swap(m_aElements);
+
+ OSL_ENSURE( m_aNameMap.empty(), "swap: what did disposeElements do?" );
+ ObjectMap( m_aNameMap ).swap( m_aNameMap );
+ // Note that it's /important/ to construct the new ObjectMap from m_aNameMap before
+ // swapping. This way, it's ensured that the compare object held by these maps is preserved
+ // during the swap. If we would not do this, the UStringMixLess instance which is used would be
+ // default constructed (instead of being constructed from the same instance in m_aNameMap), and
+ // it's case-sensitive flag would have an unpredictable value.
+ }
+
+ virtual void clear() override
+ {
+ m_aElements.clear();
+ m_aNameMap.clear();
+ }
+
+ virtual void insert(const OUString& _sName,const ObjectType& _xObject) override
+ {
+ m_aElements.push_back(m_aNameMap.insert(m_aNameMap.begin(), ObjectEntry(_sName,_xObject)));
+ }
+
+ virtual void reFill(const ::std::vector< OUString> &_rVector) override
+ {
+ OSL_ENSURE(m_aNameMap.empty(),"OCollection::reFill: collection isn't empty");
+ m_aElements.reserve(_rVector.size());
+
+ for (auto const& elem : _rVector)
+ m_aElements.push_back(m_aNameMap.insert(m_aNameMap.begin(), ObjectEntry(elem,ObjectType())));
+ }
+
+ virtual bool rename(const OUString& _sOldName, const OUString& _sNewName) override
+ {
+ bool bRet = false;
+ ObjectIter aIter = m_aNameMap.find(_sOldName);
+ if ( aIter != m_aNameMap.end() )
+ {
+ typename std::vector< ObjectIter >::iterator aFind = std::find(m_aElements.begin(),m_aElements.end(),aIter);
+ if(m_aElements.end() != aFind)
+ {
+ (*aFind) = m_aNameMap.insert(m_aNameMap.begin(), ObjectEntry(_sNewName,(*aFind)->second));
+ m_aNameMap.erase(aIter);
+
+ bRet = true;
+ }
+ }
+ return bRet;
+ }
+
+ virtual sal_Int32 size() override
+ {
+ return static_cast<sal_Int32>(m_aNameMap.size());
+ }
+
+ virtual Sequence< OUString > getElementNames() override
+ {
+ Sequence< OUString > aNameList(m_aElements.size());
+
+ OUString* pStringArray = aNameList.getArray();
+ for(const auto& rIter : m_aElements)
+ {
+ *pStringArray = rIter->first;
+ ++pStringArray;
+ }
+
+ return aNameList;
+ }
+
+ virtual OUString getName(sal_Int32 _nIndex) override
+ {
+ return m_aElements[_nIndex]->first;
+ }
+
+ virtual void disposeAndErase(sal_Int32 _nIndex) override
+ {
+ OSL_ENSURE(_nIndex >= 0 && _nIndex < static_cast<sal_Int32>(m_aElements.size()),"Illegal argument!");
+ Reference<XComponent> xComp(m_aElements[_nIndex]->second.get(),UNO_QUERY);
+ ::comphelper::disposeComponent(xComp);
+ m_aElements[_nIndex]->second = T();
+
+ OUString sName = m_aElements[_nIndex]->first;
+ m_aElements.erase(m_aElements.begin()+_nIndex);
+ m_aNameMap.erase(sName);
+ }
+
+ virtual void disposeElements() override
+ {
+ for (auto & name : m_aNameMap)
+ {
+ Reference<XComponent> xComp(name.second.get(),UNO_QUERY);
+ if ( xComp.is() )
+ {
+ ::comphelper::disposeComponent(xComp);
+ name.second = T();
+ }
+ }
+ m_aElements.clear();
+ m_aNameMap.clear();
+ }
+
+ virtual sal_Int32 findColumn( const OUString& columnName ) override
+ {
+ ObjectIter aIter = m_aNameMap.find(columnName);
+ OSL_ENSURE(aIter != m_aNameMap.end(),"findColumn:: Illegal name!");
+ return m_aElements.size() - (m_aElements.end() - std::find(m_aElements.begin(),m_aElements.end(),aIter));
+ }
+
+ virtual ObjectType getObject(sal_Int32 _nIndex) override
+ {
+ OSL_ENSURE(_nIndex >= 0 && _nIndex < static_cast<sal_Int32>(m_aElements.size()),"Illegal argument!");
+ return m_aElements[_nIndex]->second;
+ }
+
+ virtual ObjectType getObject(const OUString& columnName) override
+ {
+ return m_aNameMap.find(columnName)->second;
+ }
+
+ virtual void setObject(sal_Int32 _nIndex,const ObjectType& _xObject) override
+ {
+ OSL_ENSURE(_nIndex >= 0 && _nIndex < static_cast<sal_Int32>(m_aElements.size()),"Illegal argument!");
+ m_aElements[_nIndex]->second = _xObject;
+ }
+
+ bool isCaseSensitive() const override
+ {
+ return m_aNameMap.key_comp().isCaseSensitive();
+ }
+
+ };
+}
+
+IObjectCollection::~IObjectCollection() {}
+
+IMPLEMENT_SERVICE_INFO(OCollection,"com.sun.star.sdbcx.VContainer" , "com.sun.star.sdbcx.Container")
+
+OCollection::OCollection(::cppu::OWeakObject& _rParent
+ , bool _bCase
+ , ::osl::Mutex& _rMutex
+ , const ::std::vector< OUString> &_rVector
+ , bool _bUseIndexOnly
+ , bool _bUseHardRef)
+ :m_aContainerListeners(_rMutex)
+ ,m_aRefreshListeners(_rMutex)
+ ,m_rParent(_rParent)
+ ,m_rMutex(_rMutex)
+ ,m_bUseIndexOnly(_bUseIndexOnly)
+{
+ if ( _bUseHardRef )
+ {
+ m_pElements.reset(new OHardRefMap< ObjectType >(_bCase));
+ }
+ else
+ {
+ m_pElements.reset(new OHardRefMap< WeakReference< XPropertySet> >(_bCase));
+ }
+ m_pElements->reFill(_rVector);
+}
+
+OCollection::~OCollection()
+{
+}
+
+Any SAL_CALL OCollection::queryInterface( const Type & rType )
+{
+ if ( m_bUseIndexOnly && rType == cppu::UnoType<XNameAccess>::get() )
+ {
+ return Any();
+ }
+ return OCollectionBase::queryInterface( rType );
+}
+
+Sequence< Type > SAL_CALL OCollection::getTypes()
+{
+ if ( m_bUseIndexOnly )
+ {
+ Sequence< Type > aTypes(OCollectionBase::getTypes());
+ Type* pBegin = aTypes.getArray();
+ Type* pEnd = pBegin + aTypes.getLength();
+
+ std::vector<Type> aOwnTypes;
+ aOwnTypes.reserve(aTypes.getLength());
+ Type aType = cppu::UnoType<XNameAccess>::get();
+ for(;pBegin != pEnd; ++pBegin)
+ {
+ if ( *pBegin != aType )
+ aOwnTypes.push_back(*pBegin);
+ }
+ return Sequence< Type >(aOwnTypes.data(), aOwnTypes.size());
+ }
+ return OCollectionBase::getTypes( );
+}
+
+void OCollection::clear_NoDispose()
+{
+ ::osl::MutexGuard aGuard(m_rMutex);
+
+ m_pElements->clear();
+ m_pElements->swapAll();
+}
+
+
+void OCollection::disposing()
+{
+ m_aContainerListeners.disposeAndClear(EventObject(static_cast<XTypeProvider*>(this)));
+ m_aRefreshListeners.disposeAndClear(EventObject(static_cast<XTypeProvider*>(this)));
+
+ ::osl::MutexGuard aGuard(m_rMutex);
+
+ disposeElements();
+
+ m_pElements->swap();
+}
+
+Any SAL_CALL OCollection::getByIndex( sal_Int32 Index )
+{
+ ::osl::MutexGuard aGuard(m_rMutex);
+ if (Index < 0 || Index >= m_pElements->size() )
+ throw IndexOutOfBoundsException(OUString::number(Index),static_cast<XTypeProvider*>(this));
+
+ return Any(getObject(Index));
+}
+
+Any SAL_CALL OCollection::getByName( const OUString& aName )
+{
+ ::osl::MutexGuard aGuard(m_rMutex);
+
+ if ( !m_pElements->exists(aName) )
+ {
+ ::connectivity::SharedResources aResources;
+ const OUString sError( aResources.getResourceStringWithSubstitution(
+ STR_NO_ELEMENT_NAME,
+ "$name$", aName
+ ) );
+ throw NoSuchElementException( sError, static_cast< XTypeProvider* >( this ) );
+ }
+
+ return Any(getObject(m_pElements->findColumn(aName)));
+}
+
+Sequence< OUString > SAL_CALL OCollection::getElementNames( )
+{
+ ::osl::MutexGuard aGuard(m_rMutex);
+ return m_pElements->getElementNames();
+}
+
+void SAL_CALL OCollection::refresh( )
+{
+ ::osl::MutexGuard aGuard(m_rMutex);
+
+ disposeElements();
+
+ impl_refresh();
+ EventObject aEvt(static_cast<XTypeProvider*>(this));
+ m_aRefreshListeners.notifyEach( &XRefreshListener::refreshed, aEvt );
+}
+
+void OCollection::reFill(const ::std::vector< OUString> &_rVector)
+{
+ m_pElements->reFill(_rVector);
+}
+
+// XDataDescriptorFactory
+Reference< XPropertySet > SAL_CALL OCollection::createDataDescriptor( )
+{
+ ::osl::MutexGuard aGuard(m_rMutex);
+
+ return createDescriptor();
+}
+
+OUString OCollection::getNameForObject(const ObjectType& _xObject)
+{
+ OSL_ENSURE(_xObject.is(),"OCollection::getNameForObject: Object is NULL!");
+ OUString sName;
+ _xObject->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME)) >>= sName;
+ return sName;
+}
+
+// XAppend
+void SAL_CALL OCollection::appendByDescriptor( const Reference< XPropertySet >& descriptor )
+{
+ ::osl::ClearableMutexGuard aGuard(m_rMutex);
+
+ OUString sName = getNameForObject( descriptor );
+
+ if ( m_pElements->exists(sName) )
+ throw ElementExistException(sName,static_cast<XTypeProvider*>(this));
+
+ ObjectType xNewlyCreated = appendObject( sName, descriptor );
+ if ( !xNewlyCreated.is() )
+ throw RuntimeException();
+
+ ODescriptor* pDescriptor = dynamic_cast<ODescriptor*>( xNewlyCreated.get() );
+ if ( pDescriptor )
+ pDescriptor->setNew( false );
+
+ sName = getNameForObject( xNewlyCreated );
+ if ( !m_pElements->exists( sName ) ) // this may happen when the derived class included it itself
+ m_pElements->insert( sName, xNewlyCreated );
+
+ // notify our container listeners
+ ContainerEvent aEvent(static_cast<XContainer*>(this), Any(sName), Any(xNewlyCreated), Any());
+ aGuard.clear();
+ m_aContainerListeners.notifyEach( &XContainerListener::elementInserted, aEvent );
+}
+
+// XDrop
+void SAL_CALL OCollection::dropByName( const OUString& elementName )
+{
+ ::osl::MutexGuard aGuard(m_rMutex);
+
+ if ( !m_pElements->exists(elementName) )
+ throw NoSuchElementException(elementName,static_cast<XTypeProvider*>(this));
+
+ dropImpl(m_pElements->findColumn(elementName));
+}
+
+void SAL_CALL OCollection::dropByIndex( sal_Int32 index )
+{
+ ::osl::MutexGuard aGuard(m_rMutex);
+ if(index <0 || index >= getCount())
+ throw IndexOutOfBoundsException(OUString::number(index),static_cast<XTypeProvider*>(this));
+
+ dropImpl(index);
+}
+
+void OCollection::dropImpl(sal_Int32 _nIndex, bool _bReallyDrop)
+{
+ OUString elementName = m_pElements->getName(_nIndex);
+
+ if ( _bReallyDrop )
+ dropObject(_nIndex,elementName);
+
+ m_pElements->disposeAndErase(_nIndex);
+
+ // notify our container listeners
+ notifyElementRemoved(elementName);
+}
+
+void OCollection::notifyElementRemoved(const OUString& _sName)
+{
+ ContainerEvent aEvent(static_cast<XContainer*>(this), Any(_sName), Any(), Any());
+ // note that xExistent may be empty, in case somebody removed the data source while it is not alive at this moment
+ OInterfaceIteratorHelper3 aListenerLoop(m_aContainerListeners);
+ while (aListenerLoop.hasMoreElements())
+ aListenerLoop.next()->elementRemoved(aEvent);
+}
+
+sal_Int32 SAL_CALL OCollection::findColumn( const OUString& columnName )
+{
+ if ( !m_pElements->exists(columnName) )
+ {
+ ::dbtools::throwInvalidColumnException( columnName, static_cast< XIndexAccess*>(this) );
+ O3TL_UNREACHABLE;
+ }
+
+ return m_pElements->findColumn(columnName) + 1; // because columns start at one
+}
+
+Reference< XEnumeration > SAL_CALL OCollection::createEnumeration( )
+{
+ ::osl::MutexGuard aGuard(m_rMutex);
+ return new OEnumerationByIndex( static_cast< XIndexAccess*>(this));
+}
+
+void SAL_CALL OCollection::addContainerListener( const Reference< XContainerListener >& _rxListener )
+{
+ m_aContainerListeners.addInterface(_rxListener);
+}
+
+
+void SAL_CALL OCollection::removeContainerListener( const Reference< XContainerListener >& _rxListener )
+{
+ m_aContainerListeners.removeInterface(_rxListener);
+}
+
+void SAL_CALL OCollection::acquire() noexcept
+{
+ m_rParent.acquire();
+}
+
+void SAL_CALL OCollection::release() noexcept
+{
+ m_rParent.release();
+}
+
+Type SAL_CALL OCollection::getElementType( )
+{
+ return cppu::UnoType<XPropertySet>::get();
+}
+
+sal_Bool SAL_CALL OCollection::hasElements( )
+{
+ ::osl::MutexGuard aGuard(m_rMutex);
+ return !m_pElements->empty();
+}
+
+sal_Int32 SAL_CALL OCollection::getCount( )
+{
+ ::osl::MutexGuard aGuard(m_rMutex);
+ return m_pElements->size();
+}
+
+sal_Bool SAL_CALL OCollection::hasByName( const OUString& aName )
+{
+ ::osl::MutexGuard aGuard(m_rMutex);
+ return m_pElements->exists(aName);
+}
+
+void SAL_CALL OCollection::addRefreshListener( const Reference< XRefreshListener >& l )
+{
+ m_aRefreshListeners.addInterface(l);
+}
+
+void SAL_CALL OCollection::removeRefreshListener( const Reference< XRefreshListener >& l )
+{
+ m_aRefreshListeners.removeInterface(l);
+}
+
+void OCollection::insertElement(const OUString& _sElementName,const ObjectType& _xElement)
+{
+ OSL_ENSURE(!m_pElements->exists(_sElementName),"Element already exists");
+ if ( !m_pElements->exists(_sElementName) )
+ m_pElements->insert(_sElementName,_xElement);
+}
+
+void OCollection::renameObject(const OUString& _sOldName, const OUString& _sNewName)
+{
+ OSL_ENSURE(m_pElements->exists(_sOldName),"Element doesn't exist");
+ OSL_ENSURE(!m_pElements->exists(_sNewName),"Element already exists");
+ OSL_ENSURE(!_sNewName.isEmpty(),"New name must not be empty!");
+ OSL_ENSURE(!_sOldName.isEmpty(),"Old name must not be empty!");
+
+ if ( m_pElements->rename(_sOldName,_sNewName) )
+ {
+ ContainerEvent aEvent(static_cast<XContainer*>(this), Any(_sNewName), Any(m_pElements->getObject(_sNewName)),Any(_sOldName));
+ // note that xExistent may be empty, in case somebody removed the data source while it is not alive at this moment
+ OInterfaceIteratorHelper3 aListenerLoop(m_aContainerListeners);
+ while (aListenerLoop.hasMoreElements())
+ aListenerLoop.next()->elementReplaced(aEvent);
+ }
+}
+
+ObjectType OCollection::getObject(sal_Int32 _nIndex)
+{
+ ObjectType xName = m_pElements->getObject(_nIndex);
+ if ( !xName.is() )
+ {
+ try
+ {
+ xName = createObject(m_pElements->getName(_nIndex));
+ }
+ catch(const SQLException& e)
+ {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ try
+ {
+ dropImpl(_nIndex,false);
+ }
+ catch(const Exception& )
+ {
+ }
+ throw WrappedTargetException(e.Message,static_cast<XTypeProvider*>(this),anyEx);
+ }
+ m_pElements->setObject(_nIndex,xName);
+ }
+ return xName;
+}
+
+void OCollection::disposeElements()
+{
+ m_pElements->disposeElements();
+}
+
+Reference< XPropertySet > OCollection::createDescriptor()
+{
+ OSL_FAIL("createDescriptor() needs to be overridden when used!");
+ throw SQLException();
+}
+
+ObjectType OCollection::cloneDescriptor( const ObjectType& _descriptor )
+{
+ ObjectType xNewDescriptor( createDescriptor() );
+ ::comphelper::copyProperties( _descriptor, xNewDescriptor );
+ return xNewDescriptor;
+}
+
+ObjectType OCollection::appendObject( const OUString& /*_rForName*/, const Reference< XPropertySet >& descriptor )
+{
+ return cloneDescriptor( descriptor );
+}
+
+void OCollection::dropObject(sal_Int32 /*_nPos*/, const OUString& /*_sElementName*/)
+{
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/sdbcx/VColumn.cxx b/connectivity/source/sdbcx/VColumn.cxx
new file mode 100644
index 0000000000..ad9a52ed12
--- /dev/null
+++ b/connectivity/source/sdbcx/VColumn.cxx
@@ -0,0 +1,216 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <connectivity/sdbcx/VColumn.hxx>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <comphelper/sequence.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <TConnection.hxx>
+#include <com/sun/star/sdbc/ColumnValue.hpp>
+#include <utility>
+
+using namespace connectivity;
+using namespace connectivity::sdbcx;
+using namespace cppu;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::sdbc;
+
+
+OUString SAL_CALL OColumn::getImplementationName( )
+{
+ if(isNew())
+ return "com.sun.star.sdbcx.VColumnDescriptor";
+ return "com.sun.star.sdbcx.VColumn";
+}
+
+css::uno::Sequence< OUString > SAL_CALL OColumn::getSupportedServiceNames( )
+{
+ return { isNew()?OUString("com.sun.star.sdbcx.ColumnDescriptor"):OUString("com.sun.star.sdbcx.Column") };
+}
+
+sal_Bool SAL_CALL OColumn::supportsService( const OUString& _rServiceName )
+{
+ return cppu::supportsService(this, _rServiceName);
+}
+
+OColumn::OColumn(bool _bCase)
+ :OColumnDescriptor_BASE(m_aMutex)
+ ,ODescriptor(OColumnDescriptor_BASE::rBHelper,_bCase,true)
+ ,m_IsNullable(ColumnValue::NULLABLE)
+ ,m_Precision(0)
+ ,m_Scale(0)
+ ,m_Type(0)
+ ,m_IsAutoIncrement(false)
+ ,m_IsRowVersion(false)
+ ,m_IsCurrency(false)
+{
+ construct();
+}
+
+OColumn::OColumn( const OUString& Name,
+ OUString TypeName,
+ OUString DefaultValue,
+ OUString Description,
+ sal_Int32 IsNullable,
+ sal_Int32 Precision,
+ sal_Int32 Scale,
+ sal_Int32 Type,
+ bool IsAutoIncrement,
+ bool IsRowVersion,
+ bool IsCurrency,
+ bool _bCase,
+ OUString CatalogName,
+ OUString SchemaName,
+ OUString TableName)
+ :OColumnDescriptor_BASE(m_aMutex)
+ ,ODescriptor(OColumnDescriptor_BASE::rBHelper,_bCase)
+ ,m_TypeName(std::move(TypeName))
+ ,m_Description(std::move(Description))
+ ,m_DefaultValue(std::move(DefaultValue))
+ ,m_IsNullable(IsNullable)
+ ,m_Precision(Precision)
+ ,m_Scale(Scale)
+ ,m_Type(Type)
+ ,m_IsAutoIncrement(IsAutoIncrement)
+ ,m_IsRowVersion(IsRowVersion)
+ ,m_IsCurrency(IsCurrency)
+ ,m_CatalogName(std::move(CatalogName))
+ ,m_SchemaName(std::move(SchemaName))
+ ,m_TableName(std::move(TableName))
+{
+ m_Name = Name;
+
+ construct();
+}
+
+OColumn::~OColumn()
+{
+}
+
+::cppu::IPropertyArrayHelper* OColumn::createArrayHelper( sal_Int32 /*_nId*/ ) const
+{
+ return doCreateArrayHelper();
+}
+
+::cppu::IPropertyArrayHelper& SAL_CALL OColumn::getInfoHelper()
+{
+ return *OColumn_PROP::getArrayHelper(isNew() ? 1 : 0);
+}
+
+void SAL_CALL OColumn::acquire() noexcept
+{
+ OColumnDescriptor_BASE::acquire();
+}
+
+void SAL_CALL OColumn::release() noexcept
+{
+ OColumnDescriptor_BASE::release();
+}
+
+Any SAL_CALL OColumn::queryInterface( const Type & rType )
+{
+ Any aRet = ODescriptor::queryInterface( rType);
+ if(!aRet.hasValue())
+ {
+ if(!isNew())
+ aRet = OColumn_BASE::queryInterface(rType);
+ if(!aRet.hasValue())
+ aRet = OColumnDescriptor_BASE::queryInterface( rType);
+ }
+ return aRet;
+}
+
+Sequence< Type > SAL_CALL OColumn::getTypes( )
+{
+ if(isNew())
+ return ::comphelper::concatSequences(ODescriptor::getTypes(),OColumnDescriptor_BASE::getTypes());
+
+ return ::comphelper::concatSequences(ODescriptor::getTypes(),OColumn_BASE::getTypes(),OColumnDescriptor_BASE::getTypes());
+}
+
+void OColumn::construct()
+{
+ ODescriptor::construct();
+
+ sal_Int32 nAttrib = isNew() ? 0 : PropertyAttribute::READONLY;
+
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPENAME), PROPERTY_ID_TYPENAME, nAttrib, &m_TypeName, cppu::UnoType<decltype(m_TypeName)>::get());
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DESCRIPTION), PROPERTY_ID_DESCRIPTION, nAttrib, &m_Description, cppu::UnoType<decltype(m_Description)>::get());
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DEFAULTVALUE), PROPERTY_ID_DEFAULTVALUE, nAttrib, &m_DefaultValue, cppu::UnoType<decltype(m_DefaultValue)>::get());
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PRECISION), PROPERTY_ID_PRECISION, nAttrib, &m_Precision, cppu::UnoType<decltype(m_Precision)>::get());
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE), PROPERTY_ID_TYPE, nAttrib, &m_Type, cppu::UnoType<decltype(m_Type)>::get());
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCALE), PROPERTY_ID_SCALE, nAttrib, &m_Scale, cppu::UnoType<decltype(m_Scale)>::get());
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISNULLABLE), PROPERTY_ID_ISNULLABLE, nAttrib, &m_IsNullable, cppu::UnoType<decltype(m_IsNullable)>::get());
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISAUTOINCREMENT), PROPERTY_ID_ISAUTOINCREMENT, nAttrib, &m_IsAutoIncrement, cppu::UnoType<bool>::get());
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISROWVERSION), PROPERTY_ID_ISROWVERSION, nAttrib, &m_IsRowVersion, cppu::UnoType<bool>::get());
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISCURRENCY), PROPERTY_ID_ISCURRENCY, nAttrib, &m_IsCurrency, cppu::UnoType<bool>::get());
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_CATALOGNAME), PROPERTY_ID_CATALOGNAME, nAttrib, &m_CatalogName, cppu::UnoType<decltype(m_CatalogName)>::get());
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCHEMANAME), PROPERTY_ID_SCHEMANAME, nAttrib, &m_SchemaName, cppu::UnoType<decltype(m_SchemaName)>::get());
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TABLENAME), PROPERTY_ID_TABLENAME, nAttrib, &m_TableName, cppu::UnoType<decltype(m_TableName)>::get());
+}
+
+void OColumn::disposing()
+{
+ OPropertySetHelper::disposing();
+}
+
+Reference< XPropertySet > SAL_CALL OColumn::createDataDescriptor( )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(OColumnDescriptor_BASE::rBHelper.bDisposed);
+
+ rtl::Reference<OColumn> pNewColumn = new OColumn( m_Name,
+ m_TypeName,
+ m_DefaultValue,
+ m_Description,
+ m_IsNullable,
+ m_Precision,
+ m_Scale,
+ m_Type,
+ m_IsAutoIncrement,
+ m_IsRowVersion,
+ m_IsCurrency,
+ isCaseSensitive(),
+ m_CatalogName,
+ m_SchemaName,
+ m_TableName);
+ pNewColumn->setNew(true);
+ return pNewColumn;
+}
+
+css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL OColumn::getPropertySetInfo( )
+{
+ return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper());
+}
+
+// XNamed
+OUString SAL_CALL OColumn::getName( )
+{
+ return m_Name;
+}
+
+void SAL_CALL OColumn::setName( const OUString& aName )
+{
+ m_Name = aName;
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/sdbcx/VDescriptor.cxx b/connectivity/source/sdbcx/VDescriptor.cxx
new file mode 100644
index 0000000000..c0f65c6024
--- /dev/null
+++ b/connectivity/source/sdbcx/VDescriptor.cxx
@@ -0,0 +1,105 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <connectivity/sdbcx/VDescriptor.hxx>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <comphelper/servicehelper.hxx>
+#include <cppuhelper/queryinterface.hxx>
+#include <cppuhelper/typeprovider.hxx>
+
+#include <algorithm>
+
+namespace connectivity::sdbcx
+{
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::beans;
+
+
+ // = ODescriptor
+
+
+ ODescriptor::ODescriptor(::cppu::OBroadcastHelper& _rBHelper, bool _bCase, bool _bNew)
+ :ODescriptor_PBASE(_rBHelper)
+ ,m_aCase(_bCase)
+ ,m_bNew(_bNew)
+ {
+ }
+
+
+ // css::lang::XUnoTunnel
+ namespace
+ {
+ struct ResetROAttribute
+ {
+ void operator ()( Property& _rProperty ) const
+ {
+ _rProperty.Attributes &= ~PropertyAttribute::READONLY;
+ }
+ };
+ struct SetROAttribute
+ {
+ void operator ()( Property& _rProperty ) const
+ {
+ _rProperty.Attributes |= PropertyAttribute::READONLY;
+ }
+ };
+ }
+
+
+ ::cppu::IPropertyArrayHelper* ODescriptor::doCreateArrayHelper() const
+ {
+ Sequence< Property > aProperties;
+ describeProperties( aProperties );
+
+ auto [begin, end] = asNonConstRange(aProperties);
+ if ( isNew() )
+ std::for_each( begin, end, ResetROAttribute() );
+ else
+ std::for_each( begin, end, SetROAttribute() );
+
+ return new ::cppu::OPropertyArrayHelper( aProperties );
+ }
+
+
+ bool ODescriptor::isNew( const Reference< XInterface >& _rxDescriptor )
+ {
+ ODescriptor* pImplementation = dynamic_cast<ODescriptor*>( _rxDescriptor.get() );
+ return pImplementation && pImplementation->isNew();
+ }
+
+
+ void ODescriptor::setNew(bool _bNew)
+ {
+ m_bNew = _bNew;
+ }
+
+
+ Sequence< Type > SAL_CALL ODescriptor::getTypes( )
+ {
+ ::cppu::OTypeCollection aTypes( cppu::UnoType<XMultiPropertySet>::get(),
+ cppu::UnoType<XFastPropertySet>::get(),
+ cppu::UnoType<XPropertySet>::get());
+ return aTypes.getTypes();
+ }
+
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/sdbcx/VGroup.cxx b/connectivity/source/sdbcx/VGroup.cxx
new file mode 100644
index 0000000000..73f6aa79c5
--- /dev/null
+++ b/connectivity/source/sdbcx/VGroup.cxx
@@ -0,0 +1,166 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <sdbcx/VGroup.hxx>
+#include <comphelper/sequence.hxx>
+#include <connectivity/dbexception.hxx>
+
+
+using namespace ::connectivity::sdbcx;
+using namespace ::connectivity;
+using namespace ::dbtools;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::beans;
+
+IMPLEMENT_SERVICE_INFO(OGroup,"com.sun.star.sdbcx.VGroup","com.sun.star.sdbcx.Group");
+
+OGroup::OGroup(bool _bCase) : OGroup_BASE(m_aMutex)
+ , ODescriptor(OGroup_BASE::rBHelper,_bCase)
+{
+}
+
+OGroup::OGroup(const OUString& Name, bool _bCase) : OGroup_BASE(m_aMutex)
+ ,ODescriptor(OGroup_BASE::rBHelper,_bCase)
+{
+ m_Name = Name;
+}
+
+OGroup::~OGroup()
+{
+}
+
+Any SAL_CALL OGroup::queryInterface( const Type & rType )
+{
+ Any aRet = ODescriptor::queryInterface( rType);
+ return aRet.hasValue() ? aRet : OGroup_BASE::queryInterface( rType);
+}
+
+Sequence< Type > SAL_CALL OGroup::getTypes( )
+{
+ return ::comphelper::concatSequences(ODescriptor::getTypes(),OGroup_BASE::getTypes());
+}
+
+void OGroup::disposing()
+{
+ OPropertySetHelper::disposing();
+
+ ::osl::MutexGuard aGuard(m_aMutex);
+
+ if(m_pUsers)
+ m_pUsers->disposing();
+}
+
+::cppu::IPropertyArrayHelper* OGroup::createArrayHelper( ) const
+{
+ Sequence< Property > aProps;
+ describeProperties(aProps);
+ return new ::cppu::OPropertyArrayHelper(aProps);
+}
+
+::cppu::IPropertyArrayHelper & OGroup::getInfoHelper()
+{
+ return *getArrayHelper();
+}
+
+Reference< XNameAccess > SAL_CALL OGroup::getUsers( )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(OGroup_BASE::rBHelper.bDisposed);
+
+ try
+ {
+ if ( !m_pUsers )
+ refreshUsers();
+ }
+ catch( const RuntimeException& )
+ {
+ // allowed to leave this method
+ throw;
+ }
+ catch( const Exception& )
+ {
+ // allowed
+ }
+
+ return m_pUsers.get();
+}
+
+
+sal_Int32 SAL_CALL OGroup::getPrivileges( const OUString& /*objName*/, sal_Int32 /*objType*/ )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(OGroup_BASE::rBHelper.bDisposed);
+
+ return 0;
+}
+
+sal_Int32 SAL_CALL OGroup::getGrantablePrivileges( const OUString& /*objName*/, sal_Int32 /*objType*/ )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(OGroup_BASE::rBHelper.bDisposed);
+
+ return 0;
+}
+
+void SAL_CALL OGroup::grantPrivileges( const OUString& /*objName*/, sal_Int32 /*objType*/, sal_Int32 /*objPrivileges*/ )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(OGroup_BASE::rBHelper.bDisposed);
+ throwFeatureNotImplementedSQLException( "XAuthorizable::grantPrivileges", *this );
+}
+
+void SAL_CALL OGroup::revokePrivileges( const OUString& /*objName*/, sal_Int32 /*objType*/, sal_Int32 /*objPrivileges*/ )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(OGroup_BASE::rBHelper.bDisposed);
+ throwFeatureNotImplementedSQLException( "XAuthorizable::revokePrivileges", *this );
+}
+
+css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL OGroup::getPropertySetInfo( )
+{
+ return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper());
+}
+
+OUString SAL_CALL OGroup::getName( )
+{
+ return m_Name;
+}
+
+void SAL_CALL OGroup::setName( const OUString& /*aName*/ )
+{
+ throwFeatureNotImplementedRuntimeException( "XNamed::setName", *this );
+}
+
+// XInterface
+void SAL_CALL OGroup::acquire() noexcept
+{
+ OGroup_BASE::acquire();
+}
+
+void SAL_CALL OGroup::release() noexcept
+{
+ OGroup_BASE::release();
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/sdbcx/VIndex.cxx b/connectivity/source/sdbcx/VIndex.cxx
new file mode 100644
index 0000000000..af4977765b
--- /dev/null
+++ b/connectivity/source/sdbcx/VIndex.cxx
@@ -0,0 +1,200 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdbcx/VIndex.hxx>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <connectivity/dbexception.hxx>
+#include <comphelper/sequence.hxx>
+#include <connectivity/sdbcx/VCollection.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <TConnection.hxx>
+#include <utility>
+#include <comphelper/diagnose_ex.hxx>
+
+using namespace ::connectivity;
+using namespace ::dbtools;
+using namespace ::connectivity::sdbcx;
+using namespace ::cppu;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+
+
+OUString SAL_CALL OIndex::getImplementationName( )
+{
+ if(isNew())
+ return "com.sun.star.sdbcx.VIndexDescriptor";
+ return "com.sun.star.sdbcx.VIndex";
+}
+
+css::uno::Sequence< OUString > SAL_CALL OIndex::getSupportedServiceNames( )
+{
+ return { isNew()?OUString("com.sun.star.sdbcx.IndexDescriptor"):OUString("com.sun.star.sdbcx.Index") };
+}
+
+sal_Bool SAL_CALL OIndex::supportsService( const OUString& _rServiceName )
+{
+ return cppu::supportsService(this, _rServiceName);
+}
+
+OIndex::OIndex(bool _bCase) : ODescriptor_BASE(m_aMutex)
+ , ODescriptor(ODescriptor_BASE::rBHelper,_bCase,true)
+ ,m_IsUnique(false)
+ ,m_IsPrimaryKeyIndex(false)
+ ,m_IsClustered(false)
+{
+}
+
+OIndex::OIndex( const OUString& Name,
+ OUString Catalog,
+ bool _isUnique,
+ bool _isPrimaryKeyIndex,
+ bool _isClustered,
+ bool _bCase) : ODescriptor_BASE(m_aMutex)
+ ,ODescriptor(ODescriptor_BASE::rBHelper, _bCase)
+ ,m_Catalog(std::move(Catalog))
+ ,m_IsUnique(_isUnique)
+ ,m_IsPrimaryKeyIndex(_isPrimaryKeyIndex)
+ ,m_IsClustered(_isClustered)
+{
+ m_Name = Name;
+}
+
+OIndex::~OIndex( )
+{
+}
+
+::cppu::IPropertyArrayHelper* OIndex::createArrayHelper( sal_Int32 /*_nId*/ ) const
+{
+ return doCreateArrayHelper();
+}
+
+::cppu::IPropertyArrayHelper& SAL_CALL OIndex::getInfoHelper()
+{
+ return *OIndex_PROP::getArrayHelper(isNew() ? 1 : 0);
+}
+
+Any SAL_CALL OIndex::queryInterface( const Type & rType )
+{
+ Any aRet = ODescriptor::queryInterface( rType);
+ if(!aRet.hasValue())
+ {
+ if(!isNew())
+ aRet = OIndex_BASE::queryInterface(rType);
+ if(!aRet.hasValue())
+ aRet = ODescriptor_BASE::queryInterface( rType);
+ }
+ return aRet;
+}
+
+Sequence< Type > SAL_CALL OIndex::getTypes( )
+{
+ if(isNew())
+ return ::comphelper::concatSequences(ODescriptor::getTypes(),ODescriptor_BASE::getTypes());
+ return ::comphelper::concatSequences(ODescriptor::getTypes(),ODescriptor_BASE::getTypes(),OIndex_BASE::getTypes());
+}
+
+void OIndex::construct()
+{
+ ODescriptor::construct();
+
+ sal_Int32 nAttrib = isNew() ? 0 : PropertyAttribute::READONLY;
+
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_CATALOG), PROPERTY_ID_CATALOG, nAttrib,&m_Catalog, ::cppu::UnoType<OUString>::get());
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISUNIQUE), PROPERTY_ID_ISUNIQUE, nAttrib,&m_IsUnique, cppu::UnoType<bool>::get());
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISPRIMARYKEYINDEX),PROPERTY_ID_ISPRIMARYKEYINDEX, nAttrib,&m_IsPrimaryKeyIndex, cppu::UnoType<bool>::get());
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISCLUSTERED), PROPERTY_ID_ISCLUSTERED, nAttrib,&m_IsClustered, cppu::UnoType<bool>::get());
+}
+
+void OIndex::disposing()
+{
+ OPropertySetHelper::disposing();
+
+ ::osl::MutexGuard aGuard(m_aMutex);
+
+ if(m_pColumns)
+ m_pColumns->disposing();
+}
+
+Reference< css::container::XNameAccess > SAL_CALL OIndex::getColumns( )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(ODescriptor_BASE::rBHelper.bDisposed);
+
+ try
+ {
+ if ( !m_pColumns )
+ refreshColumns();
+ }
+ catch( const RuntimeException& )
+ {
+ // allowed to leave this method
+ throw;
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "connectivity.commontools", "OIndex::getColumns" );
+ }
+
+ return m_pColumns.get();
+}
+
+Reference< XPropertySet > SAL_CALL OIndex::createDataDescriptor( )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(ODescriptor_BASE::rBHelper.bDisposed);
+
+
+ return this;
+}
+
+css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL OIndex::getPropertySetInfo( )
+{
+ return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper());
+}
+
+OUString SAL_CALL OIndex::getName( )
+{
+ return m_Name;
+}
+
+void SAL_CALL OIndex::setName( const OUString& /*aName*/ )
+{
+}
+
+// XInterface
+void SAL_CALL OIndex::acquire() noexcept
+{
+ ODescriptor_BASE::acquire();
+}
+
+void SAL_CALL OIndex::release() noexcept
+{
+ ODescriptor_BASE::release();
+}
+
+void OIndex::refreshColumns()
+{
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/sdbcx/VIndexColumn.cxx b/connectivity/source/sdbcx/VIndexColumn.cxx
new file mode 100644
index 0000000000..edd1ea93e9
--- /dev/null
+++ b/connectivity/source/sdbcx/VIndexColumn.cxx
@@ -0,0 +1,102 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdbcx/VIndexColumn.hxx>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <cppuhelper/supportsservice.hxx>
+#include <TConnection.hxx>
+
+using namespace connectivity;
+using namespace connectivity::sdbcx;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::uno;
+
+OUString SAL_CALL OIndexColumn::getImplementationName( )
+{
+ if(isNew())
+ return "com.sun.star.sdbcx.VIndexColumnDescriptor";
+ return "com.sun.star.sdbcx.VIndexColumn";
+}
+
+css::uno::Sequence< OUString > SAL_CALL OIndexColumn::getSupportedServiceNames( )
+{
+ return { isNew()?OUString("com.sun.star.sdbcx.IndexColumnDescriptor"):OUString("com.sun.star.sdbcx.IndexColumn") };
+}
+
+sal_Bool SAL_CALL OIndexColumn::supportsService( const OUString& _rServiceName )
+{
+ return cppu::supportsService(this, _rServiceName);
+}
+
+OIndexColumn::OIndexColumn(bool _bCase) : OColumn(_bCase), m_IsAscending(true)
+{
+ construct();
+}
+
+
+OIndexColumn::OIndexColumn( bool IsAscending,
+ const OUString& Name,
+ const OUString& TypeName,
+ const OUString& DefaultValue,
+ sal_Int32 IsNullable,
+ sal_Int32 Precision,
+ sal_Int32 Scale,
+ sal_Int32 Type,
+ bool _bCase,
+ const OUString& CatalogName,
+ const OUString& SchemaName,
+ const OUString& TableName
+ ) : OColumn(Name,
+ TypeName,
+ DefaultValue,
+ OUString(),
+ IsNullable,
+ Precision,
+ Scale,
+ Type,
+ false/*IsAutoIncrement*/,
+ false/*IsRowVersion*/,
+ false/*IsCurrency*/,
+ _bCase,
+ CatalogName,
+ SchemaName,
+ TableName)
+ , m_IsAscending(IsAscending)
+{
+ construct();
+}
+
+::cppu::IPropertyArrayHelper* OIndexColumn::createArrayHelper( sal_Int32 /*_nId*/ ) const
+{
+ return doCreateArrayHelper();
+}
+
+::cppu::IPropertyArrayHelper& SAL_CALL OIndexColumn::getInfoHelper()
+{
+ return *OIndexColumn_PROP::getArrayHelper(isNew() ? 1 : 0);
+}
+
+void OIndexColumn::construct()
+{
+ sal_Int32 nAttrib = isNew() ? 0 : PropertyAttribute::READONLY;
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISASCENDING), PROPERTY_ID_ISASCENDING, nAttrib,&m_IsAscending, cppu::UnoType<bool>::get());
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/sdbcx/VKey.cxx b/connectivity/source/sdbcx/VKey.cxx
new file mode 100644
index 0000000000..2cf7bceb4d
--- /dev/null
+++ b/connectivity/source/sdbcx/VKey.cxx
@@ -0,0 +1,203 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdbcx/VKey.hxx>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/sdbc/KeyRule.hpp>
+#include <comphelper/sequence.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <connectivity/sdbcx/VCollection.hxx>
+#include <TConnection.hxx>
+#include <utility>
+
+using namespace connectivity;
+using namespace connectivity::sdbcx;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+
+
+OUString SAL_CALL OKey::getImplementationName( )
+{
+ if(isNew())
+ return "com.sun.star.sdbcx.VKeyDescriptor";
+ return "com.sun.star.sdbcx.VKey";
+}
+
+css::uno::Sequence< OUString > SAL_CALL OKey::getSupportedServiceNames( )
+{
+ return { isNew()?OUString("com.sun.star.sdbcx.KeyDescriptor"):OUString("com.sun.star.sdbcx.Key") };
+}
+
+sal_Bool SAL_CALL OKey::supportsService( const OUString& _rServiceName )
+{
+ return cppu::supportsService(this, _rServiceName);
+}
+
+OKey::OKey(bool _bCase) : ODescriptor_BASE(m_aMutex)
+ , ODescriptor(ODescriptor_BASE::rBHelper, _bCase, true)
+ , m_aProps(std::make_shared<KeyProperties>())
+{
+}
+
+OKey::OKey(const OUString& Name,std::shared_ptr<KeyProperties> _xProps, bool _bCase)
+: ODescriptor_BASE(m_aMutex)
+ ,ODescriptor(ODescriptor_BASE::rBHelper, _bCase)
+ ,m_aProps(std::move(_xProps))
+{
+ m_Name = Name;
+}
+//OKey::OKey( const OUString& _Name,
+// const OUString& _ReferencedTable,
+// sal_Int32 _Type,
+// sal_Int32 _UpdateRule,
+// sal_Int32 _DeleteRule,
+// sal_Bool _bCase) : ODescriptor_BASE(m_aMutex)
+// ,ODescriptor(ODescriptor_BASE::rBHelper,_bCase)
+// ,m_ReferencedTable(_ReferencedTable)
+// ,m_Type(_Type)
+// ,m_UpdateRule(_UpdateRule)
+// ,m_DeleteRule(_DeleteRule)
+// ,m_pColumns(NULL)
+//{
+// m_Name = _Name;
+//}
+
+OKey::~OKey( )
+{
+}
+
+Any SAL_CALL OKey::queryInterface( const Type & rType )
+{
+ Any aRet = ODescriptor::queryInterface( rType);
+ if(!aRet.hasValue())
+ {
+ if(!isNew())
+ aRet = OKey_BASE::queryInterface(rType);
+ if(!aRet.hasValue())
+ aRet = ODescriptor_BASE::queryInterface( rType);
+ }
+
+ return aRet;
+}
+
+Sequence< Type > SAL_CALL OKey::getTypes( )
+{
+ if(isNew())
+ return ::comphelper::concatSequences(ODescriptor::getTypes(),ODescriptor_BASE::getTypes());
+
+ return ::comphelper::concatSequences(ODescriptor::getTypes(),ODescriptor_BASE::getTypes(),OKey_BASE::getTypes());
+}
+
+void OKey::construct()
+{
+ ODescriptor::construct();
+
+ sal_Int32 nAttrib = isNew() ? 0 : PropertyAttribute::READONLY;
+
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_REFERENCEDTABLE), PROPERTY_ID_REFERENCEDTABLE, nAttrib,&m_aProps->m_ReferencedTable, ::cppu::UnoType<OUString>::get());
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE), PROPERTY_ID_TYPE, nAttrib,&m_aProps->m_Type, ::cppu::UnoType<sal_Int32>::get());
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_UPDATERULE), PROPERTY_ID_UPDATERULE, nAttrib,&m_aProps->m_UpdateRule, ::cppu::UnoType<sal_Int32>::get());
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DELETERULE), PROPERTY_ID_DELETERULE, nAttrib,&m_aProps->m_DeleteRule, ::cppu::UnoType<sal_Int32>::get());
+}
+
+void SAL_CALL OKey::disposing()
+{
+ OPropertySetHelper::disposing();
+
+ ::osl::MutexGuard aGuard(m_aMutex);
+
+ if(m_pColumns)
+ m_pColumns->disposing();
+
+ ODescriptor_BASE::disposing();
+}
+
+::cppu::IPropertyArrayHelper* OKey::createArrayHelper( sal_Int32 /*_nId*/ ) const
+{
+ return doCreateArrayHelper();
+}
+
+::cppu::IPropertyArrayHelper & OKey::getInfoHelper()
+{
+ return *getArrayHelper(isNew() ? 1 : 0);
+}
+
+Reference< css::container::XNameAccess > SAL_CALL OKey::getColumns( )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(ODescriptor_BASE::rBHelper.bDisposed);
+
+ try
+ {
+ if ( !m_pColumns )
+ refreshColumns();
+ }
+ catch( const RuntimeException& )
+ {
+ // allowed to leave this method
+ throw;
+ }
+ catch( const Exception& )
+ {
+ // allowed
+ }
+
+ return m_pColumns.get();
+}
+
+Reference< XPropertySet > SAL_CALL OKey::createDataDescriptor( )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(ODescriptor_BASE::rBHelper.bDisposed);
+
+
+ return this;
+}
+
+css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL OKey::getPropertySetInfo( )
+{
+ return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper());
+}
+
+OUString SAL_CALL OKey::getName( )
+{
+ return m_Name;
+}
+
+void SAL_CALL OKey::setName( const OUString& /*aName*/ )
+{
+}
+
+// XInterface
+void SAL_CALL OKey::acquire() noexcept
+{
+ ODescriptor_BASE::acquire();
+}
+
+void SAL_CALL OKey::release() noexcept
+{
+ ODescriptor_BASE::release();
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/sdbcx/VKeyColumn.cxx b/connectivity/source/sdbcx/VKeyColumn.cxx
new file mode 100644
index 0000000000..e22620fb59
--- /dev/null
+++ b/connectivity/source/sdbcx/VKeyColumn.cxx
@@ -0,0 +1,107 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdbcx/VKeyColumn.hxx>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <cppuhelper/supportsservice.hxx>
+#include <TConnection.hxx>
+#include <utility>
+
+using namespace connectivity;
+using namespace connectivity::sdbcx;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::uno;
+using namespace cppu;
+
+OUString SAL_CALL OKeyColumn::getImplementationName( )
+{
+ if(isNew())
+ return "com.sun.star.sdbcx.VKeyColumnDescriptor";
+ return "com.sun.star.sdbcx.VKeyColumn";
+}
+
+css::uno::Sequence< OUString > SAL_CALL OKeyColumn::getSupportedServiceNames( )
+{
+ return { isNew()?OUString("com.sun.star.sdbcx.KeyColumnDescriptor"):OUString("com.sun.star.sdbcx.KeyColumn") };
+}
+
+sal_Bool SAL_CALL OKeyColumn::supportsService( const OUString& _rServiceName )
+{
+ return cppu::supportsService(this, _rServiceName);
+}
+
+OKeyColumn::OKeyColumn(bool _bCase) : OColumn(_bCase)
+{
+ construct();
+}
+
+OKeyColumn::OKeyColumn( OUString ReferencedColumn,
+ const OUString& Name,
+ const OUString& TypeName,
+ const OUString& DefaultValue,
+ sal_Int32 IsNullable,
+ sal_Int32 Precision,
+ sal_Int32 Scale,
+ sal_Int32 Type,
+ bool _bCase,
+ const OUString& CatalogName,
+ const OUString& SchemaName,
+ const OUString& TableName
+ ) : OColumn(Name,
+ TypeName,
+ DefaultValue,
+ OUString(),
+ IsNullable,
+ Precision,
+ Scale,
+ Type,
+ false/*IsAutoIncrement*/,
+ false/*IsRowVersion*/,
+ false/*IsCurrency*/,
+ _bCase,
+ CatalogName,
+ SchemaName,
+ TableName)
+ , m_ReferencedColumn(std::move(ReferencedColumn))
+{
+ construct();
+}
+
+OKeyColumn::~OKeyColumn()
+{
+}
+
+::cppu::IPropertyArrayHelper* OKeyColumn::createArrayHelper( sal_Int32 /*_nId*/ ) const
+{
+ return doCreateArrayHelper();
+}
+
+::cppu::IPropertyArrayHelper& SAL_CALL OKeyColumn::getInfoHelper()
+{
+ return *OKeyColumn_PROP::getArrayHelper(isNew() ? 1 : 0);
+}
+
+void OKeyColumn::construct()
+{
+ sal_Int32 nAttrib = isNew() ? 0 : PropertyAttribute::READONLY;
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RELATEDCOLUMN), PROPERTY_ID_RELATEDCOLUMN, nAttrib,&m_ReferencedColumn, ::cppu::UnoType<OUString>::get());
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/sdbcx/VTable.cxx b/connectivity/source/sdbcx/VTable.cxx
new file mode 100644
index 0000000000..f569d01bae
--- /dev/null
+++ b/connectivity/source/sdbcx/VTable.cxx
@@ -0,0 +1,305 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <connectivity/sdbcx/VTable.hxx>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <comphelper/sequence.hxx>
+#include <connectivity/sdbcx/VCollection.hxx>
+#include <TConnection.hxx>
+#include <connectivity/dbtools.hxx>
+#include <connectivity/dbexception.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <utility>
+
+using namespace ::connectivity;
+using namespace ::connectivity::sdbcx;
+using namespace ::dbtools;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+
+
+OUString SAL_CALL OTable::getImplementationName( )
+{
+ if(isNew())
+ return "com.sun.star.sdbcx.VTableDescriptor";
+ return "com.sun.star.sdbcx.Table";
+}
+
+
+css::uno::Sequence< OUString > SAL_CALL OTable::getSupportedServiceNames( )
+{
+ return { isNew()?OUString("com.sun.star.sdbcx.TableDescriptor"):OUString("com.sun.star.sdbcx.Table") };
+}
+
+sal_Bool SAL_CALL OTable::supportsService( const OUString& _rServiceName )
+{
+ return cppu::supportsService(this, _rServiceName);
+}
+
+OTable::OTable(OCollection* _pTables,
+ bool _bCase)
+ : OTableDescriptor_BASE(m_aMutex)
+ ,ODescriptor(OTableDescriptor_BASE::rBHelper,_bCase,true)
+ ,m_pTables(_pTables)
+{
+}
+
+OTable::OTable( OCollection* _pTables,
+ bool _bCase,
+ const OUString& Name, OUString Type,
+ OUString Description, OUString SchemaName,
+ OUString CatalogName) : OTableDescriptor_BASE(m_aMutex)
+ ,ODescriptor(OTableDescriptor_BASE::rBHelper,_bCase)
+ ,m_CatalogName(std::move(CatalogName))
+ ,m_SchemaName(std::move(SchemaName))
+ ,m_Description(std::move(Description))
+ ,m_Type(std::move(Type))
+ ,m_pTables(_pTables)
+{
+ m_Name = Name;
+}
+
+OTable::~OTable()
+{
+}
+
+void OTable::construct()
+{
+ ODescriptor::construct();
+
+ sal_Int32 nAttrib = isNew() ? 0 : PropertyAttribute::READONLY;
+
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_CATALOGNAME), PROPERTY_ID_CATALOGNAME,nAttrib,&m_CatalogName, ::cppu::UnoType<OUString>::get());
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCHEMANAME), PROPERTY_ID_SCHEMANAME, nAttrib,&m_SchemaName, ::cppu::UnoType<OUString>::get());
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DESCRIPTION), PROPERTY_ID_DESCRIPTION,nAttrib,&m_Description, ::cppu::UnoType<OUString>::get());
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE), PROPERTY_ID_TYPE, nAttrib,&m_Type, ::cppu::UnoType<OUString>::get());
+}
+
+void SAL_CALL OTable::acquire() noexcept
+{
+ OTableDescriptor_BASE::acquire();
+}
+
+void SAL_CALL OTable::release() noexcept
+{
+ OTableDescriptor_BASE::release();
+}
+
+
+Any SAL_CALL OTable::queryInterface( const Type & rType )
+{
+ Any aRet = ODescriptor::queryInterface( rType);
+ if(!aRet.hasValue())
+ {
+ if(!isNew())
+ aRet = OTable_BASE::queryInterface( rType);
+ if(isNew() && (rType == cppu::UnoType<XIndexesSupplier>::get()))
+ return Any();
+ if(!aRet.hasValue())
+ aRet = OTableDescriptor_BASE::queryInterface( rType);
+ }
+ return aRet;
+}
+
+Sequence< Type > SAL_CALL OTable::getTypes( )
+{
+ if(isNew())
+ return ::comphelper::concatSequences(ODescriptor::getTypes(),OTableDescriptor_BASE::getTypes());
+ return ::comphelper::concatSequences(ODescriptor::getTypes(),OTableDescriptor_BASE::getTypes(),OTable_BASE::getTypes());
+}
+
+void SAL_CALL OTable::disposing()
+{
+ ODescriptor::disposing();
+
+ ::osl::MutexGuard aGuard(m_aMutex);
+
+ if(m_xKeys)
+ m_xKeys->disposing();
+ if(m_xColumns)
+ m_xColumns->disposing();
+ if(m_xIndexes)
+ m_xIndexes->disposing();
+
+ m_pTables = nullptr;
+}
+
+// XColumnsSupplier
+Reference< XNameAccess > SAL_CALL OTable::getColumns( )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(OTableDescriptor_BASE::rBHelper.bDisposed);
+
+ try
+ {
+ if ( !m_xColumns )
+ refreshColumns();
+ }
+ catch( const RuntimeException& )
+ {
+ // allowed to leave this method
+ throw;
+ }
+ catch( const Exception& )
+ {
+ // allowed
+ }
+
+ return m_xColumns.get();
+}
+
+
+// XKeysSupplier
+Reference< XIndexAccess > SAL_CALL OTable::getKeys( )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(OTableDescriptor_BASE::rBHelper.bDisposed);
+
+ Reference< XIndexAccess > xKeys;
+
+ try
+ {
+ if ( !m_xKeys )
+ refreshKeys();
+ xKeys = m_xKeys.get();
+ }
+ catch( const RuntimeException& )
+ {
+ // allowed to leave this method
+ throw;
+ }
+ catch( const Exception& )
+ {
+ // allowed
+ }
+
+ return xKeys;
+}
+
+cppu::IPropertyArrayHelper* OTable::createArrayHelper( sal_Int32 /*_nId*/ ) const
+{
+ return doCreateArrayHelper();
+}
+
+cppu::IPropertyArrayHelper & OTable::getInfoHelper()
+{
+ return *getArrayHelper(isNew() ? 1 : 0);
+}
+
+Reference< XPropertySet > SAL_CALL OTable::createDataDescriptor( )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(OTableDescriptor_BASE::rBHelper.bDisposed);
+
+ rtl::Reference<OTable> pTable = new OTable(m_pTables,isCaseSensitive(),m_Name,m_Type,m_Description,m_SchemaName,m_CatalogName);
+ pTable->setNew(true);
+ return pTable;
+}
+
+// XIndexesSupplier
+Reference< XNameAccess > SAL_CALL OTable::getIndexes( )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(OTableDescriptor_BASE::rBHelper.bDisposed);
+
+ try
+ {
+ if ( !m_xIndexes )
+ refreshIndexes();
+ }
+ catch( const RuntimeException& )
+ {
+ // allowed to leave this method
+ throw;
+ }
+ catch( const Exception& )
+ {
+ // allowed
+ }
+
+ return m_xIndexes.get();
+}
+
+// XRename
+void SAL_CALL OTable::rename( const OUString& newName )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(OTableDescriptor_BASE::rBHelper.bDisposed);
+
+ const OUString sOldComposedName = getName();
+ const Reference< XDatabaseMetaData> xMetaData = getMetaData();
+ if ( xMetaData.is() )
+ ::dbtools::qualifiedNameComponents(xMetaData,newName,m_CatalogName,m_SchemaName,m_Name,::dbtools::EComposeRule::InDataManipulation);
+ else
+ m_Name = newName;
+
+ m_pTables->renameObject(sOldComposedName,newName);
+}
+
+Reference< XDatabaseMetaData> OTable::getMetaData() const
+{
+ return nullptr;
+}
+
+// XAlterTable
+void SAL_CALL OTable::alterColumnByName( const OUString& /*colName*/, const Reference< XPropertySet >& /*descriptor*/ )
+{
+ throwFeatureNotImplementedSQLException( "XAlterTable::alterColumnByName", *this );
+}
+
+void SAL_CALL OTable::alterColumnByIndex( sal_Int32 /*index*/, const Reference< XPropertySet >& /*descriptor*/ )
+{
+ throwFeatureNotImplementedSQLException( "XAlterTable::alterColumnByIndex", *this );
+}
+
+css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL OTable::getPropertySetInfo( )
+{
+ return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper());
+}
+
+OUString SAL_CALL OTable::getName()
+{
+ // this is only correct for tables who haven't a schema or catalog name
+ OSL_ENSURE(m_CatalogName.isEmpty(),"getName(): forgot to override getName()!");
+ OSL_ENSURE(m_SchemaName.isEmpty(),"getName(): forgot to override getName()!");
+ return m_Name;
+}
+
+void SAL_CALL OTable::setName( const OUString& /*aName*/ )
+{
+}
+
+void OTable::refreshColumns()
+{
+}
+
+void OTable::refreshKeys()
+{
+}
+
+void OTable::refreshIndexes()
+{
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/sdbcx/VUser.cxx b/connectivity/source/sdbcx/VUser.cxx
new file mode 100644
index 0000000000..51d05b9387
--- /dev/null
+++ b/connectivity/source/sdbcx/VUser.cxx
@@ -0,0 +1,175 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <sdbcx/VUser.hxx>
+#include <connectivity/sdbcx/VCollection.hxx>
+#include <connectivity/dbexception.hxx>
+#include <comphelper/sequence.hxx>
+#include <o3tl/unreachable.hxx>
+
+
+using namespace connectivity;
+using namespace connectivity::sdbcx;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+
+IMPLEMENT_SERVICE_INFO(OUser,"com.sun.star.sdbcx.VUser","com.sun.star.sdbcx.User");
+
+OUser::OUser(bool _bCase) : OUser_BASE(m_aMutex)
+ , ODescriptor(OUser_BASE::rBHelper,_bCase,true)
+{
+}
+
+OUser::OUser(const OUString& Name, bool _bCase) : OUser_BASE(m_aMutex)
+ ,ODescriptor(OUser_BASE::rBHelper,_bCase)
+{
+ m_Name = Name;
+}
+
+OUser::~OUser( )
+{
+}
+
+void OUser::disposing()
+{
+ OPropertySetHelper::disposing();
+ ::osl::MutexGuard aGuard(m_aMutex);
+ if(m_pGroups)
+ m_pGroups->disposing();
+}
+
+Any SAL_CALL OUser::queryInterface( const Type & rType )
+{
+ Any aRet = ODescriptor::queryInterface( rType);
+ return aRet.hasValue() ? aRet : OUser_BASE::queryInterface( rType);
+}
+
+Sequence< Type > SAL_CALL OUser::getTypes( )
+{
+ return ::comphelper::concatSequences(ODescriptor::getTypes(),OUser_BASE::getTypes());
+}
+
+::cppu::IPropertyArrayHelper* OUser::createArrayHelper( ) const
+{
+ Sequence< Property > aProps;
+ describeProperties(aProps);
+ return new ::cppu::OPropertyArrayHelper(aProps);
+
+}
+
+::cppu::IPropertyArrayHelper & OUser::getInfoHelper()
+{
+ return *getArrayHelper();
+}
+
+// XUser
+void SAL_CALL OUser::changePassword( const OUString& /*objPassword*/, const OUString& /*newPassword*/ )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(OUser_BASE::rBHelper.bDisposed);
+ ::dbtools::throwFeatureNotImplementedSQLException( "XUser::changePassword", *this );
+}
+
+// XGroupsSupplier
+Reference< XNameAccess > SAL_CALL OUser::getGroups( )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(OUser_BASE::rBHelper.bDisposed);
+
+ try
+ {
+ if ( !m_pGroups )
+ refreshGroups();
+ }
+ catch( const RuntimeException& )
+ {
+ // allowed to leave this method
+ throw;
+ }
+ catch( const Exception& )
+ {
+ // allowed
+ }
+
+ return m_pGroups.get();
+}
+
+sal_Int32 SAL_CALL OUser::getPrivileges( const OUString& /*objName*/, sal_Int32 /*objType*/ )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(OUser_BASE::rBHelper.bDisposed);
+ ::dbtools::throwFeatureNotImplementedSQLException( "XAuthorizable::changePassword", *this );
+ O3TL_UNREACHABLE;
+}
+
+sal_Int32 SAL_CALL OUser::getGrantablePrivileges( const OUString& /*objName*/, sal_Int32 /*objType*/ )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(OUser_BASE::rBHelper.bDisposed);
+ ::dbtools::throwFeatureNotImplementedSQLException( "XAuthorizable::getGrantablePrivileges", *this );
+ O3TL_UNREACHABLE;
+}
+
+void SAL_CALL OUser::grantPrivileges( const OUString& /*objName*/, sal_Int32 /*objType*/, sal_Int32 /*objPrivileges*/ )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(OUser_BASE::rBHelper.bDisposed);
+ ::dbtools::throwFeatureNotImplementedSQLException( "XAuthorizable::grantPrivileges", *this );
+}
+
+void SAL_CALL OUser::revokePrivileges( const OUString& /*objName*/, sal_Int32 /*objType*/, sal_Int32 /*objPrivileges*/ )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(OUser_BASE::rBHelper.bDisposed);
+ ::dbtools::throwFeatureNotImplementedSQLException( "XAuthorizable::revokePrivileges", *this );
+}
+
+css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL OUser::getPropertySetInfo( )
+{
+ return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper());
+}
+
+OUString SAL_CALL OUser::getName( )
+{
+ return m_Name;
+}
+
+void SAL_CALL OUser::setName( const OUString& /*aName*/ )
+{
+ OSL_FAIL( "OUser::setName: not implemented!" );
+ // not allowed to throw an SQLException here ...
+}
+
+// XInterface
+void SAL_CALL OUser::acquire() noexcept
+{
+ OUser_BASE::acquire();
+}
+
+void SAL_CALL OUser::release() noexcept
+{
+ OUser_BASE::release();
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/sdbcx/VView.cxx b/connectivity/source/sdbcx/VView.cxx
new file mode 100644
index 0000000000..aa016c0e58
--- /dev/null
+++ b/connectivity/source/sdbcx/VView.cxx
@@ -0,0 +1,133 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <connectivity/sdbcx/VView.hxx>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <comphelper/sequence.hxx>
+#include <connectivity/dbtools.hxx>
+#include <TConnection.hxx>
+#include <utility>
+
+
+using namespace connectivity;
+using namespace connectivity::sdbcx;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+
+IMPLEMENT_SERVICE_INFO(OView,"com.sun.star.sdbcx.VView","com.sun.star.sdbcx.View");
+
+OView::OView(bool _bCase,
+ const OUString& Name,
+ css::uno::Reference< css::sdbc::XDatabaseMetaData > _xMetaData,
+ OUString Command,
+ OUString SchemaName,
+ OUString CatalogName) : ODescriptor(::comphelper::OMutexAndBroadcastHelper::m_aBHelper,_bCase)
+ ,m_CatalogName(std::move(CatalogName))
+ ,m_SchemaName(std::move(SchemaName))
+ ,m_Command(std::move(Command))
+ ,m_CheckOption(0)
+ ,m_xMetaData(std::move(_xMetaData))
+
+{
+ m_Name = Name;
+ construct();
+}
+
+OView::OView(bool _bCase, css::uno::Reference< css::sdbc::XDatabaseMetaData > _xMetaData)
+ : ODescriptor(::comphelper::OMutexAndBroadcastHelper::m_aBHelper, _bCase, true)
+ ,m_xMetaData(std::move(_xMetaData))
+{
+ construct();
+}
+
+OView::~OView()
+{
+}
+
+void OView::construct()
+{
+ ODescriptor::construct();
+
+ sal_Int32 nAttrib = isNew() ? 0 : PropertyAttribute::READONLY;
+
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_CATALOGNAME), PROPERTY_ID_CATALOGNAME,nAttrib,&m_CatalogName, ::cppu::UnoType<OUString>::get());
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCHEMANAME), PROPERTY_ID_SCHEMANAME, nAttrib,&m_SchemaName, ::cppu::UnoType<OUString>::get());
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_COMMAND), PROPERTY_ID_COMMAND, nAttrib,&m_Command, ::cppu::UnoType<OUString>::get());
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_CHECKOPTION), PROPERTY_ID_CHECKOPTION,nAttrib,&m_CheckOption, ::cppu::UnoType<sal_Int32>::get());
+}
+
+Sequence< Type > SAL_CALL OView::getTypes( )
+{
+ return ::comphelper::concatSequences(ODescriptor::getTypes(),OView_BASE::getTypes());
+}
+
+Any SAL_CALL OView::queryInterface( const Type & rType )
+{
+ Any aRet = OView_BASE::queryInterface( rType);
+ return aRet.hasValue() ? aRet : ODescriptor::queryInterface( rType);
+}
+
+::cppu::IPropertyArrayHelper* OView::createArrayHelper( sal_Int32 /*_nId*/ ) const
+{
+ return doCreateArrayHelper();
+}
+
+::cppu::IPropertyArrayHelper & OView::getInfoHelper()
+{
+ return *getArrayHelper(isNew() ? 1 : 0);
+}
+
+OUString SAL_CALL OView::getName()
+{
+ OUString sComposedName;
+ if(m_xMetaData.is())
+ sComposedName = ::dbtools::composeTableName( m_xMetaData, m_CatalogName, m_SchemaName, m_Name, false, ::dbtools::EComposeRule::InDataManipulation );
+ else
+ {
+ Any aValue;
+ getFastPropertyValue(aValue,PROPERTY_ID_NAME);
+ aValue >>= sComposedName;
+ }
+ return sComposedName;
+}
+
+css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL OView::getPropertySetInfo( )
+{
+ return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper());
+}
+
+void SAL_CALL OView::setName( const OUString& )
+{
+}
+
+void SAL_CALL OView::acquire() noexcept
+{
+ OView_BASE::acquire();
+}
+
+void SAL_CALL OView::release() noexcept
+{
+ OView_BASE::release();
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/workben/iniParser/main.cxx b/connectivity/workben/iniParser/main.cxx
new file mode 100644
index 0000000000..c4746fceec
--- /dev/null
+++ b/connectivity/workben/iniParser/main.cxx
@@ -0,0 +1,160 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <rtl/ustring.hxx>
+#include <sal/log.hxx>
+#include <com/sun/star/io/IOException.hpp>
+#include <osl/process.h>
+
+#include <map>
+#include <vector>
+
+
+struct ini_NameValue
+{
+ OUString sName;
+ OUString sValue;
+
+ inline ini_NameValue()
+ {}
+ inline ini_NameValue(
+ OUString const & name, OUString const & value )
+ : sName( name ),
+ sValue( value )
+ {}
+};
+
+typedef std::vector<
+ ini_NameValue
+> NameValueVector;
+
+struct ini_Section
+{
+ OUString sName;
+ NameValueVector vVector;
+};
+typedef std::map<OUString,
+ ini_Section
+ >IniSectionMap;
+
+
+class IniParser
+{
+ IniSectionMap mAllSection;
+public:
+ IniSectionMap * getAllSection(){return &mAllSection;};
+ ini_Section * getSection(OUString const & secName)
+ {
+ if (mAllSection.find(secName) != mAllSection.end())
+ return &mAllSection[secName];
+ return NULL;
+ }
+ explicit IniParser(OUString const & rIniName) throw(css::io::IOException )
+ {
+ OUString curDirPth;
+ OUString iniUrl;
+ osl_getProcessWorkingDir( &curDirPth.pData );
+ if (osl_getAbsoluteFileURL( curDirPth.pData, rIniName.pData, &iniUrl.pData ))
+ throw css::io::IOException();
+
+
+ oslFileHandle handle=NULL;
+ if (iniUrl.getLength() &&
+ osl_File_E_None == osl_openFile(iniUrl.pData, &handle, osl_File_OpenFlag_Read))
+ {
+ rtl::ByteSequence seq;
+ sal_uInt64 nSize = 0;
+
+ osl_getFileSize(handle, &nSize);
+ OUString sectionName( "no name section" );
+ while (true)
+ {
+ sal_uInt64 nPos;
+ if (osl_File_E_None != osl_getFilePos(handle, &nPos) || nPos >= nSize)
+ break;
+ if (osl_File_E_None != osl_readLine(handle , (sal_Sequence **) &seq))
+ break;
+ OString line( (const char *) seq.getConstArray(), seq.getLength() );
+ sal_Int32 nIndex = line.indexOf('=');
+ if (nIndex >= 1)
+ {
+ ini_Section *aSection = &mAllSection[sectionName];
+ struct ini_NameValue nameValue;
+ nameValue.sName = OStringToOUString(
+ line.copy(0,nIndex).trim(), RTL_TEXTENCODING_ASCII_US );
+ nameValue.sValue = OStringToOUString(
+ line.copy(nIndex+1).trim(), RTL_TEXTENCODING_UTF8 );
+
+ aSection->vVector.push_back(nameValue);
+
+ }
+ else
+ {
+ sal_Int32 nIndexStart = line.indexOf('[');
+ sal_Int32 nIndexEnd = line.indexOf(']');
+ if ( nIndexEnd > nIndexStart && nIndexStart >=0)
+ {
+ sectionName = OStringToOUString(
+ line.copy(nIndexStart + 1,nIndexEnd - nIndexStart -1).trim(), RTL_TEXTENCODING_ASCII_US );
+ if (!sectionName.getLength())
+ sectionName = "no name section";
+
+ ini_Section *aSection = &mAllSection[sectionName];
+ aSection->sName = sectionName;
+ }
+ }
+ }
+ osl_closeFile(handle);
+ }
+#if OSL_DEBUG_LEVEL > 1
+ else
+ {
+ SAL_WARN("connectivity", "couldn't open file: " << iniUrl );
+ throw css::io::IOException();
+ }
+#endif
+ }
+#if OSL_DEBUG_LEVEL > 1
+ void Dump()
+ {
+ for(auto& rEntry : mAllSection)
+ {
+ ini_Section *aSection = &rEntry.second;
+ for(const auto& rValue : aSection->vVector)
+ {
+ SAL_WARN("connectivity",
+ " section=" << aSection->sName << " name=" << rValue.sName << " value=" << rValue.sValue );
+
+ }
+ }
+
+ }
+#endif
+
+};
+
+int main( int argc, char * argv[] )
+{
+
+ IniParser parser(OUString("test.ini"));
+ parser.Dump();
+ return 0;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/workben/iniParser/makefile.mk b/connectivity/workben/iniParser/makefile.mk
new file mode 100644
index 0000000000..ffca14a542
--- /dev/null
+++ b/connectivity/workben/iniParser/makefile.mk
@@ -0,0 +1,52 @@
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# This file incorporates work covered by the following license notice:
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed
+# with this work for additional information regarding copyright
+# ownership. The ASF licenses this file to you under the Apache
+# License, Version 2.0 (the "License"); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.apache.org/licenses/LICENSE-2.0 .
+#
+
+PRJ=..$/..
+
+PRJNAME=connectivity
+TARGET=iniparser
+TARGETTYPE=CUI
+LIBTARGET=NO
+ENABLE_EXCEPTIONS=TRUE
+
+# --- Settings -----------------------------------------------------
+
+.INCLUDE : settings.mk
+
+# --- Files --------------------------------------------------------
+OBJFILES= $(OBJ)$/main.obj
+
+
+APPSTDLIBS=$(SALLIB) \
+ $(CPPULIB) \
+ $(CPPUHELPERLIB) \
+ $(UCBHELPERLIB) \
+ $(DBTOOLSLIB) \
+ $(COMPHELPERLIB)
+
+
+# ... cfgapi ..............................
+
+APP1TARGET= $(TARGET)
+APP1OBJS= $(OBJFILES)
+APP1STDLIBS = $(APPSTDLIBS)
+
+# --- Targets ------------------------------------------------------
+
+.INCLUDE : target.mk
+
diff --git a/connectivity/workben/little/main.cxx b/connectivity/workben/little/main.cxx
new file mode 100644
index 0000000000..c70f463b8b
--- /dev/null
+++ b/connectivity/workben/little/main.cxx
@@ -0,0 +1,101 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <connectivity/sqlparse.hxx>
+#include <connectivity/sqliterator.hxx>
+#include <com/sun/star/sdbcx/XTablesSupplier.hpp>
+#include <com/sun/star/sdbcx/XDataDefinitionSupplier.hpp>
+#include <com/sun/star/sdbc/XResultSet.hpp>
+#include <com/sun/star/sdbc/XResultSetMetaData.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/beans/PropertyState.hpp>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <cppuhelper/servicefactory.hxx>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <com/sun/star/sdbc/XDriver.hpp>
+#include <connectivity/sqlnode.hxx>
+
+using namespace connectivity;
+using namespace com::sun::star::sdbc;
+using namespace com::sun::star;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::beans;
+using namespace cppu;
+
+
+void main( int argc, char * argv[] )
+{
+ css::uno::Reference< css::sdbc::XConnection> m_xConnection;
+ css::uno::Reference< css::sdbc::XDriver> m_xDriver;
+
+ try{
+ Reference< css::lang::XMultiServiceFactory > xFac =
+ createRegistryServiceFactory(OUString("g:\\office50\\program\\applicat.rdb"),OUString());
+ if(!xFac.is())
+ return;
+
+ m_xDriver.set(xFac->createInstance("com.sun.star.sdbc.driver.dbase.Driver"),UNO_QUERY);
+ if(m_xDriver.is())
+ {
+
+ Sequence<PropertyValue> aValue;
+ // aValue.getArray()[0] = PropertyValue( OUString("user"),0,makeAny(OUString("TEST1")),PropertyState_DIRECT_VALUE);
+ // aValue.getArray()[1] = PropertyValue( OUString("password"),0,makeAny(OUString("TEST1")),PropertyState_DIRECT_VALUE);
+
+ m_xConnection = m_xDriver->connect(OUString("sdbc:dbase:g:\\"),aValue);
+ if(m_xConnection.is())
+ {
+ Reference<XStatement> xStmt = m_xConnection->createStatement();
+ if(xStmt.is())
+ {
+ Reference<XResultSet> xRes = xStmt->executeQuery(OUString("SELECT * FROM Tele"));
+ if(xRes.is())
+ {
+ OUString aPat( "%s\t" );
+ Reference<XRow> xRow(xRes,UNO_QUERY);
+ Reference<XResultSetMetaData> xMeta = Reference<XResultSetMetaDataSupplier>(xRes,UNO_QUERY)->getMetaData();
+ for(sal_Int32 i=1;i<xMeta->getColumnCount();++i)
+ {
+ wprintf(aPat.getStr(), xMeta->getColumnName(i).getStr());
+ }
+ printf("----------------------------------------------------------------------\n");
+ while(xRes->next())
+ {
+ for(sal_Int32 j=1;j<xMeta->getColumnCount();++j)
+ wprintf(aPat.getStr(), xRow->getString(j).getStr());
+ printf("\n");
+ }
+ }
+ }
+ }
+
+ }
+ }
+ catch(...)
+ {
+ printf("Exception thrown!\n");
+
+ }
+ sal_Int32 d;
+ scanf("%d",&d);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/workben/little/makefile.mk b/connectivity/workben/little/makefile.mk
new file mode 100644
index 0000000000..75fcccf50e
--- /dev/null
+++ b/connectivity/workben/little/makefile.mk
@@ -0,0 +1,50 @@
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# This file incorporates work covered by the following license notice:
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed
+# with this work for additional information regarding copyright
+# ownership. The ASF licenses this file to you under the Apache
+# License, Version 2.0 (the "License"); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.apache.org/licenses/LICENSE-2.0 .
+#
+
+PRJ=..\..
+
+PRJNAME=connectivity
+TARGET=little
+TARGETTYPE=CUI
+LIBTARGET=NO
+ENABLE_EXCEPTIONS=TRUE
+
+# --- Settings -----------------------------------------------------
+
+.INCLUDE : settings.mk
+
+# --- Files --------------------------------------------------------
+OBJFILES= $(OBJ)$/main.obj
+
+APP1TARGET= $(TARGET)
+APP1OBJS= $(OBJFILES)
+APPSTDLIBS=$(SALLIB) \
+ $(CPPULIB) \
+ $(CPPUHELPERLIB) \
+ $(SLB)$/sql.lib
+
+
+# ... cfgapi ..............................
+APP1STDLIBS = $(APPSTDLIBS)
+
+APP1STDLIBS+=$(STDLIBCPP)
+
+# --- Targets ------------------------------------------------------
+
+.INCLUDE : target.mk
+
diff --git a/connectivity/workben/skeleton/SResultSet.hxx b/connectivity/workben/skeleton/SResultSet.hxx
new file mode 100644
index 0000000000..514aec2df6
--- /dev/null
+++ b/connectivity/workben/skeleton/SResultSet.hxx
@@ -0,0 +1,235 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <com/sun/star/sdbc/XResultSet.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
+#include <com/sun/star/sdbc/XCloseable.hpp>
+#include <com/sun/star/sdbc/XColumnLocate.hpp>
+#include <com/sun/star/util/XCancellable.hpp>
+#include <com/sun/star/sdbc/XWarningsSupplier.hpp>
+#include <com/sun/star/sdbc/XResultSetUpdate.hpp>
+#include <com/sun/star/sdbc/XRowUpdate.hpp>
+#include <com/sun/star/sdbcx/XRowLocate.hpp>
+#include <com/sun/star/sdbcx/XDeleteRows.hpp>
+#include <cppuhelper/compbase.hxx>
+#include <comphelper/proparrhlp.hxx>
+#include "SStatement.hxx"
+#include <connectivity/CommonTools.hxx>
+#include <connectivity/FValue.hxx>
+
+namespace connectivity::skeleton
+ {
+
+ /*
+ ** java_sql_ResultSet
+ */
+ typedef ::cppu::WeakComponentImplHelper< css::sdbc::XResultSet,
+ css::sdbc::XRow,
+ css::sdbc::XResultSetMetaDataSupplier,
+ css::util::XCancellable,
+ css::sdbc::XWarningsSupplier,
+ css::sdbc::XResultSetUpdate,
+ css::sdbc::XRowUpdate,
+ css::sdbcx::XRowLocate,
+ css::sdbcx::XDeleteRows,
+ css::sdbc::XCloseable,
+ css::sdbc::XColumnLocate,
+ css::lang::XServiceInfo> OResultSet_BASE;
+
+
+ typedef sal_Int64 TVoidPtr;
+ typedef std::allocator< TVoidPtr > TVoidAlloc;
+ typedef std::vector<TVoidPtr> TVoidVector;
+
+ class OResultSet : public cppu::BaseMutex,
+ public OResultSet_BASE,
+ public ::cppu::OPropertySetHelper,
+ public ::comphelper::OPropertyArrayUsageHelper<OResultSet>
+ {
+ protected:
+ TVoidVector m_aBindVector;
+ std::vector<sal_Int32> m_aLengthVector;
+ std::vector<sal_Int32> m_aColMapping; // pos 0 is unused so we don't have to decrement 1 every time
+ std::vector< ORowSetValue> m_aRow; // only used when SQLGetData can't be called in any order
+ OStatement_Base* m_pStatement;
+ css::uno::WeakReferenceHelper m_aStatement;
+ css::uno::Reference< css::sdbc::XResultSetMetaData> m_xMetaData;
+ rtl_TextEncoding m_nTextEncoding;
+ sal_Int32 m_nRowPos;
+ sal_Int32 m_nLastColumnPos; // used for m_aRow just to know where we are
+ sal_Bool m_bWasNull;
+ sal_Bool m_bBOF; // before first record
+ sal_Bool m_bEOF; // after last record
+ sal_Bool m_bLastRecord;
+ sal_Bool m_bFreeHandle;
+ sal_Bool m_bInserting;
+ sal_Bool m_bFetchData; // true when SQLGetaData can be called in any order or when fetching data for m_aRow
+
+ sal_Bool isBookmarkable() const throw(css::sdbc::SQLException, css::uno::RuntimeException);
+ sal_Int32 getResultSetConcurrency() const throw(css::sdbc::SQLException, css::uno::RuntimeException);
+ sal_Int32 getResultSetType() const throw(css::sdbc::SQLException, css::uno::RuntimeException);
+ sal_Int32 getFetchDirection() const throw(css::sdbc::SQLException, css::uno::RuntimeException);
+ sal_Int32 getFetchSize() const throw(css::sdbc::SQLException, css::uno::RuntimeException);
+ OUString getCursorName() const throw(css::sdbc::SQLException, css::uno::RuntimeException);
+
+ void setFetchDirection(sal_Int32 _par0) throw(css::sdbc::SQLException, css::uno::RuntimeException);
+ void setFetchSize(sal_Int32 _par0) throw(css::sdbc::SQLException, css::uno::RuntimeException);
+
+
+ void fillRow(sal_Int32 _nToColumn);
+ void allocBuffer(sal_Bool _bAllocRow);
+ void releaseBuffer();
+
+
+ // OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const;
+ // OPropertySetHelper
+ virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper();
+
+ virtual sal_Bool SAL_CALL convertFastPropertyValue(
+ css::uno::Any & rConvertedValue,
+ css::uno::Any & rOldValue,
+ sal_Int32 nHandle,
+ const css::uno::Any& rValue )
+ throw (css::lang::IllegalArgumentException);
+ virtual void SAL_CALL setFastPropertyValue_NoBroadcast(
+ sal_Int32 nHandle,
+ const css::uno::Any& rValue
+ )
+ throw (css::uno::Exception);
+ virtual void SAL_CALL getFastPropertyValue(
+ css::uno::Any& rValue,
+ sal_Int32 nHandle
+ ) const;
+
+ // you can't delete objects of this type
+ virtual ~OResultSet();
+ public:
+ DECLARE_SERVICE_INFO();
+
+ OResultSet( OStatement_Base* pStmt);
+
+
+ css::uno::Reference< css::uno::XInterface > operator *()
+ {
+ return css::uno::Reference< css::uno::XInterface >(*(OResultSet_BASE*)this);
+ }
+
+ // ::cppu::OComponentHelper
+ virtual void SAL_CALL disposing();
+ // XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) throw(css::uno::RuntimeException);
+ virtual void SAL_CALL acquire() throw(css::uno::RuntimeException);
+ virtual void SAL_CALL release() throw(css::uno::RuntimeException);
+ //XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) throw(css::uno::RuntimeException);
+ // XPropertySet
+ virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) throw(css::uno::RuntimeException);
+ // XResultSet
+ virtual sal_Bool SAL_CALL next( ) throw(css::sdbc::SQLException, css::uno::RuntimeException);
+ virtual sal_Bool SAL_CALL isBeforeFirst( ) throw(css::sdbc::SQLException, css::uno::RuntimeException);
+ virtual sal_Bool SAL_CALL isAfterLast( ) throw(css::sdbc::SQLException, css::uno::RuntimeException);
+ virtual sal_Bool SAL_CALL isFirst( ) throw(css::sdbc::SQLException, css::uno::RuntimeException);
+ virtual sal_Bool SAL_CALL isLast( ) throw(css::sdbc::SQLException, css::uno::RuntimeException);
+ virtual void SAL_CALL beforeFirst( ) throw(css::sdbc::SQLException, css::uno::RuntimeException);
+ virtual void SAL_CALL afterLast( ) throw(css::sdbc::SQLException, css::uno::RuntimeException);
+ virtual sal_Bool SAL_CALL first( ) throw(css::sdbc::SQLException, css::uno::RuntimeException);
+ virtual sal_Bool SAL_CALL last( ) throw(css::sdbc::SQLException, css::uno::RuntimeException);
+ virtual sal_Int32 SAL_CALL getRow( ) throw(css::sdbc::SQLException, css::uno::RuntimeException);
+ virtual sal_Bool SAL_CALL absolute( sal_Int32 row ) throw(css::sdbc::SQLException, css::uno::RuntimeException);
+ virtual sal_Bool SAL_CALL relative( sal_Int32 rows ) throw(css::sdbc::SQLException, css::uno::RuntimeException);
+ virtual sal_Bool SAL_CALL previous( ) throw(css::sdbc::SQLException, css::uno::RuntimeException);
+ virtual void SAL_CALL refreshRow( ) throw(css::sdbc::SQLException, css::uno::RuntimeException);
+ virtual sal_Bool SAL_CALL rowUpdated( ) throw(css::sdbc::SQLException, css::uno::RuntimeException);
+ virtual sal_Bool SAL_CALL rowInserted( ) throw(css::sdbc::SQLException, css::uno::RuntimeException);
+ virtual sal_Bool SAL_CALL rowDeleted( ) throw(css::sdbc::SQLException, css::uno::RuntimeException);
+ virtual css::uno::Reference< css::uno::XInterface > SAL_CALL getStatement( ) throw(css::sdbc::SQLException, css::uno::RuntimeException);
+ // XRow
+ virtual sal_Bool SAL_CALL wasNull( ) throw(css::sdbc::SQLException, css::uno::RuntimeException);
+ virtual OUString SAL_CALL getString( sal_Int32 columnIndex ) throw(css::sdbc::SQLException, css::uno::RuntimeException);
+ virtual sal_Bool SAL_CALL getBoolean( sal_Int32 columnIndex ) throw(css::sdbc::SQLException, css::uno::RuntimeException);
+ virtual sal_Int8 SAL_CALL getByte( sal_Int32 columnIndex ) throw(css::sdbc::SQLException, css::uno::RuntimeException);
+ virtual sal_Int16 SAL_CALL getShort( sal_Int32 columnIndex ) throw(css::sdbc::SQLException, css::uno::RuntimeException);
+ virtual sal_Int32 SAL_CALL getInt( sal_Int32 columnIndex ) throw(css::sdbc::SQLException, css::uno::RuntimeException);
+ virtual sal_Int64 SAL_CALL getLong( sal_Int32 columnIndex ) throw(css::sdbc::SQLException, css::uno::RuntimeException);
+ virtual float SAL_CALL getFloat( sal_Int32 columnIndex ) throw(css::sdbc::SQLException, css::uno::RuntimeException);
+ virtual double SAL_CALL getDouble( sal_Int32 columnIndex ) throw(css::sdbc::SQLException, css::uno::RuntimeException);
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getBytes( sal_Int32 columnIndex ) throw(css::sdbc::SQLException, css::uno::RuntimeException);
+ virtual css::util::Date SAL_CALL getDate( sal_Int32 columnIndex ) throw(css::sdbc::SQLException, css::uno::RuntimeException);
+ virtual css::util::Time SAL_CALL getTime( sal_Int32 columnIndex ) throw(css::sdbc::SQLException, css::uno::RuntimeException);
+ virtual css::util::DateTime SAL_CALL getTimestamp( sal_Int32 columnIndex ) throw(css::sdbc::SQLException, css::uno::RuntimeException);
+ virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getBinaryStream( sal_Int32 columnIndex ) throw(css::sdbc::SQLException, css::uno::RuntimeException);
+ virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getCharacterStream( sal_Int32 columnIndex ) throw(css::sdbc::SQLException, css::uno::RuntimeException);
+ virtual css::uno::Any SAL_CALL getObject( sal_Int32 columnIndex, const css::uno::Reference< css::container::XNameAccess >& typeMap ) throw(css::sdbc::SQLException, css::uno::RuntimeException);
+ virtual css::uno::Reference< css::sdbc::XRef > SAL_CALL getRef( sal_Int32 columnIndex ) throw(css::sdbc::SQLException, css::uno::RuntimeException);
+ virtual css::uno::Reference< css::sdbc::XBlob > SAL_CALL getBlob( sal_Int32 columnIndex ) throw(css::sdbc::SQLException, css::uno::RuntimeException);
+ virtual css::uno::Reference< css::sdbc::XClob > SAL_CALL getClob( sal_Int32 columnIndex ) throw(css::sdbc::SQLException, css::uno::RuntimeException);
+ virtual css::uno::Reference< css::sdbc::XArray > SAL_CALL getArray( sal_Int32 columnIndex ) throw(css::sdbc::SQLException, css::uno::RuntimeException);
+ // XResultSetMetaDataSupplier
+ virtual css::uno::Reference< css::sdbc::XResultSetMetaData > SAL_CALL getMetaData( ) throw(css::sdbc::SQLException, css::uno::RuntimeException);
+ // XCancellable
+ virtual void SAL_CALL cancel( ) throw(css::uno::RuntimeException);
+ // XCloseable
+ virtual void SAL_CALL close( ) throw(css::sdbc::SQLException, css::uno::RuntimeException);
+ // XWarningsSupplier
+ virtual css::uno::Any SAL_CALL getWarnings( ) throw(css::sdbc::SQLException, css::uno::RuntimeException);
+ virtual void SAL_CALL clearWarnings( ) throw(css::sdbc::SQLException, css::uno::RuntimeException);
+ // XResultSetUpdate
+ virtual void SAL_CALL insertRow( ) throw(css::sdbc::SQLException, css::uno::RuntimeException);
+ virtual void SAL_CALL updateRow( ) throw(css::sdbc::SQLException, css::uno::RuntimeException);
+ virtual void SAL_CALL deleteRow( ) throw(css::sdbc::SQLException, css::uno::RuntimeException);
+ virtual void SAL_CALL cancelRowUpdates( ) throw(css::sdbc::SQLException, css::uno::RuntimeException);
+ virtual void SAL_CALL moveToInsertRow( ) throw(css::sdbc::SQLException, css::uno::RuntimeException);
+ virtual void SAL_CALL moveToCurrentRow( ) throw(css::sdbc::SQLException, css::uno::RuntimeException);
+ // XRowUpdate
+ virtual void SAL_CALL updateNull( sal_Int32 columnIndex ) throw(css::sdbc::SQLException, css::uno::RuntimeException);
+ virtual void SAL_CALL updateBoolean( sal_Int32 columnIndex, sal_Bool x ) throw(css::sdbc::SQLException, css::uno::RuntimeException);
+ virtual void SAL_CALL updateByte( sal_Int32 columnIndex, sal_Int8 x ) throw(css::sdbc::SQLException, css::uno::RuntimeException);
+ virtual void SAL_CALL updateShort( sal_Int32 columnIndex, sal_Int16 x ) throw(css::sdbc::SQLException, css::uno::RuntimeException);
+ virtual void SAL_CALL updateInt( sal_Int32 columnIndex, sal_Int32 x ) throw(css::sdbc::SQLException, css::uno::RuntimeException);
+ virtual void SAL_CALL updateLong( sal_Int32 columnIndex, sal_Int64 x ) throw(css::sdbc::SQLException, css::uno::RuntimeException);
+ virtual void SAL_CALL updateFloat( sal_Int32 columnIndex, float x ) throw(css::sdbc::SQLException, css::uno::RuntimeException);
+ virtual void SAL_CALL updateDouble( sal_Int32 columnIndex, double x ) throw(css::sdbc::SQLException, css::uno::RuntimeException);
+ virtual void SAL_CALL updateString( sal_Int32 columnIndex, const OUString& x ) throw(css::sdbc::SQLException, css::uno::RuntimeException);
+ virtual void SAL_CALL updateBytes( sal_Int32 columnIndex, const css::uno::Sequence< sal_Int8 >& x ) throw(css::sdbc::SQLException, css::uno::RuntimeException);
+ virtual void SAL_CALL updateDate( sal_Int32 columnIndex, const css::util::Date& x ) throw(css::sdbc::SQLException, css::uno::RuntimeException);
+ virtual void SAL_CALL updateTime( sal_Int32 columnIndex, const css::util::Time& x ) throw(css::sdbc::SQLException, css::uno::RuntimeException);
+ virtual void SAL_CALL updateTimestamp( sal_Int32 columnIndex, const css::util::DateTime& x ) throw(css::sdbc::SQLException, css::uno::RuntimeException);
+ virtual void SAL_CALL updateBinaryStream( sal_Int32 columnIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) throw(css::sdbc::SQLException, css::uno::RuntimeException);
+ virtual void SAL_CALL updateCharacterStream( sal_Int32 columnIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) throw(css::sdbc::SQLException, css::uno::RuntimeException);
+ virtual void SAL_CALL updateObject( sal_Int32 columnIndex, const css::uno::Any& x ) throw(css::sdbc::SQLException, css::uno::RuntimeException);
+ virtual void SAL_CALL updateNumericObject( sal_Int32 columnIndex, const css::uno::Any& x, sal_Int32 scale ) throw(css::sdbc::SQLException, css::uno::RuntimeException);
+ // XColumnLocate
+ virtual sal_Int32 SAL_CALL findColumn( const OUString& columnName ) throw(css::sdbc::SQLException, css::uno::RuntimeException);
+ // XRowLocate
+ virtual css::uno::Any SAL_CALL getBookmark( ) throw(css::sdbc::SQLException, css::uno::RuntimeException);
+ virtual sal_Bool SAL_CALL moveToBookmark( const css::uno::Any& bookmark ) throw(css::sdbc::SQLException, css::uno::RuntimeException);
+ virtual sal_Bool SAL_CALL moveRelativeToBookmark( const css::uno::Any& bookmark, sal_Int32 rows ) throw(css::sdbc::SQLException, css::uno::RuntimeException);
+ virtual sal_Int32 SAL_CALL compareBookmarks( const css::uno::Any& first, const css::uno::Any& second ) throw(css::sdbc::SQLException, css::uno::RuntimeException);
+ virtual sal_Bool SAL_CALL hasOrderedBookmarks( ) throw(css::sdbc::SQLException, css::uno::RuntimeException);
+ virtual sal_Int32 SAL_CALL hashBookmark( const css::uno::Any& bookmark ) throw(css::sdbc::SQLException, css::uno::RuntimeException);
+ // XDeleteRows
+ virtual css::uno::Sequence< sal_Int32 > SAL_CALL deleteRows( const css::uno::Sequence< css::uno::Any >& rows ) throw(css::sdbc::SQLException, css::uno::RuntimeException);
+ };
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/workben/skeleton/how_to_write_a_driver.txt b/connectivity/workben/skeleton/how_to_write_a_driver.txt
new file mode 100644
index 0000000000..e336f3664d
--- /dev/null
+++ b/connectivity/workben/skeleton/how_to_write_a_driver.txt
@@ -0,0 +1,69 @@
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# This file incorporates work covered by the following license notice:
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed
+# with this work for additional information regarding copyright
+# ownership. The ASF licenses this file to you under the Apache
+# License, Version 2.0 (the "License"); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.apache.org/licenses/LICENSE-2.0 .
+#
+
+How to write my own sdbc driver
+
+all example files can be found in connectivity/workben/skeleton
+
+Pre implementation steps
+- copy all files from connectivity/workben/skeleton into your new created directory under
+ connectivity/source/drivers and rename the first char of the files to one which isn't used so far
+ ( please have a look at the other drivers )
+- search all occurrences of skeleton and replace them to a name which you prefer
+
+1. Implement a class called driver or modify the existing skeleton -> have a look at SDriver.?xx
+2. Implement a class called connection -> have a look at SConnection.?xx
+3. Have a look at the DatabaseMetaData -> see SDatabaseMetaData.cxx
+ The methods which should be implemented at least are
+ - getTableTypes
+ - getTables
+ - getTypeInfo
+ - getColumns
+
+4. You need a statement to show/access some data -> have a look at SStatement.cxx
+ -> especially executeQuery()
+
+5. The ResultSet: without you see nothing -> look at SResultSet.cxx
+6. The ResultSetMetaData needed to get some information about what are waiting for us
+ -> look at SResultSetMetaData.cxx
+
+7. The prepared statement is the last class we have to implement now
+ -> you have to allow statements like "SELECT * FROM table WHERE id = ?"
+
+
+8. insert entry in version.mk
+# ----------------------------SKELETON settings-----------------------------------#
+# target
+SKELETON_TARGET=skeleton
+
+# the major
+SKELETON_MAJOR=2
+# the minor
+SKELETON_MINOR=0
+# the micro
+SKELETON_MICRO=0
+
+# this is a c++ compatible library
+SKELETON_CPP=1
+
+SKELETON=$(SKELETON_TARGET_TARGET)_$(CMPEXT)
+
+
+9. copy dll to program dir of office and register the dll
+
+10. congratulations you have now implement your own driver :-)