summaryrefslogtreecommitdiffstats
path: root/connectivity/source/drivers
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
commited5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch)
tree7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /connectivity/source/drivers
parentInitial commit. (diff)
downloadlibreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.tar.xz
libreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.zip
Adding upstream version 4:7.4.7.upstream/4%7.4.7upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'connectivity/source/drivers')
-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.cxx248
-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.cxx142
-rw-r--r--connectivity/source/drivers/ado/AGroups.cxx76
-rw-r--r--connectivity/source/drivers/ado/AIndex.cxx121
-rw-r--r--connectivity/source/drivers/ado/AIndexes.cxx82
-rw-r--r--connectivity/source/drivers/ado/AKey.cxx134
-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.cxx868
-rw-r--r--connectivity/source/drivers/ado/ATable.cxx230
-rw-r--r--connectivity/source/drivers/ado/ATables.cxx103
-rw-r--r--connectivity/source/drivers/ado/AUser.cxx190
-rw-r--r--connectivity/source/drivers/ado/AUsers.cxx77
-rw-r--r--connectivity/source/drivers/ado/AView.cxx93
-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.cxx2008
-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.cxx265
-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.cxx652
-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.cxx240
-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.cxx190
-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.cxx386
-rw-r--r--connectivity/source/drivers/dbase/DDriver.cxx118
-rw-r--r--connectivity/source/drivers/dbase/DIndex.cxx608
-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.cxx116
-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.cxx2769
-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.cxx1046
-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.hxx106
-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.cxx1038
-rw-r--r--connectivity/source/drivers/evoab2/NResultSet.hxx182
-rw-r--r--connectivity/source/drivers/evoab2/NResultSetMetaData.cxx174
-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.hxx43
-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.cxx432
-rw-r--r--connectivity/source/drivers/file/FDatabaseMetaData.cxx1055
-rw-r--r--connectivity/source/drivers/file/FDateFunctions.cxx278
-rw-r--r--connectivity/source/drivers/file/FDriver.cxx205
-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.cxx1593
-rw-r--r--connectivity/source/drivers/file/FResultSetMetaData.cxx188
-rw-r--r--connectivity/source/drivers/file/FStatement.cxx711
-rw-r--r--connectivity/source/drivers/file/FStringFunctions.cxx233
-rw-r--r--connectivity/source/drivers/file/FTable.cxx185
-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.cxx984
-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.cxx34
-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.cxx245
-rw-r--r--connectivity/source/drivers/firebird/Table.hxx81
-rw-r--r--connectivity/source/drivers/firebird/Tables.cxx229
-rw-r--r--connectivity/source/drivers/firebird/Tables.hxx60
-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.cxx440
-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.cxx244
-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.cxx961
-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.cxx337
-rw-r--r--connectivity/source/drivers/hsqldb/HDriver.cxx894
-rw-r--r--connectivity/source/drivers/hsqldb/HStorageAccess.cxx511
-rw-r--r--connectivity/source/drivers/hsqldb/HStorageMap.cxx361
-rw-r--r--connectivity/source/drivers/hsqldb/HTable.cxx386
-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.cxx328
-rw-r--r--connectivity/source/drivers/hsqldb/HUsers.cxx98
-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.cxx803
-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.hxx138
-rw-r--r--connectivity/source/drivers/mozab/bootstrap/MMozillaBootstrap.cxx138
-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.cxx210
-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.cxx327
-rw-r--r--connectivity/source/drivers/mysql_jdbc/YTables.cxx208
-rw-r--r--connectivity/source/drivers/mysql_jdbc/YUser.cxx325
-rw-r--r--connectivity/source/drivers/mysql_jdbc/YUsers.cxx91
-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.cxx70
-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.cxx524
-rw-r--r--connectivity/source/drivers/mysqlc/mysqlc_connection.hxx190
-rw-r--r--connectivity/source/drivers/mysqlc/mysqlc_databasemetadata.cxx1051
-rw-r--r--connectivity/source/drivers/mysqlc/mysqlc_databasemetadata.hxx233
-rw-r--r--connectivity/source/drivers/mysqlc/mysqlc_driver.cxx149
-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.cxx1129
-rw-r--r--connectivity/source/drivers/mysqlc/mysqlc_prepared_resultset.hxx253
-rw-r--r--connectivity/source/drivers/mysqlc/mysqlc_preparedstatement.cxx580
-rw-r--r--connectivity/source/drivers/mysqlc/mysqlc_preparedstatement.hxx157
-rw-r--r--connectivity/source/drivers/mysqlc/mysqlc_propertyids.hxx44
-rw-r--r--connectivity/source/drivers/mysqlc/mysqlc_resultset.cxx1112
-rw-r--r--connectivity/source/drivers/mysqlc/mysqlc_resultset.hxx275
-rw-r--r--connectivity/source/drivers/mysqlc/mysqlc_resultsetmetadata.cxx212
-rw-r--r--connectivity/source/drivers/mysqlc/mysqlc_resultsetmetadata.hxx103
-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.hxx175
-rw-r--r--connectivity/source/drivers/mysqlc/mysqlc_subcomponent.hxx138
-rw-r--r--connectivity/source/drivers/mysqlc/mysqlc_table.cxx160
-rw-r--r--connectivity/source/drivers/mysqlc/mysqlc_table.hxx65
-rw-r--r--connectivity/source/drivers/mysqlc/mysqlc_tables.cxx157
-rw-r--r--connectivity/source/drivers/mysqlc/mysqlc_tables.hxx56
-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.cxx55
-rw-r--r--connectivity/source/drivers/mysqlc/mysqlc_user.hxx45
-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.cxx192
-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.hxx97
-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.cxx571
-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.cxx148
-rw-r--r--connectivity/source/drivers/postgresql/pq_driver.hxx116
-rw-r--r--connectivity/source/drivers/postgresql/pq_fakedupdateableresultset.cxx214
-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.cxx308
-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.cxx888
-rw-r--r--connectivity/source/drivers/postgresql/pq_statement.hxx198
-rw-r--r--connectivity/source/drivers/postgresql/pq_statics.cxx626
-rw-r--r--connectivity/source/drivers/postgresql/pq_statics.hxx239
-rw-r--r--connectivity/source/drivers/postgresql/pq_tools.cxx1249
-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.hxx169
-rw-r--r--connectivity/source/drivers/postgresql/pq_xbase.cxx215
-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.cxx409
-rw-r--r--connectivity/source/drivers/postgresql/pq_xcontainer.hxx188
-rw-r--r--connectivity/source/drivers/postgresql/pq_xindex.cxx186
-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.cxx267
-rw-r--r--connectivity/source/drivers/postgresql/pq_xindexcolumns.hxx110
-rw-r--r--connectivity/source/drivers/postgresql/pq_xindexes.cxx302
-rw-r--r--connectivity/source/drivers/postgresql/pq_xindexes.hxx102
-rw-r--r--connectivity/source/drivers/postgresql/pq_xkey.cxx182
-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.cxx238
-rw-r--r--connectivity/source/drivers/postgresql/pq_xkeycolumns.hxx101
-rw-r--r--connectivity/source/drivers/postgresql/pq_xkeys.cxx294
-rw-r--r--connectivity/source/drivers/postgresql/pq_xkeys.hxx101
-rw-r--r--connectivity/source/drivers/postgresql/pq_xtable.cxx394
-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.cxx218
-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.cxx246
-rw-r--r--connectivity/source/drivers/writer/WDatabaseMetaData.cxx112
-rw-r--r--connectivity/source/drivers/writer/WDriver.cxx90
-rw-r--r--connectivity/source/drivers/writer/WTable.cxx250
-rw-r--r--connectivity/source/drivers/writer/WTables.cxx45
-rw-r--r--connectivity/source/drivers/writer/writer.component17
399 files changed, 107257 insertions, 0 deletions
diff --git a/connectivity/source/drivers/ado/ACallableStatement.cxx b/connectivity/source/drivers/ado/ACallableStatement.cxx
new file mode 100644
index 000000000..94ad744d0
--- /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 000000000..efab28344
--- /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 000000000..a521586b9
--- /dev/null
+++ b/connectivity/source/drivers/ado/AColumn.cxx
@@ -0,0 +1,248 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * 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;
+}
+
+
+Sequence< sal_Int8 > OAdoColumn::getUnoTunnelId()
+{
+ static const comphelper::UnoIdInit implId;
+ return implId.getSeq();
+}
+
+// css::lang::XUnoTunnel
+
+sal_Int64 OAdoColumn::getSomething( const Sequence< sal_Int8 > & rId )
+{
+ return comphelper::getSomethingImpl(rId, this,
+ comphelper::FallbackToGetSomethingOf<OColumn_ADO>{});
+}
+
+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 000000000..229903502
--- /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 = getFromUnoTunnel<OAdoColumn>( descriptor );
+ 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 000000000..686a9fed5
--- /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 000000000..65e0a80f5
--- /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 000000000..b78720706
--- /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 000000000..bb5bda634
--- /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 000000000..3fa13d06b
--- /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 000000000..6568f7a1e
--- /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 000000000..a347fb96d
--- /dev/null
+++ b/connectivity/source/drivers/ado/AGroup.cxx
@@ -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 .
+ */
+
+
+#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()));
+}
+
+Sequence< sal_Int8 > OAdoGroup::getUnoTunnelId()
+{
+ static const comphelper::UnoIdInit implId;
+ return implId.getSeq();
+}
+
+// css::lang::XUnoTunnel
+
+sal_Int64 OAdoGroup::getSomething( const Sequence< sal_Int8 > & rId )
+{
+ return comphelper::getSomethingImpl(rId, this,
+ comphelper::FallbackToGetSomethingOf<OGroup_ADO>{});
+}
+
+
+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 000000000..e3fb165b0
--- /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 = getFromUnoTunnel<OAdoGroup>(descriptor);
+ 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 000000000..af643a436
--- /dev/null
+++ b/connectivity/source/drivers/ado/AIndex.cxx
@@ -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 .
+ */
+
+#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));
+}
+
+
+Sequence< sal_Int8 > OAdoIndex::getUnoTunnelId()
+{
+ static const comphelper::UnoIdInit implId;
+ return implId.getSeq();
+}
+
+// css::lang::XUnoTunnel
+
+sal_Int64 OAdoIndex::getSomething( const Sequence< sal_Int8 > & rId )
+{
+ return comphelper::getSomethingImpl(rId, this,
+ comphelper::FallbackToGetSomethingOf<sdbcx::OIndex>{});
+}
+
+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 000000000..621ddec60
--- /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 = getFromUnoTunnel<OAdoIndex>(descriptor);
+ 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 000000000..b74103d83
--- /dev/null
+++ b/connectivity/source/drivers/ado/AKey.cxx
@@ -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 .
+ */
+
+#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));
+}
+
+Sequence< sal_Int8 > OAdoKey::getUnoTunnelId()
+{
+ static const comphelper::UnoIdInit implId;
+ return implId.getSeq();
+}
+
+// css::lang::XUnoTunnel
+
+sal_Int64 OAdoKey::getSomething( const Sequence< sal_Int8 > & rId )
+{
+ return comphelper::getSomethingImpl(rId, this,
+ comphelper::FallbackToGetSomethingOf<OKey_ADO>{});
+}
+
+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 000000000..f0d938d39
--- /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 = getFromUnoTunnel<OAdoKey>( descriptor );
+ 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 000000000..cf2339fdc
--- /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);
+ delete pChildNode->replace(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 000000000..85ca2b081
--- /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 000000000..d43ee5da9
--- /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 000000000..1c48734d8
--- /dev/null
+++ b/connectivity/source/drivers/ado/AStatement.cxx
@@ -0,0 +1,868 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * 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;
+using namespace ::std;
+
+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 000000000..f048f3ec0
--- /dev/null
+++ b/connectivity/source/drivers/ado/ATable.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 <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()));
+}
+
+Sequence< sal_Int8 > OAdoTable::getUnoTunnelId()
+{
+ static const comphelper::UnoIdInit implId;
+ return implId.getSeq();
+}
+
+// css::lang::XUnoTunnel
+
+sal_Int64 OAdoTable::getSomething( const Sequence< sal_Int8 > & rId )
+{
+ return comphelper::getSomethingImpl(rId, this,
+ comphelper::FallbackToGetSomethingOf<OTable_TYPEDEF>{});
+}
+
+// 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 = comphelper::getFromUnoTunnel<OAdoColumn>(descriptor);
+ 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 000000000..234a41fa5
--- /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 = getFromUnoTunnel<OAdoTable>( descriptor );
+ 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 000000000..42f7240f8
--- /dev/null
+++ b/connectivity/source/drivers/ado/AUser.cxx
@@ -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 .
+ */
+
+#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()));
+}
+
+Sequence< sal_Int8 > OAdoUser::getUnoTunnelId()
+{
+ static const comphelper::UnoIdInit implId;
+ return implId.getSeq();
+}
+
+// css::lang::XUnoTunnel
+
+sal_Int64 OAdoUser::getSomething( const Sequence< sal_Int8 > & rId )
+{
+ return comphelper::getSomethingImpl(rId, this,
+ comphelper::FallbackToGetSomethingOf<OUser_TYPEDEF>{});
+}
+
+
+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 000000000..407433091
--- /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 = getFromUnoTunnel<OUserExtend>( descriptor );
+ 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 000000000..3b88116bc
--- /dev/null
+++ b/connectivity/source/drivers/ado/AView.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 <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)
+{
+}
+
+Sequence< sal_Int8 > OAdoView::getUnoTunnelId()
+{
+ static const comphelper::UnoIdInit implId;
+ return implId.getSeq();
+}
+
+// css::lang::XUnoTunnel
+
+sal_Int64 OAdoView::getSomething( const Sequence< sal_Int8 > & rId )
+{
+ return comphelper::getSomethingImpl(rId, this,
+ comphelper::FallbackToGetSomethingOf<OView_ADO>{});
+}
+
+
+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 000000000..38f9ae4d7
--- /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 = getFromUnoTunnel<OAdoView>( descriptor );
+ 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 000000000..c082c1987
--- /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 000000000..c25c0d6e0
--- /dev/null
+++ b/connectivity/source/drivers/ado/Awrapado.cxx
@@ -0,0 +1,2008 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * 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 <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,
+ const OUString& 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(tableNamePattern.toChar() != '%')
+ 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,
+ const OUString& 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(procedureNamePattern.toChar() != '%')
+ 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,
+ const OUString& procedureNamePattern,
+ const OUString& 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(procedureNamePattern.toChar() != '%')
+ varCriteria[nPos].setString(procedureNamePattern);
+ SafeArrayPutElement(psa,&nPos,&varCriteria[nPos]);nPos++;// TABLE_NAME
+
+ if(columnNamePattern.toChar() != '%')
+ 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,
+ const OUString& 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(tableNamePattern.toChar() != '%')
+ 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,
+ const OUString& 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(tableNamePattern.toChar() != '%')
+ 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 000000000..7c97fb2d8
--- /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 000000000..0f0d02268
--- /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 000000000..03c4358b9
--- /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 000000000..8d4a0c01e
--- /dev/null
+++ b/connectivity/source/drivers/calc/CConnection.cxx
@@ -0,0 +1,265 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * 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;
+ aDetailException.Message = m_aResources.getResourceStringWithSubstitution(
+ STR_LOAD_FILE_ERROR_MESSAGE,
+ "$exception_type$", aLoaderException.getValueTypeName(),
+ "$error_message$", aLoaderError.Message
+ );
+ 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 000000000..159349cac
--- /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 000000000..b7b11cc29
--- /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 static_cast<cppu::OWeakObject*>(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 000000000..53a8c8eeb
--- /dev/null
+++ b/connectivity/source/drivers/calc/CTable.cxx
@@ -0,0 +1,652 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * 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;
+
+}
+
+const Sequence< sal_Int8 > & OCalcTable::getUnoTunnelId()
+{
+ static const comphelper::UnoIdInit implId;
+ return implId.getSeq();
+}
+
+// css::lang::XUnoTunnel
+
+sal_Int64 OCalcTable::getSomething( const Sequence< sal_Int8 > & rId )
+{
+ return comphelper::getSomethingImpl(rId, this,
+ comphelper::FallbackToGetSomethingOf<OCalcTable_BASE>{});
+}
+
+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 000000000..08e5d63e3
--- /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 000000000..a4fc7d8f1
--- /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 000000000..9f802b6e4
--- /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 000000000..b8bbae3d7
--- /dev/null
+++ b/connectivity/source/drivers/component/CDatabaseMetaData.cxx
@@ -0,0 +1,240 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * 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( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ rtl::Reference<ODatabaseMetaDataResultSet> pResult = new ODatabaseMetaDataResultSet(::connectivity::ODatabaseMetaDataResultSet::eTypeInfo);
+
+ static ODatabaseMetaDataResultSet::ORows aRows;
+ if(aRows.empty())
+ {
+ 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 000000000..7c5c8e07f
--- /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 000000000..08e6e04ac
--- /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 000000000..f3bd03e8b
--- /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 000000000..83dbf8a68
--- /dev/null
+++ b/connectivity/source/drivers/component/CTable.cxx
@@ -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 .
+ */
+
+#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();
+
+ const Any aRet = ::cppu::queryInterface(rType,static_cast< css::lang::XUnoTunnel*> (this));
+ return aRet.hasValue() ? aRet : 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 000000000..a8aaf89c5
--- /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 000000000..b997ec8d9
--- /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 000000000..c9c7a93fa
--- /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 000000000..bdff15caf
--- /dev/null
+++ b/connectivity/source/drivers/dbase/DDatabaseMetaData.cxx
@@ -0,0 +1,386 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * 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( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ rtl::Reference<::connectivity::ODatabaseMetaDataResultSet> pResult = new ::connectivity::ODatabaseMetaDataResultSet(::connectivity::ODatabaseMetaDataResultSet::eTypeInfo);
+
+ static ODatabaseMetaDataResultSet::ORows aRows;
+ if(aRows.empty())
+ {
+ 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(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(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(getBOOL(xIndex->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISUNIQUE))));
+ aRow[6] = new ORowSetValueDecorator(*pBegin);
+
+ auto pIndex = comphelper::getFromUnoTunnel<ODbaseIndex>(xIndex);
+ 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 000000000..8eae0013c
--- /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 static_cast<cppu::OWeakObject*>(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 000000000..4ac8b1a41
--- /dev/null
+++ b/connectivity/source/drivers/dbase/DIndex.cxx
@@ -0,0 +1,608 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * 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));
+}
+
+const Sequence< sal_Int8 > & ODbaseIndex::getUnoTunnelId()
+{
+ static const comphelper::UnoIdInit implId;
+ return implId.getSeq();
+}
+
+// XUnoTunnel
+
+sal_Int64 ODbaseIndex::getSomething( const Sequence< sal_Int8 > & rId )
+{
+ return comphelper::getSomethingImpl(rId, this,
+ comphelper::FallbackToGetSomethingOf<ODbaseIndex_BASE>{});
+}
+
+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 = OString("NDX");
+ aNewEntry += 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())
+ {
+ Reference< XUnoTunnel> xTunnel(xSet, UNO_QUERY_THROW);
+ ODbaseResultSet* pDbaseRes = comphelper::getFromUnoTunnel<ODbaseResultSet>(xTunnel);
+ assert(pDbaseRes); //"No dbase resultset found? What's going on here!
+ nRowsLeft = xSet->getRow();
+
+ xSet->beforeFirst();
+ ORowSetValue atmpValue;
+ ONDXKey aKey(atmpValue, nType, 0);
+ ONDXKey aInsertKey(atmpValue, 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 000000000..886c7273d
--- /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 000000000..37e28a073
--- /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 000000000..7f47085c6
--- /dev/null
+++ b/connectivity/source/drivers/dbase/DIndexes.cxx
@@ -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 .
+ */
+
+#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 )
+{
+ Reference<XUnoTunnel> xTunnel(descriptor,UNO_QUERY);
+ if(xTunnel.is())
+ {
+ ODbaseIndex* pIndex = comphelper::getFromUnoTunnel<ODbaseIndex>(xTunnel);
+ if(!pIndex)
+ throw SQLException();
+ pIndex->CreateImpl();
+ }
+
+ return createObject( _rForName );
+}
+
+// XDrop
+void ODbaseIndexes::dropObject(sal_Int32 _nPos, const OUString& /*_sElementName*/)
+{
+ auto pIndex = comphelper::getFromUnoTunnel<ODbaseIndex>(getObject(_nPos));
+ 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 000000000..9a2b54409
--- /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 000000000..47b898ada
--- /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 = comphelper::getFromUnoTunnel<dbase::ODbaseIndex>(_xIndex);
+ 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 000000000..d25372327
--- /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 000000000..1f942ad08
--- /dev/null
+++ b/connectivity/source/drivers/dbase/DTable.cxx
@@ -0,0 +1,2769 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * 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 <tools/diagnose_ex.h>
+#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.hasValue() ? aRet : ::cppu::queryInterface(rType,static_cast< css::lang::XUnoTunnel*> (this));
+}
+
+
+const Sequence< sal_Int8 > & ODbaseTable::getUnoTunnelId()
+{
+ static const comphelper::UnoIdInit implId;
+ return implId.getSeq();
+}
+
+// css::lang::XUnoTunnel
+
+sal_Int64 ODbaseTable::getSomething( const Sequence< sal_Int8 > & rId )
+{
+ return comphelper::getSomethingImpl(rId, this,
+ comphelper::FallbackToGetSomethingOf<ODbaseTable_BASE>{});
+}
+
+bool ODbaseTable::fetchRow(OValueRefRow& _rRow, const OSQLColumns & _rCols, bool bRetrieveData)
+{
+ if (!m_pBuffer)
+ return false;
+
+ // Read the data
+ bool bIsCurRecordDeleted = static_cast<char>(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. Use intern() to ref-count it.
+ *(*_rRow)[i] = OUString::intern(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 = OUString::intern(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;
+
+ Reference<XUnoTunnel> xTunnel(xIndex,UNO_QUERY);
+ OSL_ENSURE(xTunnel.is(),"No TunnelImplementation!");
+ ODbaseIndex* pIndex = comphelper::getFromUnoTunnel<ODbaseIndex>(xTunnel);
+ 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
+ {
+ Reference<XUnoTunnel> xTunnel(xIndex,UNO_QUERY);
+ OSL_ENSURE(xTunnel.is(),"No TunnelImplementation!");
+ ODbaseIndex* pIndex = comphelper::getFromUnoTunnel<ODbaseIndex>(xTunnel);
+ 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())
+ {
+ Reference<XUnoTunnel> xTunnel(aIndexedCols[i],UNO_QUERY);
+ OSL_ENSURE(xTunnel.is(),"No TunnelImplementation!");
+ ODbaseIndex* pIndex = comphelper::getFromUnoTunnel<ODbaseIndex>(xTunnel);
+ 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 sTempName(aIdent);
+ OUString sExt("." + m_pConnection->getExtension());
+ OUString sName(m_Name);
+ TempFile aTempFile(sName, true, &sExt, &sTempName);
+ if(!aTempFile.IsValid())
+ getConnection()->throwGenericSQLException(STR_COULD_NOT_ALTER_TABLE, *this);
+
+ INetURLObject aURL;
+ aURL.SetSmartProtocol(INetProtocol::File);
+ aURL.SetURL(aTempFile.GetURL());
+
+ 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.makeStringAndClear(),
+ 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.makeStringAndClear(), 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 000000000..8f63263c1
--- /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 = comphelper::getFromUnoTunnel<ODbaseTable>(descriptor);
+ 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< XUnoTunnel> 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 = comphelper::getFromUnoTunnel<ODbaseTable>(xTunnel);
+ 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 000000000..b078a765d
--- /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 000000000..3ac8b8064
--- /dev/null
+++ b/connectivity/source/drivers/dbase/dindexnode.cxx
@@ -0,0 +1,1046 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * 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>
+
+
+using namespace connectivity;
+using namespace connectivity::dbase;
+using namespace connectivity::file;
+using namespace com::sun::star::sdbc;
+
+ONDXKey::ONDXKey()
+ :nRecord(0)
+{
+}
+
+ONDXKey::ONDXKey(const ORowSetValue& rVal, sal_Int32 eType, sal_uInt32 nRec)
+ : ONDXKey_BASE(eType)
+ , nRecord(nRec)
+ , xValue(rVal)
+{
+}
+
+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 000000000..9ec8e0d44
--- /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 000000000..9a2138eb2
--- /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 000000000..6b409ce66
--- /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 000000000..b2bd80844
--- /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 000000000..5b2b64d5d
--- /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 000000000..f768c51bb
--- /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 000000000..02e8d476d
--- /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 000000000..4d6604f09
--- /dev/null
+++ b/connectivity/source/drivers/evoab2/NConnection.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 "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 );
+
+ OString const & getPassword() const { return m_aPassword; }
+ 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 000000000..dbb8cb447
--- /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 (sal_Int32 i = 0; i < static_cast<sal_Int32>(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( 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 const OUStringLiteral aTable(u"TABLE");
+
+ 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 000000000..a64c234e6
--- /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 000000000..d1b7746f4
--- /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 000000000..9d3b57fa7
--- /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 OUStringLiteral EVOAB_DRIVER_IMPL_NAME = u"com.sun.star.comp.sdbc.evoab.OEvoabDriver";
+
+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 000000000..7b6172ac6
--- /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 <tools/diagnose_ex.h>
+
+#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 000000000..cd42d42d5
--- /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 000000000..53b50a5c3
--- /dev/null
+++ b/connectivity/source/drivers/evoab2/NResultSet.cxx
@@ -0,0 +1,1038 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * 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 <tools/diagnose_ex.h>
+#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 );
+ OString 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, OString &/*rPassword*/) 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 )
+ {
+ OString aPassword = m_pConnection->getPassword();
+ m_pVersionHelper->executeQuery(pBook, _rData.getQuery(), aPassword);
+ m_pConnection->setPassword( aPassword );
+
+ 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 static_cast<cppu::OWeakObject*>(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 000000000..74a5e40dd
--- /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, OString &rPassword) = 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 000000000..a2ce922ff
--- /dev/null
+++ b/connectivity/source/drivers/evoab2/NResultSetMetaData.cxx
@@ -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 .
+ */
+
+#include "NResultSetMetaData.hxx"
+#include "NDatabaseMetaData.hxx"
+#include <connectivity/dbexception.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::sdbc;
+
+OEvoabResultSetMetaData::OEvoabResultSetMetaData(const OUString& _aTableName)
+ : m_aTableName(_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 000000000..66fffb984
--- /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(const 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 000000000..a5554dd06
--- /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 <tools/diagnose_ex.h>
+
+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 000000000..a348c5335
--- /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 000000000..208c52747
--- /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 000000000..0aa30815b
--- /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 000000000..69b54ba70
--- /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 000000000..7e200ff6a
--- /dev/null
+++ b/connectivity/source/drivers/evoab2/NTables.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/sdbcx/VCollection.hxx>
+#include <com/sun/star/sdbc/XDatabaseMetaData.hpp>
+
+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(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/evoab2/evoab.component b/connectivity/source/drivers/evoab2/evoab.component
new file mode 100644
index 000000000..c0928c178
--- /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 000000000..eedda26ef
--- /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 000000000..1b90385bf
--- /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 000000000..90030abb5
--- /dev/null
+++ b/connectivity/source/drivers/file/FConnection.cxx
@@ -0,0 +1,432 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * 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)
+{
+ SQLException aError;
+ aError.Message = getResources().getResourceStringWithSubstitution(
+ STR_NO_VALID_FILE_URL,
+ "$URL$", _rsUrl
+ );
+
+ aError.SQLState = "S1000";
+ aError.ErrorCode = 0;
+ aError.Context = static_cast< XConnection* >(this);
+ if (!_rsMessage.isEmpty())
+ aError.NextException <<= SQLException(_rsMessage, aError.Context, OUString(), 0, Any());
+
+ 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 000000000..6d0a4f2fe
--- /dev/null
+++ b/connectivity/source/drivers/file/FDatabaseMetaData.cxx
@@ -0,0 +1,1055 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * 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 <tools/diagnose_ex.h>
+#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 OUStringLiteral aTable = u"TABLE";
+
+ 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(OUString(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 = comphelper::getFromUnoTunnel<OFileTable>(xTable);
+ 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( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ rtl::Reference<ODatabaseMetaDataResultSet> pResult = new ODatabaseMetaDataResultSet( ODatabaseMetaDataResultSet::eTableTypes );
+ static ODatabaseMetaDataResultSet::ORows aRows;
+ if(aRows.empty())
+ {
+ 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 000000000..1be992d4b
--- /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 000000000..4b6d45fe7
--- /dev/null
+++ b/connectivity/source/drivers/file/FDriver.cxx
@@ -0,0 +1,205 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * 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>
+
+
+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(const css::uno::Reference< css::uno::XComponentContext >& _rxContext)
+ : ODriver_BASE(m_aMutex)
+ ,m_xContext(_rxContext)
+{
+}
+
+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 000000000..920bb3885
--- /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 000000000..7c7fdc754
--- /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 000000000..f2a8571b6
--- /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 000000000..4d0e256b9
--- /dev/null
+++ b/connectivity/source/drivers/file/FResultSet.cxx
@@ -0,0 +1,1593 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * 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 <tools/diagnose_ex.h>
+
+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;
+}
+
+const Sequence< sal_Int8 > & OResultSet::getUnoTunnelId()
+{
+ static const comphelper::UnoIdInit implId;
+ return implId.getSeq();
+}
+
+// css::lang::XUnoTunnel
+
+sal_Int64 OResultSet::getSomething( const Sequence< sal_Int8 > & rId )
+{
+ return comphelper::getSomethingImpl(rId, this);
+}
+
+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)
+{
+ Reference<css::lang::XUnoTunnel> xTunnel(_xTable, UNO_QUERY_THROW);
+ m_pTable = comphelper::getFromUnoTunnel<OFileTable>(xTunnel);
+ 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 000000000..fdc944043
--- /dev/null
+++ b/connectivity/source/drivers/file/FResultSetMetaData.cxx
@@ -0,0 +1,188 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * 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>
+
+
+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(const ::rtl::Reference<connectivity::OSQLColumns>& _rxColumns,const OUString& _aTableName,OFileTable* _pTable)
+ :m_aTableName(_aTableName)
+ ,m_xColumns(_rxColumns)
+ ,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 000000000..d32ac0ed2
--- /dev/null
+++ b/connectivity/source/drivers/file/FStatement.cxx
@@ -0,0 +1,711 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * 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>
+
+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 = comphelper::getFromUnoTunnel<OFileTable>(rTabs.begin()->second);
+ 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 (sal_Int32 i=0; i<static_cast<sal_Int32>(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 000000000..94152bc5d
--- /dev/null
+++ b/connectivity/source/drivers/file/FStringFunctions.cxx
@@ -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 .
+ */
+
+#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();
+ sal_Int32 nIndexOf = sStr.indexOf(sFrom);
+ while (nIndexOf != -1)
+ {
+ sStr = sStr.replaceAt(nIndexOf, sFrom.getLength(), sTo);
+ nIndexOf = sStr.indexOf(sFrom, nIndexOf + sTo.getLength());
+ }
+
+ return sStr;
+}
+
+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 000000000..6ec776452
--- /dev/null
+++ b/connectivity/source/drivers/file/FTable.cxx
@@ -0,0 +1,185 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * 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();
+}
+
+const Sequence< sal_Int8 > & OFileTable::getUnoTunnelId()
+{
+ static const comphelper::UnoIdInit s_Id;
+ return s_Id.getSeq();
+}
+
+// css::lang::XUnoTunnel
+
+sal_Int64 OFileTable::getSomething( const Sequence< sal_Int8 > & rId )
+{
+ return comphelper::getSomethingImpl(rId, this,
+ comphelper::FallbackToGetSomethingOf<OTable_TYPEDEF>{});
+}
+
+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 000000000..c063f4a89
--- /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 000000000..a0d1305f6
--- /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 000000000..d41d3e607
--- /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 000000000..5a1646a20
--- /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 <tools/diagnose_ex.h>
+#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 000000000..f654c709e
--- /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 000000000..33ab36b8d
--- /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 <tools/diagnose_ex.h>
+
+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 000000000..990108934
--- /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 000000000..2ef4f514b
--- /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 000000000..3ffb9238e
--- /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 000000000..dde050ede
--- /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 000000000..7fc5459d5
--- /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 000000000..0a18ebe5b
--- /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 000000000..c66287ce5
--- /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 000000000..200eec1fb
--- /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 000000000..a211f70d1
--- /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 000000000..9230eb22f
--- /dev/null
+++ b/connectivity/source/drivers/firebird/Connection.cxx
@@ -0,0 +1,984 @@
+/* -*- 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 OUStringLiteral our_sFDBLocation( u"firebird.fdb" );
+/**
+ * Older version of LO may store the database in a .fdb file
+ */
+constexpr OUStringLiteral our_sFBKLocation( u"firebird.fbk" );
+
+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::TempFile(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(OUString("sdbc:firebird:").getLength());
+ 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";
+ userPassword = "masterkey";
+ }
+ 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 )
+{
+ MutexGuard aGuard( m_aMutex );
+ // 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);
+
+
+ OStringBuffer aRequest; // byte array
+
+
+ aRequest.append(static_cast<char>(nAction));
+
+ aRequest.append(char(isc_spb_dbname)); // .fdb
+ sal_uInt16 nFDBLength = sFDBPath.getLength();
+ aRequest.append(static_cast<char>(nFDBLength & 0xFF)); // least significant byte first
+ aRequest.append(static_cast<char>((nFDBLength >> 8) & 0xFF));
+ aRequest.append(sFDBPath);
+
+ aRequest.append(char(isc_spb_bkp_file)); // .fbk
+ sal_uInt16 nFBKLength = sFBKPath.getLength();
+ aRequest.append(static_cast<char>(nFBKLength & 0xFF));
+ aRequest.append(static_cast<char>((nFBKLength >> 8) & 0xFF));
+ aRequest.append(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 000000000..9fdb0d4d3
--- /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::TempFile > 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 000000000..cfee4f41b
--- /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(true); // Nullable
+ aRow[8] = new ORowSetValueDecorator(true); // Case sensitive
+ aRow[10] = new ORowSetValueDecorator(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(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(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(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(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(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(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(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(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(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(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(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(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(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 000000000..c577f594d
--- /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 000000000..3a1b80292
--- /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 OUStringLiteral our_sFirebirdTmpVar = u"FIREBIRD_TMP";
+constexpr OUStringLiteral our_sFirebirdLockVar = u"FIREBIRD_LOCK";
+constexpr OUStringLiteral our_sFirebirdMsgVar = u"FIREBIRD_MSG";
+#ifdef MACOSX
+constexpr OUStringLiteral our_sFirebirdLibVar = u"LIBREOFFICE_FIREBIRD_LIB";
+#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(OUString(our_sFirebirdTmpVar).pData, m_firebirdTMPDirectory.GetFileName().pData);
+
+ // Overrides firebird's default of /tmp/firebird or c:\temp\firebird
+ osl_setEnvironment(OUString(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(OUString(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(OUString(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(OUString(our_sFirebirdTmpVar).pData);
+ osl_clearEnvironment(OUString(our_sFirebirdLockVar).pData);
+
+#ifndef SYSTEM_FIREBIRD
+ osl_clearEnvironment(OUString(our_sFirebirdMsgVar).pData);
+#ifdef MACOSX
+ osl_clearEnvironment(OUString(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 000000000..06841d937
--- /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::TempFile m_firebirdTMPDirectory;
+ ::utl::TempFile 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 000000000..10ec90dc5
--- /dev/null
+++ b/connectivity/source/drivers/firebird/Indexes.cxx
@@ -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/.
+ */
+
+#include "Indexes.hxx"
+
+using namespace ::connectivity;
+using namespace ::connectivity::firebird;
+
+using namespace ::osl;
+using namespace ::std;
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::sdbc;
+
+Indexes::Indexes(Table* pTable, Mutex& rMutex, const 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 000000000..12d7dd198
--- /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 000000000..8de112ec6
--- /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 000000000..4e9ba5a7e
--- /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 000000000..816c38d5c
--- /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 sBuffer.makeStringAndClear().toInt64();
+ }
+}
+
+}
+
+//----- 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,
+ OUStringConcatenation("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 000000000..3e61436b5
--- /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 000000000..ea3ac86ae
--- /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 000000000..fdae21dfb
--- /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 000000000..5653d29c4
--- /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 = '"
+ + escapeWith(sTable, '\'', '\'') + "' AND "
+ "relfields.RDB$FIELD_NAME = '"+ escapeWith(sColumnName, '\'', '\'') +"'";
+
+ 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 = '"
+ + escapeWith(sTable, '\'', '\'') + "' AND "
+ "RDB$FIELD_NAME = '"+ escapeWith(sColumnName, '\'', '\'') +"'";
+
+ 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 = '"
+ + escapeWith(getTableName(column), '\'', '\'') + "' AND "
+ "RDB$RELATION_FIELDS.RDB$FIELD_NAME = '"
+ + escapeWith(sColumnName, '\'', '\'') +"'";
+ 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 000000000..a32c20621
--- /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 000000000..f4faebbf1
--- /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;
+using namespace ::std;
+
+// ---- 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);
+ checkDisposed(OStatementCommonBase_Base::rBHelper.bDisposed);
+
+ 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 000000000..d1b967def
--- /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 000000000..df4d971e8
--- /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;
+using namespace ::std;
+
+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:
+ 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 000000000..fa9cd7902
--- /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 000000000..bea5d76d4
--- /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 000000000..c32160b99
--- /dev/null
+++ b/connectivity/source/drivers/firebird/Table.cxx
@@ -0,0 +1,245 @@
+/* -*- 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;
+ // Dirty hack: can't change null directly in sql, we have to fiddle
+ // the system tables manually.
+ if (nNullable == ColumnValue::NULLABLE)
+ {
+ sSql = "UPDATE RDB$RELATION_FIELDS SET RDB$NULL_FLAG = NULL "
+ "WHERE RDB$FIELD_NAME = '" + rColName + "' "
+ "AND RDB$RELATION_NAME = '" + getName() + "'";
+ }
+ else if (nNullable == ColumnValue::NO_NULLS)
+ {
+ // And if we are making NOT NULL then we have to make sure we have
+ // no nulls left in the column.
+ OUString sFillNulls("UPDATE \"" + getName() + "\" SET \""
+ + rColName + "\" = 0 "
+ "WHERE \"" + rColName + "\" IS NULL");
+ getConnection()->createStatement()->execute(sFillNulls);
+
+ sSql = "UPDATE RDB$RELATION_FIELDS SET RDB$NULL_FLAG = 1 "
+ "WHERE RDB$FIELD_NAME = '" + rColName + "' "
+ "AND RDB$RELATION_NAME = '" + getName() + "'";
+ }
+ 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 000000000..ed638a9c8
--- /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 000000000..936e1465c
--- /dev/null
+++ b/connectivity/source/drivers/firebird/Tables.cxx
@@ -0,0 +1,229 @@
+/* -*- 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(" ");
+
+ 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(" ");
+ aSql.append("CHARACTER SET OCTETS");
+ }
+ }
+
+ if ( bIsAutoIncrement && !sAutoIncrementValue.isEmpty())
+ {
+ aSql.append(" ");
+ 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);
+ aSqlBuffer.append(" (");
+
+ // 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));
+ aSqlBuffer.append(",");
+ }
+ }
+ 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 000000000..7d84edb20
--- /dev/null
+++ b/connectivity/source/drivers/firebird/Tables.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 <com/sun/star/sdbc/XConnection.hpp>
+#include <com/sun/star/sdbc/XDatabaseMetaData.hpp>
+
+#include <connectivity/sdbcx/VCollection.hxx>
+
+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(const css::uno::Reference< css::sdbc::XDatabaseMetaData >& rMetaData,
+ ::cppu::OWeakObject& rParent,
+ ::osl::Mutex& rMutex,
+ ::std::vector< OUString> const & rNames) : sdbcx::OCollection(rParent, true, rMutex, rNames), m_xMetaData(rMetaData) {}
+
+ // 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 000000000..9f647713a
--- /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 000000000..e47565f5d
--- /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 000000000..50cfef84b
--- /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 000000000..7e78444d1
--- /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 000000000..c015f2d47
--- /dev/null
+++ b/connectivity/source/drivers/firebird/Util.cxx
@@ -0,0 +1,440 @@
+/* -*- 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*");
+ buf.append(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;
+ }
+ }
+}
+
+
+OUString firebird::escapeWith( const OUString& sText, const char aKey, const char aEscapeChar)
+{
+ OUString sRet(sText);
+ sal_Int32 aIndex = 0;
+ for (;;)
+ {
+ aIndex = sRet.indexOf(aKey, aIndex);
+ if ( aIndex <= 0 || aIndex >= sRet.getLength())
+ break;
+ sRet = sRet.replaceAt(aIndex, 1, rtl::OUStringConcatenation(OUStringChar(aEscapeChar) + OUStringChar(aKey)) );
+ aIndex += 2;
+ }
+
+ return sRet;
+}
+
+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 000000000..bf1a172ed
--- /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>
+
+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, const OUString& sCharset = OUString() )
+ : m_aType(aType)
+ , m_aSubType(aSubType)
+ , m_nScale(nScale)
+ , m_sCharsetName(sCharset) {}
+ explicit ColumnTypeInfo( short aType, const OUString& sCharset )
+ : m_aType(aType)
+ , m_aSubType(0)
+ , m_nScale(0)
+ , m_sCharsetName(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);
+
+ OUString escapeWith( const OUString& sText, const char aKey, const char aEscapeChar);
+ 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 000000000..6dcbf6bce
--- /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 000000000..2b300a8d0
--- /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 000000000..2e5bec42a
--- /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 000000000..6887bdc66
--- /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 000000000..d80755a24
--- /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 000000000..aed042fdd
--- /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 000000000..a9e210321
--- /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 000000000..288a53fa6
--- /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 000000000..b711645b5
--- /dev/null
+++ b/connectivity/source/drivers/flat/EDatabaseMetaData.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 <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( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ 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 000000000..294928955
--- /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 static_cast<cppu::OWeakObject*>(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 000000000..f4095ac2c
--- /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 000000000..9d1975c77
--- /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 000000000..dc801ac48
--- /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 000000000..bd6be38d7
--- /dev/null
+++ b/connectivity/source/drivers/flat/ETable.cxx
@@ -0,0 +1,961 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * 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.hasValue() ? aRet : ::cppu::queryInterface(rType,static_cast< css::lang::XUnoTunnel*> (this));
+}
+
+
+const Sequence< sal_Int8 > & OFlatTable::getUnoTunnelId()
+{
+ static const comphelper::UnoIdInit implId;
+ return implId.getSeq();
+}
+
+// css::lang::XUnoTunnel
+
+sal_Int64 OFlatTable::getSomething( const Sequence< sal_Int8 > & rId )
+{
+ return comphelper::getSomethingImpl(rId, this,
+ comphelper::FallbackToGetSomethingOf<OFlatTable_BASE>{});
+}
+
+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(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 000000000..2e4dd377e
--- /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 000000000..715fbecd8
--- /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 000000000..1074be535
--- /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 000000000..3f03c3616
--- /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 000000000..506bf5b07
--- /dev/null
+++ b/connectivity/source/drivers/hsqldb/HConnection.cxx
@@ -0,0 +1,337 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * 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 <tools/diagnose_ex.h>
+
+#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;
+ sSQL.append( "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 000000000..c18a46e84
--- /dev/null
+++ b/connectivity/source/drivers/hsqldb/HDriver.cxx
@@ -0,0 +1,894 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * 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 <tools/diagnose_ex.h>
+#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 OUStringLiteral IMPL_NAME = u"com.sun.star.sdbcx.comp.hsqldb.Driver";
+
+
+
+ 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 const OUStringLiteral sProperties( u"properties" );
+ 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 const OUStringLiteral sScript(u"script");
+ 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() )
+ {
+ Reference<XTransactionListener> xListener(*this,UNO_QUERY);
+ xBroad->addTransactionListener(xListener);
+ }
+ }
+ }
+ }
+ 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;
+ aStatement.append( "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 000000000..36ef9f287
--- /dev/null
+++ b/connectivity/source/drivers/hsqldb/HStorageAccess.cxx
@@ -0,0 +1,511 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * 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 <tools/diagnose_ex.h>
+
+#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);
+ Reference< XSeekable> xSeek = pHelper ? pHelper->getSeek() : Reference< XSeekable>();
+
+ 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 000000000..aba88f192
--- /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 <tools/diagnose_ex.h>
+
+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,const OUString& _sFileURL)
+ {
+ return OUString(_sURL.substr(_sFileURL.getLength()+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 000000000..42ca7b527
--- /dev/null
+++ b/connectivity/source/drivers/hsqldb/HTable.cxx
@@ -0,0 +1,386 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * 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 <tools/diagnose_ex.h>
+
+
+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);
+}
+
+const Sequence< sal_Int8 > & OHSQLTable::getUnoTunnelId()
+{
+ static const comphelper::UnoIdInit implId;
+ return implId.getSeq();
+}
+
+// css::lang::XUnoTunnel
+
+sal_Int64 OHSQLTable::getSomething( const Sequence< sal_Int8 > & rId )
+{
+ return comphelper::getSomethingImpl(rId, this,
+ comphelper::FallbackToGetSomethingOf<OTable_TYPEDEF>{});
+}
+
+// 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 000000000..de99a3b04
--- /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 000000000..a9df5ccc9
--- /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 000000000..baf66e90e
--- /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 000000000..3dd388ace
--- /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 000000000..2ed0c0626
--- /dev/null
+++ b/connectivity/source/drivers/hsqldb/HUser.cxx
@@ -0,0 +1,328 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * 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>
+
+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( const css::uno::Reference< css::sdbc::XConnection >& _xConnection) : connectivity::sdbcx::OUser(true)
+ ,m_xConnection(_xConnection)
+{
+ construct();
+}
+
+OHSQLUser::OHSQLUser( const css::uno::Reference< css::sdbc::XConnection >& _xConnection,
+ const OUString& Name
+ ) : connectivity::sdbcx::OUser(Name,true)
+ ,m_xConnection(_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 000000000..9fe31e58e
--- /dev/null
+++ b/connectivity/source/drivers/hsqldb/HUsers.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 <hsqldb/HUsers.hxx>
+#include <hsqldb/HUser.hxx>
+#include <connectivity/sdbcx/IRefreshable.hxx>
+#include <comphelper/types.hxx>
+#include <connectivity/dbtools.hxx>
+#include <TConnection.hxx>
+
+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,
+ const css::uno::Reference< css::sdbc::XConnection >& _xConnection,
+ connectivity::sdbcx::IRefreshableUsers* _pParent)
+ : sdbcx::OCollection(_rParent, true, _rMutex, _rVector)
+ ,m_xConnection(_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 000000000..29e5a4000
--- /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 <tools/diagnose_ex.h>
+#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;
+ aCommand.append( "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 000000000..1f4b80748
--- /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 000000000..e352f78fb
--- /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 <tools/diagnose_ex.h>
+
+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 000000000..4fcbbc5aa
--- /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 <tools/diagnose_ex.h>
+#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 000000000..f766696e0
--- /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 000000000..f7e0f10ee
--- /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 000000000..81db98ae7
--- /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 000000000..a541e02aa
--- /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 000000000..d03b01928
--- /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 000000000..4531fc9b8
--- /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 000000000..5709674f3
--- /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 000000000..884de3d4c
--- /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 000000000..862827d12
--- /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 000000000..6108981ac
--- /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 000000000..96a82fb61
--- /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 000000000..3ab1b88eb
--- /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 000000000..2633fd09b
--- /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 000000000..6086e8190
--- /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 000000000..3fb157fb2
--- /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 000000000..9fa2d5c18
--- /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 000000000..c384760b3
--- /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 000000000..7cbcd6486
--- /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 000000000..19391e60e
--- /dev/null
+++ b/connectivity/source/drivers/jdbc/JConnection.cxx
@@ -0,0 +1,803 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * 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 <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 const & theClassPath, OUString const & theClassName):
+ classPath(theClassPath), className(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;
+ aWarning.Context = aAsException.Context;
+ aWarning.Message = aAsException.Message;
+ aWarning.SQLState = aAsException.SQLState;
+ aWarning.ErrorCode = aAsException.ErrorCode;
+ aWarning.NextException = 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 000000000..f294d30b4
--- /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 000000000..c94f0fd68
--- /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 <tools/diagnose_ex.h>
+#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,*static_cast<cppu::OWeakObject*>(this))));
+ }
+
+ 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 000000000..f05eced9d
--- /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 000000000..33aadcbca
--- /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 000000000..85d02e87a
--- /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 000000000..12ce9fda8
--- /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 000000000..c274c521c
--- /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 000000000..fdf5bfe69
--- /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 000000000..9374407d1
--- /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 000000000..487665d7d
--- /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 000000000..e229ef54a
--- /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 000000000..db4bb8920
--- /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 000000000..eb7624719
--- /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 000000000..86a6a079b
--- /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 000000000..4a4d5069e
--- /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 000000000..02d4faf74
--- /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 const OUString aDefaultTableName
+ (OUString("Address Book"));
+
+ 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 000000000..a23e0c1eb
--- /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 000000000..96ff62fd5
--- /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 const OUString sDot = ".";
+ 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 000000000..1757bb908
--- /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 000000000..6a49ad1d0
--- /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 000000000..7123af89d
--- /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 000000000..eaa6cf523
--- /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 000000000..dc2bfa34f
--- /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 000000000..b54b844c9
--- /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 OUStringLiteral aTable = u"TABLE";
+ 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(OUString(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 000000000..662be1c01
--- /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 000000000..4667c690a
--- /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 <tools/diagnose_ex.h>
+#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)!");
+
+ const OUString sModuleName( SAL_MODULENAME( "macabdrv1" ) );
+ 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 000000000..d18f5e982
--- /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 000000000..a57f1729f
--- /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 000000000..ddcd47b46
--- /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 000000000..da270dd05
--- /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 000000000..24b3fc7b0
--- /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 000000000..6d72345b6
--- /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 000000000..6e649bf64
--- /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 000000000..3072e1eaa
--- /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 000000000..5184eefc8
--- /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 000000000..17ee6585d
--- /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.
+ */
+ bool bFoundRequiredProperties[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 000000000..8d0d5cf6f
--- /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 000000000..4142fcb6c
--- /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 000000000..306ef562d
--- /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 000000000..e08d92cfc
--- /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 000000000..b82088154
--- /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 000000000..95b922ce6
--- /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 000000000..700a895c0
--- /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 000000000..1628cd297
--- /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 000000000..897d589cc
--- /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 000000000..e7149d264
--- /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 000000000..0b0d841b7
--- /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 000000000..7cbc0d9c8
--- /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 000000000..41e087b2c
--- /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 000000000..32e7b7071
--- /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 000000000..133e5d599
--- /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 000000000..e5eb6c987
--- /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 000000000..cfe46f37f
--- /dev/null
+++ b/connectivity/source/drivers/macab/macabutilities.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 <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);
+
+ UniChar unichars[nStringLength+1];
+
+ //'close' the string buffer correctly
+ unichars[nStringLength] = '\0';
+
+ CFStringGetCharacters (sOrig, CFRangeMake(0,nStringLength), unichars);
+ CFRelease(sOrig);
+
+ return OUString(reinterpret_cast<sal_Unicode *>(unichars));
+ }
+
+
+ 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 000000000..faa2063b2
--- /dev/null
+++ b/connectivity/source/drivers/mozab/bootstrap/MMozillaBootstrap.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 <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;
+using ::com::sun::star::lang::XSingleServiceFactory;
+using ::com::sun::star::lang::XMultiServiceFactory;
+
+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 000000000..e01a2bb96
--- /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 000000000..71c70c641
--- /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 000000000..90674a0f4
--- /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 000000000..a146d0c09
--- /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 000000000..27746364a
--- /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 000000000..18d95cdbd
--- /dev/null
+++ b/connectivity/source/drivers/mozab/bootstrap/MNSProfileDiscover.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 "MNSProfileDiscover.hxx"
+#include "MNSFolders.hxx"
+#include "MNSINIParser.hxx"
+
+namespace connectivity::mozab
+{
+ ProfileStruct::ProfileStruct()
+ {
+ }
+
+ ProfileStruct::ProfileStruct(const OUString& aProfileName,
+ const OUString& aProfilePath)
+ : profileName(aProfileName)
+ , profilePath(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 000000000..a5f271183
--- /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(const OUString& aProfileName, const 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 000000000..cea68d86c
--- /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 000000000..bfc0afe38
--- /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 000000000..9c0afb55a
--- /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 000000000..54beb77ca
--- /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 000000000..0f8357abd
--- /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 OUStringLiteral s_sCharSetOp = u"useUnicode=true&";
+ 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 000000000..3dfdfbdae
--- /dev/null
+++ b/connectivity/source/drivers/mysql_jdbc/YTable.cxx
@@ -0,0 +1,327 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * 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);
+}
+
+const Sequence<sal_Int8>& OMySQLTable::getUnoTunnelId()
+{
+ static const comphelper::UnoIdInit implId;
+ return implId.getSeq();
+}
+
+// css::lang::XUnoTunnel
+
+sal_Int64 OMySQLTable::getSomething(const Sequence<sal_Int8>& rId)
+{
+ return comphelper::getSomethingImpl(rId, this,
+ comphelper::FallbackToGetSomethingOf<OTable_TYPEDEF>{});
+}
+
+// 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 000000000..c28f8e44e
--- /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::OUStringConcatenation(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 000000000..b683fe2b2
--- /dev/null
+++ b/connectivity/source/drivers/mysql_jdbc/YUser.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 <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>
+
+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(const css::uno::Reference<css::sdbc::XConnection>& _xConnection)
+ : connectivity::sdbcx::OUser(true)
+ , m_xConnection(_xConnection)
+{
+ construct();
+}
+
+OMySQLUser::OMySQLUser(const css::uno::Reference<css::sdbc::XConnection>& _xConnection,
+ const OUString& Name)
+ : connectivity::sdbcx::OUser(Name, true)
+ , m_xConnection(_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 000000000..ed33cb0e2
--- /dev/null
+++ b/connectivity/source/drivers/mysql_jdbc/YUsers.cxx
@@ -0,0 +1,91 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * 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>
+
+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,
+ const css::uno::Reference<css::sdbc::XConnection>& _xConnection,
+ connectivity::sdbcx::IRefreshableUsers* _pParent)
+ : sdbcx::OCollection(_rParent, true, _rMutex, _rVector)
+ , m_xConnection(_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 000000000..3dba721c0
--- /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 000000000..7ecd7a441
--- /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 000000000..e4295110f
--- /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 000000000..d8b9db742
--- /dev/null
+++ b/connectivity/source/drivers/mysqlc/mysqlc_catalog.cxx
@@ -0,0 +1,70 @@
+/* -*- 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"
+
+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()
+{
+ // TODO: implement me
+}
+
+/* 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 000000000..1bea18c76
--- /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 000000000..ceb743738
--- /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 000000000..f69ef1afc
--- /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 000000000..b34b36b45
--- /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 000000000..34230db37
--- /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 000000000..d56993f89
--- /dev/null
+++ b/connectivity/source/drivers/mysqlc/mysqlc_connection.cxx
@@ -0,0 +1,524 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * 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" };
+ 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,
+ OString{ "SET session sql_mode='ANSI_QUOTES,NO_AUTO_VALUE_ON_ZERO'" });
+ lcl_executeUpdate(&m_mysql, OString{ "SET NAMES utf8mb4" });
+}
+
+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*/)
+{
+ MutexGuard aGuard(m_aMutex);
+
+ // 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 000000000..3a0ccf36b
--- /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 000000000..109ae2c1c
--- /dev/null
+++ b/connectivity/source/drivers/mysqlc/mysqlc_databasemetadata.cxx
@@ -0,0 +1,1051 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * 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");
+ 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 '");
+ buffer.append(types[0]);
+ buffer.append("'");
+ }
+ else if (types.getLength() > 1)
+ {
+ buffer.append("AND (TABLE_TYPE LIKE '");
+ buffer.append(types[0]);
+ buffer.append("'");
+ for (sal_Int32 i = 1; i < types.getLength(); ++i)
+ {
+ buffer.append(" OR TABLE_TYPE LIKE '");
+ buffer.append(types[i]);
+ buffer.append("'");
+ }
+ 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*/)
+{
+ // TODO
+ SAL_WARN("connectivity.mysqlc", "method not implemented");
+ throw SQLException("getTablePrivileges method not implemented", *this, "IM001", 0, Any());
+}
+
+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 000000000..caed92f20
--- /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 000000000..37a14e822
--- /dev/null
+++ b/connectivity/source/drivers/mysqlc/mysqlc_driver.cxx
@@ -0,0 +1,149 @@
+/* -*- 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"
+
+using namespace css::uno;
+using namespace css::lang;
+using namespace css::beans;
+using namespace css::sdbc;
+using namespace css::sdbcx;
+using namespace connectivity::mysqlc;
+
+#include <cppuhelper/supportsservice.hxx>
+#include <comphelper/servicehelper.hxx>
+
+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 000000000..a29040892
--- /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 000000000..bc5777041
--- /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 000000000..16236e153
--- /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 000000000..c496f9c21
--- /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 000000000..4c918d184
--- /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 000000000..7706844f2
--- /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 000000000..9d0a9ef1c
--- /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 000000000..90d0e3d87
--- /dev/null
+++ b/connectivity/source/drivers/mysqlc/mysqlc_prepared_resultset.cxx
@@ -0,0 +1,1129 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * 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>
+
+using namespace rtl;
+
+#include <cstdlib>
+
+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;
+
+#include <typeindex>
+
+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<css::uno::XWeak>(static_cast<OWeakObject*>(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 000000000..0be8e2ab3
--- /dev/null
+++ b/connectivity/source/drivers/mysqlc/mysqlc_prepared_resultset.hxx
@@ -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 .
+ */
+
+#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::sdbc::SQLException;
+using ::com::sun::star::uno::Any;
+using ::com::sun::star::uno::RuntimeException;
+
+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 000000000..3c1c6d88e
--- /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{ sAscii.getStr() };
+ 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 000000000..d280bd935
--- /dev/null
+++ b/connectivity/source/drivers/mysqlc/mysqlc_preparedstatement.hxx
@@ -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 .
+ */
+
+#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::SQLException;
+using ::com::sun::star::sdbc::XResultSetMetaData;
+using ::com::sun::star::uno::Any;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::RuntimeException;
+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 000000000..113b28a2f
--- /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 000000000..f1c23ca48
--- /dev/null
+++ b/connectivity/source/drivers/mysqlc/mysqlc_resultset.cxx
@@ -0,0 +1,1112 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * 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<css::uno::XWeak>(static_cast<OWeakObject*>(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(std::string_view(sVal.getStr(), 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 000000000..8114cddc9
--- /dev/null
+++ b/connectivity/source/drivers/mysqlc/mysqlc_resultset.hxx
@@ -0,0 +1,275 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except 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::sdbc::SQLException;
+using ::com::sun::star::uno::Any;
+using ::com::sun::star::uno::RuntimeException;
+
+/*
+ ** 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 000000000..84cd6be2a
--- /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 000000000..c2e5db5f3
--- /dev/null
+++ b/connectivity/source/drivers/mysqlc/mysqlc_resultsetmetadata.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 "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
+{
+using ::com::sun::star::sdbc::SQLException;
+using ::com::sun::star::uno::RuntimeException;
+using ::com::sun::star::uno::RuntimeException;
+
+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 000000000..6e4e2fbb5
--- /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 000000000..ea3783a95
--- /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 000000000..464051b72
--- /dev/null
+++ b/connectivity/source/drivers/mysqlc/mysqlc_statement.hxx
@@ -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 .
+ */
+
+#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::SQLException;
+using ::com::sun::star::sdbc::SQLWarning;
+using ::com::sun::star::uno::Any;
+using ::com::sun::star::uno::RuntimeException;
+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 000000000..edba70a93
--- /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 000000000..13d748099
--- /dev/null
+++ b/connectivity/source/drivers/mysqlc/mysqlc_table.cxx
@@ -0,0 +1,160 @@
+/* -*- 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("ALTER TABLE `" + getTableName() + "` 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("ALTER TABLE `" + getName() + "` 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::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 000000000..f17a32687
--- /dev/null
+++ b/connectivity/source/drivers/mysqlc/mysqlc_table.hxx
@@ -0,0 +1,65 @@
+/* -*- 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;
+};
+
+} // 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 000000000..81498978d
--- /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 000000000..2d3c4c745
--- /dev/null
+++ b/connectivity/source/drivers/mysqlc/mysqlc_tables.hxx
@@ -0,0 +1,56 @@
+/* -*- 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>
+
+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(const css::uno::Reference<css::sdbc::XDatabaseMetaData>& rMetaData,
+ ::cppu::OWeakObject& rParent, ::osl::Mutex& rMutex,
+ ::std::vector<OUString> const& rNames)
+ : sdbcx::OCollection(rParent, true, rMutex, rNames)
+ , m_xMetaData(rMetaData)
+ {
+ }
+
+ 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 000000000..ca473cebd
--- /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 000000000..9f2db7715
--- /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 000000000..65470be59
--- /dev/null
+++ b/connectivity/source/drivers/mysqlc/mysqlc_user.cxx
@@ -0,0 +1,55 @@
+/* -*- 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_user.hxx"
+
+using namespace ::connectivity;
+using namespace ::connectivity::mysqlc;
+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 */)
+{
+ // TODO: implement
+}
+
+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/mysqlc/mysqlc_user.hxx b/connectivity/source/drivers/mysqlc/mysqlc_user.hxx
new file mode 100644
index 000000000..e9e37e3fa
--- /dev/null
+++ b/connectivity/source/drivers/mysqlc/mysqlc_user.hxx
@@ -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/.
+ */
+
+#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(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::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 000000000..86837381d
--- /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 000000000..845015249
--- /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 000000000..1c79c9225
--- /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 000000000..14570fc8d
--- /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 000000000..7ae8c4680
--- /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 000000000..ce3f107e2
--- /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 000000000..5fbe8bf8f
--- /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 000000000..df7b3fd20
--- /dev/null
+++ b/connectivity/source/drivers/odbc/ODriver.cxx
@@ -0,0 +1,192 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * 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>
+
+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(const css::uno::Reference< css::uno::XComponentContext >& _rxContext)
+ :ODriver_BASE(m_aMutex)
+ ,m_xContext(_rxContext)
+ ,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 000000000..951eb8b36
--- /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 000000000..d5852c9ea
--- /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 000000000..28c054b45
--- /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 000000000..9e68cd176
--- /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 000000000..21b95c6a7
--- /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 000000000..da50e01f1
--- /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()));
+ aBatchSql.append(";");
+ }
+
+ 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 000000000..4781415de
--- /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 000000000..4d3348378
--- /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 000000000..8c5a6ff05
--- /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 000000000..a14ab2c96
--- /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 000000000..841ed70c6
--- /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 000000000..b847d646a
--- /dev/null
+++ b/connectivity/source/drivers/postgresql/pq_array.hxx
@@ -0,0 +1,97 @@
+/* -*- 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 <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(
+ const rtl::Reference< comphelper::RefCountedMutex > & mutex,
+ std::vector< css::uno::Any > && data,
+ const css::uno::Reference< css::uno::XInterface > & owner,
+ const css::uno::Reference< css::script::XTypeConverter > &tc) :
+ m_data( std::move(data) ),
+ m_owner( owner ),
+ m_tc( tc ),
+ m_xMutex( 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 000000000..9ff5e01e0
--- /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 000000000..90e6609a0
--- /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 000000000..6661a97d5
--- /dev/null
+++ b/connectivity/source/drivers/postgresql/pq_connection.cxx
@@ -0,0 +1,571 @@
+/* -*- 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 <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( const ::rtl::ByteSequence & id , Connection *that )
+ : m_conn( that ), m_id( 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,
+ const css::uno::Reference< css::uno::XComponentContext > & ctx )
+ : ConnectionBase( refMutex->GetMutex() ),
+ m_ctx( 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 000000000..f30483f70
--- /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,
+ const 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 000000000..7da57d1b6
--- /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>
+
+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(
+ const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex,
+ const css::uno::Reference< css::sdbc::XConnection > & origin,
+ ConnectionSettings *pSettings )
+ : m_xMutex( refMutex ),
+ m_pSettings( pSettings ),
+ m_origin( 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( const OUString &name, const OUString & type ) :
+ typeName( name ),
+ typeType( 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 = " );
+ queryBuf.append( 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 000000000..134f72cf0
--- /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(
+ const ::rtl::Reference< comphelper::RefCountedMutex > & reMutex,
+ const 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 000000000..09fe61ab2
--- /dev/null
+++ b/connectivity/source/drivers/postgresql/pq_driver.cxx
@@ -0,0 +1,148 @@
+/* -*- 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 osl::MutexGuard;
+
+using com::sun::star::lang::XSingleComponentFactory;
+using com::sun::star::lang::XServiceInfo;
+using com::sun::star::lang::XComponent;
+
+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 000000000..31d407f36
--- /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 000000000..a75897ccb
--- /dev/null
+++ b/connectivity/source/drivers/postgresql/pq_fakedupdateableresultset.cxx
@@ -0,0 +1,214 @@
+/* -*- 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>
+
+
+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,
+ const OUString &aReason )
+ : ResultSet( mutex, owner, pSettings, result, schema, table ),
+ m_aReason( 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 000000000..c2907aeb0
--- /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,
+ const 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 000000000..2f31b4226
--- /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>
+
+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,
+ const OString & stmt )
+ : PreparedStatement_BASE(refMutex->GetMutex())
+ , OPropertySetHelper(PreparedStatement_BASE::rBHelper)
+ , m_connection(conn)
+ , m_pSettings(pSettings)
+ , m_stmt(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: ");
+ buf.append(
+ OUString( errorMsg, strlen(errorMsg) , ConnectionSettings::encoding ) );
+ buf.append( " (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] = OString( "NULL" );
+}
+
+void PreparedStatement::setObjectNull(
+ sal_Int32 parameterIndex, sal_Int32, const OUString& )
+{
+ MutexGuard guard( m_xMutex->GetMutex() );
+ checkClosed();
+ checkColumnIndex( parameterIndex );
+ m_vars[parameterIndex-1] = OString( "NULL" );
+}
+
+
+void PreparedStatement::setBoolean( sal_Int32 parameterIndex, sal_Bool x )
+{
+ MutexGuard guard(m_xMutex->GetMutex() );
+ checkClosed();
+ checkColumnIndex( parameterIndex );
+ if( x )
+ m_vars[parameterIndex-1] = OString( "'t'" );
+ else
+ m_vars[parameterIndex-1] = OString( "'f'" );
+}
+
+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 000000000..4755efbe0
--- /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,
+ const 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 000000000..556bae92d
--- /dev/null
+++ b/connectivity/source/drivers/postgresql/pq_resultset.cxx
@@ -0,0 +1,308 @@
+/* -*- 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>
+
+
+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,
+ const OUString &schema,
+ const OUString &table)
+ : BaseResultSet(
+ refMutex, owner, PQntuples( result ),
+ PQnfields( result ),(*ppSettings)->tc ),
+ m_result( result ),
+ m_schema( schema ),
+ m_table( 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 000000000..340e34b70
--- /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,
+ const OUString &schema,
+ const 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 000000000..fbe10f82d
--- /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 <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(
+ const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex,
+ const css::uno::Reference< css::sdbc::XResultSet > & origin,
+ ResultSet * pResultSet,
+ ConnectionSettings **ppSettings,
+ PGresult const *pResult,
+ const OUString &schemaName,
+ const OUString &tableName ) :
+ m_xMutex( refMutex ),
+ m_ppSettings( ppSettings ),
+ m_origin( origin ),
+ m_tableName( tableName ),
+ m_schemaName( 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=" );
+ buf.append( 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 000000000..67e34d44d
--- /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(
+ const ::rtl::Reference< comphelper::RefCountedMutex > & reMutex,
+ const css::uno::Reference< css::sdbc::XResultSet > & origin,
+ ResultSet *pResultSet,
+ ConnectionSettings **pSettings,
+ PGresult const *pResult,
+ const OUString &schemaName,
+ const 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 000000000..defb99906
--- /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 000000000..64ac212b6
--- /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 000000000..568e6bb9f
--- /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 000000000..3cd32ff66
--- /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 000000000..7db4b2053
--- /dev/null
+++ b/connectivity/source/drivers/postgresql/pq_statement.cxx
@@ -0,0 +1,888 @@
+/* -*- 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 <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 ) );
+ buf.append( " (caused by statement '" );
+ buf.append( OStringToOUString( sql, ConnectionSettings::encoding ) );
+ buf.append( "')" );
+ 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 !)
+ int i;
+ for( i = 0 ; i < static_cast<int>(sourceTableKeys.size()) ; i ++ )
+ {
+ if( -1 == PQfnumber(
+ result,
+ OUStringToOString( sourceTableKeys[i] ,
+ ConnectionSettings::encoding ).getStr()) )
+ {
+ break;
+ }
+ }
+
+ if( !sourceTableKeys.empty() && i == static_cast<int>(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,
+ const OUString & lastTableInserted,
+ const OString & lastQuery )
+{
+ Reference< XResultSet > ret;
+ OUString query;
+ OUString schemaName, tableName;
+ splitConcatenatedIdentifier(
+ lastTableInserted, &schemaName, &tableName );
+
+ if( nLastOid && lastTableInserted.getLength() )
+ {
+ OUStringBuffer buf( 128 );
+ buf.append( "SELECT * FROM " );
+ if( schemaName.getLength() )
+ bufferQuoteQualifiedIdentifier(buf, schemaName, tableName, pConnectionSettings );
+ else
+ bufferQuoteIdentifier( buf, lastTableInserted, pConnectionSettings );
+ buf.append( " WHERE oid = " );
+ buf.append( nLastOid );
+ query = buf.makeStringAndClear();
+ }
+ else if ( lastTableInserted.getLength() && 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( " = " );
+ 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 000000000..fae6568bb
--- /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,
+ const OUString & 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 000000000..ec3d0d8ac
--- /dev/null
+++ b/connectivity/source/drivers/postgresql/pq_statics.cxx
@@ -0,0 +1,626 @@
+/* -*- 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>
+
+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( const OUString &str, const Type &t )
+ : name( 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 000000000..b5a868d6c
--- /dev/null
+++ b/connectivity/source/drivers/postgresql/pq_statics.hxx
@@ -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/.
+ *
+ ************************************************************************/
+
+#pragma once
+
+#include <unordered_map>
+#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(
+ const OUString &_columnName,
+ const OUString &_tableName,
+ const OUString &_schemaTableName,
+ const OUString &_typeName,
+ sal_Int32 _type,
+ sal_Int32 _precision,
+ sal_Int32 _scale,
+ bool _isCurrency,
+ bool _isNullable,
+ bool _isAutoIncrement ) :
+ columnName( _columnName ),
+ tableName( _tableName ),
+ schemaTableName( _schemaTableName ),
+ typeName( _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 000000000..eb90c24ce
--- /dev/null
+++ b/connectivity/source/drivers/postgresql/pq_tools.cxx
@@ -0,0 +1,1249 @@
+/* -*- 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.makeStringAndClear(), 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( const OUString & sql )
+{
+ OUString ret;
+ int i = 0;
+ while (i < sql.getLength() && isWhitespace(sql[i])) { i++; }
+
+ if( sql.matchIgnoreAsciiCase("insert", i) )
+ {
+ i += 6;
+ while (i < sql.getLength() && isWhitespace(sql[i])) { i++; }
+ if( sql.matchIgnoreAsciiCase("into", i) )
+ {
+ i +=4;
+ while (i < sql.getLength() && isWhitespace(sql[i])) { i++; }
+ int start = i;
+ bool quote = (sql[i] == '"');
+ for( i++ ; i < sql.getLength() ; i ++ )
+ {
+ if( quote && sql[i] == '"' )
+ {
+ while (i < sql.getLength() && isWhitespace(sql[i])) { i++; }
+ if( '.' == sql[i] )
+ {
+ while (i < sql.getLength() && 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.subView(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( OString( "." ) );
+ 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( const OUString & str )
+{
+ int len = str.getLength();
+ bool doubleQuote = false;
+ int brackets = 0;
+ int 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( digits.makeStringAndClear().toInt32() );
+ 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( "(" );
+ typeName.append( precision );
+ typeName.append( ")" );
+ break;
+ }
+ case css::sdbc::DataType::DECIMAL:
+ case css::sdbc::DataType::NUMERIC:
+ {
+ typeName.append( "(" );
+ typeName.append( precision );
+ typeName.append( "," );
+ typeName.append( extractIntProperty( desc, getStatics().SCALE ) );
+ typeName.append( ")" );
+ 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 000000000..1f9356ed4
--- /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( const OUString & 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( const OUString & 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 000000000..5c1b23e82
--- /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] );
+ buf.append( " = " );
+ 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( " " );
+ 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 000000000..1beeadc31
--- /dev/null
+++ b/connectivity/source/drivers/postgresql/pq_updateableresultset.hxx
@@ -0,0 +1,169 @@
+/* -*- 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>
+
+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,
+ const OUString &schema,
+ const OUString &table,
+ std::vector< OUString >&& primaryKey)
+ : SequenceResultSet( mutex, owner, std::move(colNames), std::move(data), (*ppSettings)->tc ),
+ m_ppSettings( ppSettings ),
+ m_schema( schema ),
+ m_table( 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 000000000..5dbe6e98b
--- /dev/null
+++ b/connectivity/source/drivers/postgresql/pq_xbase.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 <cppuhelper/supportsservice.hxx>
+#include <comphelper/sequence.hxx>
+
+#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(
+ const OUString &implName,
+ const css::uno::Sequence< OUString > &supportedServices,
+ const ::rtl::Reference< comphelper::RefCountedMutex >& refMutex,
+ const 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( implName ),
+ m_supportedServices( supportedServices ),
+ m_xMutex( refMutex ),
+ m_conn( 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 000000000..3cd16bc70
--- /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(
+ const OUString &implName,
+ const css::uno::Sequence< OUString > &supportedServices,
+ const ::rtl::Reference< comphelper::RefCountedMutex >& refMutex,
+ const 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 000000000..b19d95c3c
--- /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 000000000..794b5851d
--- /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 000000000..f1d3c0a53
--- /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 "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,
+ const OUString &schemaName,
+ const OUString &tableName)
+ : Container( refMutex, origin, pSettings, "COLUMN" ),
+ m_schemaName( schemaName ),
+ m_tableName( 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 );
+ buf.append( "SET DEFAULT " );
+ // LEM TODO: check out
+ // default value is not quoted, caller needs to quote himself (otherwise
+ // how to pass e.g. nextval('something' ) ????
+ buf.append( 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 000000000..aa91a9754
--- /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,
+ const OUString &schemaName,
+ const 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 000000000..fea88b682
--- /dev/null
+++ b/connectivity/source/drivers/postgresql/pq_xcontainer.cxx
@@ -0,0 +1,409 @@
+/* -*- 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 <cppuhelper/implbase.hxx>
+#include <o3tl/safeint.hxx>
+
+#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,
+ const css::uno::Reference< css::sdbc::XConnection > & origin,
+ ConnectionSettings *pSettings,
+ const OUString &type)
+ : ContainerBase( refMutex->GetMutex() ),
+ m_xMutex( refMutex ),
+ m_pSettings( pSettings ),
+ m_origin( origin ),
+ m_type( 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 & )
+ {
+ OSL_ENSURE( false, "exception caught" );
+ // loose coupling, a runtime exception shall not break anything
+ // TODO: log away as warning !
+ }
+ catch( css::uno::Exception & )
+ {
+ OSL_ENSURE( false, "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 000000000..fd9d432bf
--- /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,
+ const css::uno::Reference< css::sdbc::XConnection > & origin,
+ ConnectionSettings *pSettings,
+ const 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 000000000..5a96eeeb1
--- /dev/null
+++ b/connectivity/source/drivers/postgresql/pq_xindex.cxx
@@ -0,0 +1,186 @@
+/* -*- 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 "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,
+ const OUString & schemaName,
+ const OUString & tableName )
+ : ReflectionBase(
+ getStatics().refl.index.implName,
+ getStatics().refl.index.serviceNames,
+ refMutex,
+ connection,
+ pSettings,
+ * getStatics().refl.index.pProps ),
+ m_schemaName( schemaName ),
+ m_tableName( 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 000000000..46275ad3a
--- /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,
+ const OUString &schemaName,
+ const 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 000000000..fe72059bc
--- /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 000000000..7872985ec
--- /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 000000000..841ea9805
--- /dev/null
+++ b/connectivity/source/drivers/postgresql/pq_xindexcolumns.cxx
@@ -0,0 +1,267 @@
+/* -*- 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 <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,
+ const OUString &schemaName,
+ const OUString &tableName,
+ const OUString &indexName,
+ const css::uno::Sequence< OUString > &columns )
+ : Container( refMutex, origin, pSettings, "INDEX_COLUMN" ),
+ m_schemaName( schemaName ),
+ m_tableName( tableName ),
+ m_indexName( 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 000000000..eaaa709e6
--- /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,
+ const OUString &schemaName,
+ const OUString &tableName,
+ const 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 000000000..ef1e7116a
--- /dev/null
+++ b/connectivity/source/drivers/postgresql/pq_xindexes.cxx
@@ -0,0 +1,302 @@
+/* -*- 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 "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,
+ const OUString &schemaName,
+ const OUString &tableName)
+ : Container( refMutex, origin, pSettings, getStatics().KEY ),
+ m_schemaName( schemaName ),
+ m_tableName( 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 000000000..c2e81f617
--- /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,
+ const OUString &schemaName,
+ const 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 000000000..e27778245
--- /dev/null
+++ b/connectivity/source/drivers/postgresql/pq_xkey.cxx
@@ -0,0 +1,182 @@
+/* -*- 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 "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,
+ const OUString & schemaName,
+ const OUString & tableName )
+ : ReflectionBase(
+ getStatics().refl.key.implName,
+ getStatics().refl.key.serviceNames,
+ refMutex,
+ connection,
+ pSettings,
+ * getStatics().refl.key.pProps ),
+ m_schemaName( schemaName ),
+ m_tableName( 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 000000000..d231e1e89
--- /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,
+ const OUString &schemaName,
+ const 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 000000000..30eef1797
--- /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 000000000..7d49d5d26
--- /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 000000000..8b62f2842
--- /dev/null
+++ b/connectivity/source/drivers/postgresql/pq_xkeycolumns.cxx
@@ -0,0 +1,238 @@
+/* -*- 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 "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,
+ const OUString &schemaName,
+ const OUString &tableName,
+ const Sequence< OUString > &columnNames,
+ const Sequence< OUString > &foreignColumnNames )
+ : Container( refMutex, origin, pSettings, "KEY_COLUMN" ),
+ m_schemaName( schemaName ),
+ m_tableName( 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 000000000..0c56fd189
--- /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,
+ const OUString &schemaName,
+ const 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 000000000..dced2bc9b
--- /dev/null
+++ b/connectivity/source/drivers/postgresql/pq_xkeys.cxx
@@ -0,0 +1,294 @@
+/* -*- 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 "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,
+ const OUString &schemaName,
+ const OUString &tableName)
+ : Container( refMutex, origin, pSettings, getStatics().KEY ),
+ m_schemaName( schemaName ),
+ m_tableName( 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 000000000..fe1afef35
--- /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,
+ const OUString &schemaName,
+ const 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 000000000..4a659ffb9
--- /dev/null
+++ b/connectivity/source/drivers/postgresql/pq_xtable.cxx
@@ -0,0 +1,394 @@
+/* -*- 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 )
+ {
+ OUString buf( e.Message + "(NOTE: Only postgresql server >= V8.1 support changing a table's schema)" );
+ e.Message = buf;
+ 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 000000000..7c8ca73f5
--- /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 000000000..423ec81f2
--- /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 000000000..9222db82c
--- /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 000000000..4d0a01f63
--- /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 000000000..702787a67
--- /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 000000000..08cdf2d1c
--- /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 000000000..f95ec1749
--- /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 000000000..2b8f61be7
--- /dev/null
+++ b/connectivity/source/drivers/postgresql/pq_xview.cxx
@@ -0,0 +1,218 @@
+/* -*- 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 )
+ {
+ OUString buf( e.Message + "(NOTE: Only postgresql server >= V8.1 support changing a table's schema)" );
+ e.Message = buf;
+ 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 000000000..f68b5535a
--- /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 000000000..1f5b6c4fa
--- /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 000000000..04137b686
--- /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 000000000..8671af7bd
--- /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 000000000..385692951
--- /dev/null
+++ b/connectivity/source/drivers/writer/WConnection.cxx
@@ -0,0 +1,246 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * 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 <tools/diagnose_ex.h>
+
+using namespace ::com::sun::star;
+
+using OConnection_BASE = connectivity::file::OConnection;
+
+namespace connectivity::writer
+{
+OWriterConnection::OWriterConnection(ODriver* _pDriver)
+ : OConnection(_pDriver)
+ , m_nDocCount(0)
+{
+}
+
+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 000000000..f944d86a7
--- /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 000000000..fa3a3dcf6
--- /dev/null
+++ b/connectivity/source/drivers/writer/WDriver.cxx
@@ -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 incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * 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*/)
+{
+ rtl::Reference<ODriver> ret;
+ try
+ {
+ ret = new ODriver(context);
+ }
+ catch (...)
+ {
+ }
+ if (ret)
+ ret->acquire();
+ return static_cast<cppu::OWeakObject*>(ret.get());
+}
+
+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 000000000..42b65173e
--- /dev/null
+++ b/connectivity/source/drivers/writer/WTable.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 <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>
+#include <comphelper/servicehelper.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)
+ , m_nStartCol(0)
+ , m_nDataCols(0)
+ , m_bHasHeaders(false)
+{
+}
+
+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;
+}
+
+const uno::Sequence<sal_Int8>& OWriterTable::getUnoTunnelId()
+{
+ static const comphelper::UnoIdInit implId;
+ return implId.getSeq();
+}
+
+sal_Int64 OWriterTable::getSomething(const uno::Sequence<sal_Int8>& rId)
+{
+ return comphelper::getSomethingImpl(rId, this,
+ comphelper::FallbackToGetSomethingOf<OWriterTable_BASE>{});
+}
+
+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 000000000..8b2692d93
--- /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 000000000..3a0432412
--- /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>